-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathGameState.fs
131 lines (102 loc) · 4.02 KB
/
GameState.fs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
namespace FunkyTicTacToe
open Types
module GameState =
let init =
[ 0..8 ]
|> List.map CellPosition
|> List.map (fun pos -> { Position = pos; Status = Empty })
|> fun cells ->
{ Cells = cells
Player = X
GameStatus = InProgress }
let getValue (cell: Cell) : string =
match cell.Status with
| Empty -> ""
| Full token ->
match token with
| X -> "X"
| O -> "O"
let canClickCell ({ Status = status }) =
match status with
| Empty -> true
| Full _ -> false
let setCellValue newCell oldCell : CellUpdateResult =
match oldCell.Position = newCell.Position with
| true ->
match canClickCell oldCell with
| true -> { Cell = newCell; Updated = true }
| false -> { Cell = oldCell; Updated = false }
| false -> { Cell = oldCell; Updated = false }
let shouldUpdatePlayer cellUpdateResults =
cellUpdateResults
|> List.map (fun ({ Updated = updated }: CellUpdateResult) -> updated)
|> List.contains true
let extractCellsFromUpdate (cellUpdateResults: CellUpdateResult list) =
cellUpdateResults |> List.map (fun ({ Cell = cell }) -> cell)
let swapPlayerToken player =
match player with
| X -> O
| O -> X
let playerClaimedCell player cell =
match cell.Status with
| Full playerToken -> player = playerToken
| Empty -> false
let leftColumn () = [ 0; 3; 6 ] |> List.map CellPosition
let middleColumn () = [ 1; 4; 7 ] |> List.map CellPosition
let rightColumn () = [ 2; 5; 8 ] |> List.map CellPosition
let topRow () = [ 0; 1; 2 ] |> List.map CellPosition
let middleRow () = [ 3; 4; 5 ] |> List.map CellPosition
let bottomRow () = [ 6; 7; 8 ] |> List.map CellPosition
let diagonalDownToRight () = [ 0; 4; 8 ] |> List.map CellPosition
let diagonalDownToLeft () = [ 2; 4; 6 ] |> List.map CellPosition
let checkWin ({ Cells = cells; Player = player }) winPositions =
cells
|> List.where (fun cell -> winPositions |> List.contains cell.Position)
|> List.forall (fun cell -> playerClaimedCell player cell)
let checkForWinCondition ({ Player = player } as state) =
[ leftColumn
middleColumn
rightColumn
topRow
middleRow
bottomRow
diagonalDownToLeft
diagonalDownToRight ]
|> List.map (fun positionList -> (positionList () |> checkWin state))
|> List.contains true
|> function
| true ->
{ state with
GameStatus = Winner player }
| false -> state
let checkForNoMoreMoves ({ Cells = cells } as gameState) =
cells
|> List.map (fun cell -> cell.Status = Empty)
|> List.contains true
|> function
| true -> gameState
| false ->
match gameState.GameStatus with
| InProgress -> { gameState with GameStatus = Tie }
| _ -> gameState
let swapPlayer state =
{ state with
Player = swapPlayerToken state.Player }
let updateCells state cells = { state with Cells = cells }
let handlePlayerSwap state =
match state.GameStatus with
| InProgress -> swapPlayer state
| _ -> state
let checkForWinAndSwapPlayers =
checkForWinCondition >> checkForNoMoreMoves >> handlePlayerSwap
let getCellUpdates updateResults =
(extractCellsFromUpdate updateResults), (shouldUpdatePlayer updateResults)
let modifyStateAfterUpdates gameState (updatedCells, shouldUpdatePlayer) =
match shouldUpdatePlayer with
| true -> updatedCells |> updateCells gameState |> checkForWinAndSwapPlayers
| false -> gameState
let setValue ({ Cells = cells } as gameState) cell =
cells
|> List.map (setCellValue cell)
|> getCellUpdates
|> modifyStateAfterUpdates gameState