Skip to content

Instantly share code, notes, and snippets.

@nerdo
Last active March 23, 2018 16:37
Show Gist options
  • Save nerdo/24d24a432bcde285f42e69328bbcbca4 to your computer and use it in GitHub Desktop.
Save nerdo/24d24a432bcde285f42e69328bbcbca4 to your computer and use it in GitHub Desktop.
ReSwift Tic Tac Toe
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="13771" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="BYZ-38-t0r">
<device id="retina4_7" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13772"/>
<capability name="Aspect ratio constraints" minToolsVersion="5.1"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="Stack View standard spacing" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
<!--View Controller-->
<scene sceneID="tne-QT-ifu">
<objects>
<viewController id="BYZ-38-t0r" customClass="ViewController" customModule="TicTacToe" customModuleProvider="target" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" distribution="fillEqually" spacingType="standard" translatesAutoresizingMaskIntoConstraints="NO" id="GYC-JQ-41v">
<rect key="frame" x="15" y="161" width="345" height="345"/>
<subviews>
<stackView opaque="NO" contentMode="scaleToFill" distribution="fillEqually" spacingType="standard" translatesAutoresizingMaskIntoConstraints="NO" id="v7b-c4-5Ke">
<rect key="frame" x="0.0" y="0.0" width="345" height="109.5"/>
<subviews>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="2cU-au-Mow">
<rect key="frame" x="0.0" y="0.0" width="109.5" height="109.5"/>
<color key="backgroundColor" red="0.92143100499999997" green="0.92145264149999995" blue="0.92144101860000005" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<fontDescription key="fontDescription" type="system" weight="heavy" pointSize="32"/>
<state key="normal">
<color key="titleColor" red="0.12984204290000001" green="0.12984612579999999" blue="0.12984395030000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</state>
<connections>
<action selector="button0Pressed:" destination="BYZ-38-t0r" eventType="touchUpInside" id="82X-ZM-363"/>
</connections>
</button>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="drs-Bo-49n">
<rect key="frame" x="117.5" y="0.0" width="110" height="109.5"/>
<color key="backgroundColor" red="0.92143100499999997" green="0.92145264149999995" blue="0.92144101860000005" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<fontDescription key="fontDescription" type="system" weight="heavy" pointSize="32"/>
<state key="normal">
<color key="titleColor" red="0.12984204290000001" green="0.12984612579999999" blue="0.12984395030000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</state>
<connections>
<action selector="button1Pressed:" destination="BYZ-38-t0r" eventType="touchUpInside" id="y6O-wU-B7p"/>
</connections>
</button>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="C4m-5v-2rO">
<rect key="frame" x="235.5" y="0.0" width="109.5" height="109.5"/>
<color key="backgroundColor" red="0.92143100499999997" green="0.92145264149999995" blue="0.92144101860000005" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<fontDescription key="fontDescription" type="system" weight="heavy" pointSize="32"/>
<state key="normal">
<color key="titleColor" red="0.12984204290000001" green="0.12984612579999999" blue="0.12984395030000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</state>
<connections>
<action selector="button2Pressed:" destination="BYZ-38-t0r" eventType="touchUpInside" id="KVg-VM-FO8"/>
</connections>
</button>
</subviews>
</stackView>
<stackView opaque="NO" contentMode="scaleToFill" distribution="fillEqually" spacingType="standard" translatesAutoresizingMaskIntoConstraints="NO" id="IDm-oR-oQE">
<rect key="frame" x="0.0" y="117.5" width="345" height="110"/>
<subviews>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="YtA-u5-gCw">
<rect key="frame" x="0.0" y="0.0" width="109.5" height="110"/>
<color key="backgroundColor" red="0.92143100499999997" green="0.92145264149999995" blue="0.92144101860000005" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<fontDescription key="fontDescription" type="system" weight="heavy" pointSize="32"/>
<state key="normal">
<color key="titleColor" red="0.12984204290000001" green="0.12984612579999999" blue="0.12984395030000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</state>
<connections>
<action selector="button3Pressed:" destination="BYZ-38-t0r" eventType="touchUpInside" id="M7o-Ua-KhF"/>
</connections>
</button>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="lnr-Ld-pnz">
<rect key="frame" x="117.5" y="0.0" width="110" height="110"/>
<color key="backgroundColor" red="0.92143100499999997" green="0.92145264149999995" blue="0.92144101860000005" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<fontDescription key="fontDescription" type="system" weight="heavy" pointSize="32"/>
<state key="normal">
<color key="titleColor" red="0.12984204290000001" green="0.12984612579999999" blue="0.12984395030000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</state>
<connections>
<action selector="button4Pressed:" destination="BYZ-38-t0r" eventType="touchUpInside" id="wNY-9B-ocj"/>
</connections>
</button>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="tTU-Xd-RTN">
<rect key="frame" x="235.5" y="0.0" width="109.5" height="110"/>
<color key="backgroundColor" red="0.92143100499999997" green="0.92145264149999995" blue="0.92144101860000005" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<fontDescription key="fontDescription" type="system" weight="heavy" pointSize="32"/>
<state key="normal">
<color key="titleColor" red="0.12984204290000001" green="0.12984612579999999" blue="0.12984395030000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</state>
<connections>
<action selector="button5Pressed:" destination="BYZ-38-t0r" eventType="touchUpInside" id="yNV-Mf-v4H"/>
</connections>
</button>
</subviews>
</stackView>
<stackView opaque="NO" contentMode="scaleToFill" distribution="fillEqually" spacingType="standard" translatesAutoresizingMaskIntoConstraints="NO" id="wO4-X9-a35">
<rect key="frame" x="0.0" y="235.5" width="345" height="109.5"/>
<subviews>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="S5y-Gp-PXp">
<rect key="frame" x="0.0" y="0.0" width="109.5" height="109.5"/>
<color key="backgroundColor" red="0.92143100499999997" green="0.92145264149999995" blue="0.92144101860000005" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<fontDescription key="fontDescription" type="system" weight="heavy" pointSize="32"/>
<state key="normal">
<color key="titleColor" red="0.12984204290000001" green="0.12984612579999999" blue="0.12984395030000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</state>
<connections>
<action selector="button6Pressed:" destination="BYZ-38-t0r" eventType="touchUpInside" id="fwN-Ea-0nP"/>
</connections>
</button>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="DZE-sb-KSR">
<rect key="frame" x="117.5" y="0.0" width="110" height="109.5"/>
<color key="backgroundColor" red="0.92143100499999997" green="0.92145264149999995" blue="0.92144101860000005" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<fontDescription key="fontDescription" type="system" weight="heavy" pointSize="32"/>
<state key="normal">
<color key="titleColor" red="0.12984204290000001" green="0.12984612579999999" blue="0.12984395030000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</state>
<connections>
<action selector="button7Pressed:" destination="BYZ-38-t0r" eventType="touchUpInside" id="qKa-ck-me6"/>
</connections>
</button>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="HN8-ZY-CpP">
<rect key="frame" x="235.5" y="0.0" width="109.5" height="109.5"/>
<color key="backgroundColor" red="0.92143100499999997" green="0.92145264149999995" blue="0.92144101860000005" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<fontDescription key="fontDescription" type="system" weight="heavy" pointSize="32"/>
<state key="normal">
<color key="titleColor" red="0.12984204290000001" green="0.12984612579999999" blue="0.12984395030000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</state>
<connections>
<action selector="button8Pressed:" destination="BYZ-38-t0r" eventType="touchUpInside" id="Ule-JU-klE"/>
</connections>
</button>
</subviews>
</stackView>
</subviews>
<constraints>
<constraint firstAttribute="width" secondItem="GYC-JQ-41v" secondAttribute="height" multiplier="1:1" id="1Ir-Zn-ZiX"/>
</constraints>
</stackView>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="YVy-GY-iZt">
<rect key="frame" x="111.5" y="104" width="152" height="49"/>
<color key="backgroundColor" red="0.016804177310000001" green="0.19835099580000001" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<fontDescription key="fontDescription" type="system" pointSize="24"/>
<inset key="contentEdgeInsets" minX="10" minY="10" maxX="10" maxY="10"/>
<state key="normal" title="PLAY AGAIN">
<color key="titleColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</state>
<connections>
<action selector="playAgain:" destination="BYZ-38-t0r" eventType="touchUpInside" id="y0M-27-msF"/>
</connections>
</button>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Z Won!" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="XL9-cY-Sce">
<rect key="frame" x="138" y="514" width="99" height="38.5"/>
<fontDescription key="fontDescription" type="system" pointSize="32"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstItem="XL9-cY-Sce" firstAttribute="centerX" secondItem="GYC-JQ-41v" secondAttribute="centerX" id="0S8-2B-MAc"/>
<constraint firstItem="GYC-JQ-41v" firstAttribute="centerY" secondItem="8bC-Xf-vdC" secondAttribute="centerY" id="5my-Tr-Ff6"/>
<constraint firstItem="GYC-JQ-41v" firstAttribute="top" relation="greaterThanOrEqual" secondItem="6Tk-OE-BBY" secondAttribute="top" constant="65" id="D0B-8f-seN"/>
<constraint firstItem="XL9-cY-Sce" firstAttribute="top" secondItem="GYC-JQ-41v" secondAttribute="bottom" constant="8" symbolic="YES" id="Ecy-HS-Eaw"/>
<constraint firstItem="6Tk-OE-BBY" firstAttribute="trailing" secondItem="GYC-JQ-41v" secondAttribute="trailing" constant="15" id="SAa-sC-3vU"/>
<constraint firstItem="GYC-JQ-41v" firstAttribute="height" secondItem="6Tk-OE-BBY" secondAttribute="height" priority="750" id="SGK-vz-AuA"/>
<constraint firstItem="YVy-GY-iZt" firstAttribute="centerX" secondItem="GYC-JQ-41v" secondAttribute="centerX" id="XeQ-MS-qYm"/>
<constraint firstItem="GYC-JQ-41v" firstAttribute="top" secondItem="YVy-GY-iZt" secondAttribute="bottom" constant="8" symbolic="YES" id="cua-PS-2Ah"/>
<constraint firstItem="6Tk-OE-BBY" firstAttribute="bottom" relation="greaterThanOrEqual" secondItem="GYC-JQ-41v" secondAttribute="bottom" constant="50" id="pDf-n6-QyB"/>
<constraint firstItem="GYC-JQ-41v" firstAttribute="leading" secondItem="6Tk-OE-BBY" secondAttribute="leading" constant="15" id="rP6-im-sYS"/>
<constraint firstItem="GYC-JQ-41v" firstAttribute="centerX" secondItem="8bC-Xf-vdC" secondAttribute="centerX" id="y7y-qw-7Jy"/>
</constraints>
<viewLayoutGuide key="safeArea" id="6Tk-OE-BBY"/>
<variation key="default">
<mask key="constraints">
<exclude reference="pDf-n6-QyB"/>
<exclude reference="D0B-8f-seN"/>
<exclude reference="SGK-vz-AuA"/>
</mask>
</variation>
<variation key="heightClass=compact">
<mask key="constraints">
<exclude reference="SAa-sC-3vU"/>
<include reference="pDf-n6-QyB"/>
<include reference="D0B-8f-seN"/>
<include reference="SGK-vz-AuA"/>
<exclude reference="rP6-im-sYS"/>
</mask>
</variation>
</view>
<connections>
<outlet property="button0" destination="2cU-au-Mow" id="udq-uF-Eak"/>
<outlet property="button1" destination="drs-Bo-49n" id="PrU-gF-4oa"/>
<outlet property="button2" destination="C4m-5v-2rO" id="fdE-sp-oC5"/>
<outlet property="button3" destination="YtA-u5-gCw" id="3Vz-n5-w01"/>
<outlet property="button4" destination="lnr-Ld-pnz" id="rZc-UI-8Sc"/>
<outlet property="button5" destination="tTU-Xd-RTN" id="cIr-hZ-04Q"/>
<outlet property="button6" destination="S5y-Gp-PXp" id="yMU-9m-uCS"/>
<outlet property="button7" destination="DZE-sb-KSR" id="HcP-JR-cxR"/>
<outlet property="button8" destination="HN8-ZY-CpP" id="410-BS-gY0"/>
<outlet property="playAgainButton" destination="YVy-GY-iZt" id="czv-PK-bW4"/>
<outlet property="winnerLabel" destination="XL9-cY-Sce" id="dG6-ga-Uyr"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
</objects>
</scene>
</scenes>
</document>
//
// TicTacToe.swift
// TicTacToe
//
// Created by Dannel Albert on 3/22/18.
// Copyright © 2018 Dannel Albert. All rights reserved.
//
import ReSwift
open class TicTacToe {
public typealias Winner = (player: Player, path: [Int])
public static var store = Store<State>(reducer: Reducer.ticTacToe, state: nil)
public enum Player: String {
case x = "X"
case o = "O"
}
public struct State: ReSwift.StateType {
var board: [Player?] = [
nil, nil, nil,
nil, nil, nil,
nil, nil, nil
]
var currentPlayer: Player = .x
var winner: Winner?
}
public enum Action: ReSwift.Action {
case move(location: Int)
case reset
}
open class Reducer {
static func ticTacToe(action: ReSwift.Action, state: State?) -> State {
var state = state ?? State()
state = self.reset(action: action, state: state)
state = self.move(action: action, state: state)
return state
}
private static func reset(action: ReSwift.Action, state: State?) -> State {
var state = state ?? State()
guard let action = action as? Action else {
return state
}
if case .reset = action {
state = State()
}
return state
}
private static func move(action: ReSwift.Action, state: State?) -> State {
var state = self.handlePlayerMove(action: action, state: state)
state = self.checkForWinner(action: action, state: state)
return state
}
private static func handlePlayerMove(action: ReSwift.Action, state: State?) -> State {
var state = state ?? State()
guard let action = action as? Action else {
return state
}
if case let .move(location) = action {
if location >= 0 && location < 9 && state.board[location] == nil {
state.board[location] = state.currentPlayer
switch state.currentPlayer {
case .x:
state.currentPlayer = .o
case .o:
state.currentPlayer = .x
}
}
}
return state
}
private static func checkForWinner(action: ReSwift.Action, state: State?) -> State {
var state = state ?? State()
var winner: Winner?
winner = winner ?? self.getWinner(state.board, 0, 1, 2)
winner = winner ?? self.getWinner(state.board, 3, 4, 5)
winner = winner ?? self.getWinner(state.board, 6, 7, 8)
winner = winner ?? self.getWinner(state.board, 0, 3, 6)
winner = winner ?? self.getWinner(state.board, 1, 4, 7)
winner = winner ?? self.getWinner(state.board, 2, 5, 8)
winner = winner ?? self.getWinner(state.board, 0, 4, 8)
winner = winner ?? self.getWinner(state.board, 2, 4, 6)
state.winner = winner
return state
}
private static func getWinner(_ board: [Player?], _ a: Int, _ b: Int, _ c: Int) -> Winner? {
if board[a] == nil || board[b] == nil || board[c] == nil {
return nil
}
if board[a] == board[b] && board[b] == board[c] {
return (player: board[a]!, path: [a, b, c])
}
return nil
}
}
}
//
// ViewController.swift
// TicTacToe
//
// Created by Dannel Albert on 3/22/18.
// Copyright © 2018 Dannel Albert. All rights reserved.
//
import UIKit
import ReSwift
class ViewController: UIViewController, StoreSubscriber {
@IBOutlet weak var button0: UIButton!
@IBOutlet weak var button1: UIButton!
@IBOutlet weak var button2: UIButton!
@IBOutlet weak var button3: UIButton!
@IBOutlet weak var button4: UIButton!
@IBOutlet weak var button5: UIButton!
@IBOutlet weak var button6: UIButton!
@IBOutlet weak var button7: UIButton!
@IBOutlet weak var button8: UIButton!
@IBOutlet weak var playAgainButton: UIButton!
@IBOutlet weak var winnerLabel: UILabel!
var buttons: [UIButton]!
override func viewDidLoad() {
super.viewDidLoad()
setupButtons()
TicTacToe.store.subscribe(self)
}
func newState(state: TicTacToe.State) {
DispatchQueue.main.async {
self.render(state: state)
}
if state.currentPlayer == .o {
DispatchQueue.global(qos: .background).async {
self.computerMove(state: state)
}
}
}
func render(state: TicTacToe.State) {
let thereIsAWinner = state.winner != nil
let hasMovesLeft = state.board.filter { $0 == nil }.count > 0
playAgainButton.isHidden = !thereIsAWinner && hasMovesLeft
winnerLabel.isHidden = !thereIsAWinner && hasMovesLeft
for (i, player) in state.board.enumerated() {
if let player = player {
buttons[i].setTitle(player.rawValue, for: .normal)
} else {
buttons[i].setTitle(nil, for: .normal)
}
if state.winner?.path.contains(i) == true {
buttons[i].backgroundColor = .green
} else {
buttons[i].backgroundColor = .lightGray
}
}
if let winner = state.winner {
winnerLabel.text = "\(winner.player.rawValue) Won!"
} else if !hasMovesLeft {
winnerLabel.text = "It's a draw!"
}
for button in buttons {
button.isEnabled = state.currentPlayer == .x && !thereIsAWinner && hasMovesLeft
}
#if DEBUG
renderTextBoard(state: state)
#endif
}
func renderTextBoard(state: TicTacToe.State) {
let board = state.board.map { $0?.rawValue ?? " " }
print()
print(" \(board[0]) | \(board[1]) | \(board[2])")
print("-----------")
print(" \(board[3]) | \(board[4]) | \(board[5])")
print("-----------")
print(" \(board[6]) | \(board[7]) | \(board[8])")
if let winner = state.winner {
print("\(winner.player.rawValue) Won!")
}
print()
}
private func setupButtons() {
buttons = [
button0, button1, button2,
button3, button4, button5,
button6, button7, button8
]
}
func computerMove(state: TicTacToe.State) {
if state.winner != nil {
return
}
let emptyLocations = state.board
.enumerated()
.map { (player: $1, location: $0) }
.filter { $0.player == nil }
.map { $0.location }
if emptyLocations.count == 0 {
return
}
let location = emptyLocations[Int(arc4random_uniform(UInt32(emptyLocations.count)))]
TicTacToe.store.dispatch(
TicTacToe.Action.move(location: location)
)
}
@IBAction func button0Pressed(_ sender: Any) {
TicTacToe.store.dispatch(TicTacToe.Action.move(location: 0))
}
@IBAction func button1Pressed(_ sender: Any) {
TicTacToe.store.dispatch(TicTacToe.Action.move(location: 1))
}
@IBAction func button2Pressed(_ sender: Any) {
TicTacToe.store.dispatch(TicTacToe.Action.move(location: 2))
}
@IBAction func button3Pressed(_ sender: Any) {
TicTacToe.store.dispatch(TicTacToe.Action.move(location: 3))
}
@IBAction func button4Pressed(_ sender: Any) {
TicTacToe.store.dispatch(TicTacToe.Action.move(location: 4))
}
@IBAction func button5Pressed(_ sender: Any) {
TicTacToe.store.dispatch(TicTacToe.Action.move(location: 5))
}
@IBAction func button6Pressed(_ sender: Any) {
TicTacToe.store.dispatch(TicTacToe.Action.move(location: 6))
}
@IBAction func button7Pressed(_ sender: Any) {
TicTacToe.store.dispatch(TicTacToe.Action.move(location: 7))
}
@IBAction func button8Pressed(_ sender: Any) {
TicTacToe.store.dispatch(TicTacToe.Action.move(location: 8))
}
@IBAction func playAgain(_ sender: Any) {
TicTacToe.store.dispatch(TicTacToe.Action.reset)
}
deinit {
TicTacToe.store.unsubscribe(self)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment