Make "makeMove" return void.
When doing moves the result must no longer be discarded.
This commit is contained in:
@@ -50,7 +50,7 @@ proc newGameState*(player1: var Player, player2: var Player): GameState =
|
|||||||
players: [player1, player2],
|
players: [player1, player2],
|
||||||
currentPlayer: player1,
|
currentPlayer: player1,
|
||||||
result: Mark.Free,
|
result: Mark.Free,
|
||||||
board: newBoard(newBoard(Mark.Free)))
|
board: newBoard(newBoard(Mark.Free))) # The meta board is a board of boards
|
||||||
|
|
||||||
###################################################
|
###################################################
|
||||||
# Board Checking
|
# Board Checking
|
||||||
@@ -70,6 +70,19 @@ proc selectResult(states: HashSet[Mark]): Mark =
|
|||||||
return Mark.Free
|
return Mark.Free
|
||||||
return Mark.Draw
|
return Mark.Draw
|
||||||
|
|
||||||
|
proc transposed(board: Board): Board =
|
||||||
|
## Flip a board along the axis from top left to bottom right
|
||||||
|
result = newBoard(Mark.Free);
|
||||||
|
for x in 0 .. 2:
|
||||||
|
for y in 0 .. 2:
|
||||||
|
result[x][y] = board[y][x]
|
||||||
|
|
||||||
|
proc flipped(board: Board): Board =
|
||||||
|
## Flip a board along the center horizonal axis
|
||||||
|
result = newBoard(Mark.Free)
|
||||||
|
for x in 0 .. 2:
|
||||||
|
result[x] = board[2-x]
|
||||||
|
|
||||||
proc checkRow(row: array[3, Mark]): Mark =
|
proc checkRow(row: array[3, Mark]): Mark =
|
||||||
## Evaluates a single row of a board
|
## Evaluates a single row of a board
|
||||||
var tokens = toHashSet(row)
|
var tokens = toHashSet(row)
|
||||||
@@ -93,40 +106,31 @@ proc checkRows(board: Board[Mark]): Mark =
|
|||||||
proc checkDiagonals(board: Board[Mark]): Mark =
|
proc checkDiagonals(board: Board[Mark]): Mark =
|
||||||
var states: HashSet[Mark]
|
var states: HashSet[Mark]
|
||||||
states.init()
|
states.init()
|
||||||
var criss: array[3, Mark] # Top left to bottom right cell
|
# Construct a temporary row from the diagonal indices, so checkRow cann be used
|
||||||
var cross: array[3, Mark] # Bottom left to top right cell
|
var row: array[3, Mark]
|
||||||
for x in 0 .. 2:
|
# Flip the board so the other diagonal is checked too.
|
||||||
criss[x] = board[x][x]
|
for b in [board, board.flipped]:
|
||||||
cross[x] = board[2-x][x]
|
for x in 0 .. 2:
|
||||||
states.incl(checkRow(criss))
|
row[x] = b[x][x]
|
||||||
states.incl(checkRow(cross))
|
states.incl(checkRow(row))
|
||||||
return states.selectResult()
|
return states.selectResult()
|
||||||
|
|
||||||
proc checkBoard*(board: Board[Mark]): Mark =
|
proc checkBoard*(board: Board[Mark]): Mark =
|
||||||
## Perform a check on a single sub board to see its result
|
## Perform a check on a single sub board to see its result
|
||||||
|
|
||||||
# Create a seconded, transposed board.
|
|
||||||
# This way 'checkRows' can be used to check the columns
|
|
||||||
var transposed = newBoard(Mark.Free);
|
|
||||||
for x in 0 .. 2:
|
|
||||||
for y in 0 .. 2:
|
|
||||||
transposed[x][y] = board[y][x]
|
|
||||||
|
|
||||||
var states: HashSet[Mark]
|
var states: HashSet[Mark]
|
||||||
states.init()
|
states.init()
|
||||||
states.incl(checkDiagonals(board))
|
states.incl(checkDiagonals(board))
|
||||||
for b in [board, transposed]:
|
# Create a seconded, transposed board.
|
||||||
|
# This way 'checkRows' can be used to check the columns
|
||||||
|
for b in [board, board.transposed]:
|
||||||
states.incl(checkRows(b))
|
states.incl(checkRows(b))
|
||||||
|
|
||||||
return selectResult(states)
|
return selectResult(states)
|
||||||
|
|
||||||
proc checkBoard*(board: Board[Board[Mark]]): Mark =
|
proc checkBoard*(board: Board[Board[Mark]]): Mark =
|
||||||
## Perform a check on a metaboard to see the overall game result
|
## Perform a check on a metaboard to see the overall game result
|
||||||
|
|
||||||
# This temporary board will hold the intermediate results from each sub board
|
# This temporary board will hold the intermediate results from each sub board
|
||||||
var subResults = newBoard(Mark.Free)
|
var subResults = newBoard(Mark.Free)
|
||||||
var states: HashSet[Mark]
|
|
||||||
states.init()
|
|
||||||
for x in 0 .. 2:
|
for x in 0 .. 2:
|
||||||
for y in 0 .. 2:
|
for y in 0 .. 2:
|
||||||
subResults[x][y] = checkBoard(board[x][y])
|
subResults[x][y] = checkBoard(board[x][y])
|
||||||
@@ -136,7 +140,7 @@ proc checkBoard*(board: Board[Board[Mark]]): Mark =
|
|||||||
# Process Player Moves
|
# Process Player Moves
|
||||||
###################################################
|
###################################################
|
||||||
|
|
||||||
proc makeMove*(state: GameState, cell: Coordinate): GameState =
|
proc makeMove*(state: GameState, cell: Coordinate): void =
|
||||||
if state.result != Mark.Free:
|
if state.result != Mark.Free:
|
||||||
raise newException(IllegalMoveError, "The game has already ended")
|
raise newException(IllegalMoveError, "The game has already ended")
|
||||||
if cell.x > 2 or cell.y > 2:
|
if cell.x > 2 or cell.y > 2:
|
||||||
@@ -156,7 +160,8 @@ proc makeMove*(state: GameState, cell: Coordinate): GameState =
|
|||||||
|
|
||||||
# Exit early. The game has ended.
|
# Exit early. The game has ended.
|
||||||
if state.result != Mark.Free:
|
if state.result != Mark.Free:
|
||||||
return state
|
state.currentBoard = none(Coordinate)
|
||||||
|
return
|
||||||
|
|
||||||
let nextBoard = checkBoard(state.board[cell.x][cell.y])
|
let nextBoard = checkBoard(state.board[cell.x][cell.y])
|
||||||
if nextBoard == Mark.Free:
|
if nextBoard == Mark.Free:
|
||||||
@@ -166,10 +171,8 @@ proc makeMove*(state: GameState, cell: Coordinate): GameState =
|
|||||||
|
|
||||||
state.currentPlayer = state.players.filter(proc (p: Player): bool =
|
state.currentPlayer = state.players.filter(proc (p: Player): bool =
|
||||||
p.mark != state.currentPlayer.mark)[0]
|
p.mark != state.currentPlayer.mark)[0]
|
||||||
|
|
||||||
return state
|
|
||||||
|
|
||||||
proc makeMove*(state: GameState, cell: Coordinate, boardChoice: Coordinate): GameState =
|
proc makeMove*(state: GameState, cell: Coordinate, boardChoice: Coordinate): void =
|
||||||
if state.result != Mark.Free:
|
if state.result != Mark.Free:
|
||||||
raise newException(IllegalMoveError, "The game has already ended")
|
raise newException(IllegalMoveError, "The game has already ended")
|
||||||
if checkBoard(state.board[boardChoice.x][boardChoice.y]) != Mark.Free:
|
if checkBoard(state.board[boardChoice.x][boardChoice.y]) != Mark.Free:
|
||||||
@@ -177,4 +180,4 @@ proc makeMove*(state: GameState, cell: Coordinate, boardChoice: Coordinate): Gam
|
|||||||
if state.currentBoard.isSome:
|
if state.currentBoard.isSome:
|
||||||
raise newException(IllegalMoveError, "Player does not have free choice for board")
|
raise newException(IllegalMoveError, "Player does not have free choice for board")
|
||||||
state.currentBoard = boardChoice.some()
|
state.currentBoard = boardChoice.some()
|
||||||
return state.makeMove(cell)
|
state.makeMove(cell)
|
||||||
@@ -47,7 +47,7 @@ suite "Test the board result checker":
|
|||||||
]
|
]
|
||||||
check(checkBoard(game.board[0][0]) == Mark.Player1)
|
check(checkBoard(game.board[0][0]) == Mark.Player1)
|
||||||
|
|
||||||
test "board is a draw":
|
test "board is a draw":
|
||||||
game.board[0][0] = [
|
game.board[0][0] = [
|
||||||
[Mark.Player1, Mark.Player2, Mark.Player1],
|
[Mark.Player1, Mark.Player2, Mark.Player1],
|
||||||
[Mark.Player2, Mark.Player1, Mark.Player1],
|
[Mark.Player2, Mark.Player1, Mark.Player1],
|
||||||
|
|||||||
@@ -17,33 +17,33 @@ suite "Test the move procedures":
|
|||||||
check game.result == Mark.Free
|
check game.result == Mark.Free
|
||||||
|
|
||||||
test "First move":
|
test "First move":
|
||||||
game = game.makeMove((1, 1), (1, 1))
|
game.makeMove((1, 1), (1, 1))
|
||||||
check game.currentPlayer == player2
|
check game.currentPlayer == player2
|
||||||
check game.turn == 1
|
check game.turn == 1
|
||||||
check game.currentBoard == (1, 1).some()
|
check game.currentBoard == (1, 1).some()
|
||||||
check game.result == Mark.Free
|
check game.result == Mark.Free
|
||||||
|
|
||||||
test "Second move":
|
test "Second move":
|
||||||
game = game.makeMove((1, 1), (1, 1))
|
game.makeMove((1, 1), (1, 1))
|
||||||
game = game.makeMove((0, 0))
|
game.makeMove((0, 0))
|
||||||
check game.currentPlayer == player1
|
check game.currentPlayer == player1
|
||||||
check game.turn == 2
|
check game.turn == 2
|
||||||
check game.currentBoard == (0, 0).some()
|
check game.currentBoard == (0, 0).some()
|
||||||
check game.result == Mark.Free
|
check game.result == Mark.Free
|
||||||
|
|
||||||
test "Move on wrong board":
|
test "Move on wrong board":
|
||||||
game = game.makeMove((1, 1), (1, 1))
|
game.makeMove((1, 1), (1, 1))
|
||||||
expect(IllegalMoveError):
|
expect(IllegalMoveError):
|
||||||
game = game.makeMove((0, 0), (2, 2))
|
game.makeMove((0, 0), (2, 2))
|
||||||
|
|
||||||
test "Move on a taken cell":
|
test "Move on a taken cell":
|
||||||
game = game.makeMove((1, 1), (1, 1))
|
game.makeMove((1, 1), (1, 1))
|
||||||
expect(IllegalMoveError):
|
expect(IllegalMoveError):
|
||||||
game = game.makeMove((1, 1))
|
game.makeMove((1, 1))
|
||||||
|
|
||||||
test "Move out of bounds":
|
test "Move out of bounds":
|
||||||
expect(IndexError):
|
expect(IndexError):
|
||||||
game = game.makeMove((3, 0), (0, 0))
|
game.makeMove((3, 0), (0, 0))
|
||||||
|
|
||||||
test "Player 1 wins the game":
|
test "Player 1 wins the game":
|
||||||
let winner = [
|
let winner = [
|
||||||
@@ -60,7 +60,7 @@ suite "Test the move procedures":
|
|||||||
[Mark.Player1, Mark.Free, Mark.Free]
|
[Mark.Player1, Mark.Free, Mark.Free]
|
||||||
]
|
]
|
||||||
check checkBoard(game.board) == Mark.Free
|
check checkBoard(game.board) == Mark.Free
|
||||||
game = game.makeMove((1, 0), (2, 2))
|
game.makeMove((1, 0), (2, 2))
|
||||||
check game.result == Mark.Player1
|
check game.result == Mark.Player1
|
||||||
check game.currentPlayer == player1
|
check game.currentPlayer == player1
|
||||||
|
|
||||||
@@ -80,6 +80,6 @@ suite "Test the move procedures":
|
|||||||
[Mark.Player2, Mark.Free, Mark.Player2]
|
[Mark.Player2, Mark.Free, Mark.Player2]
|
||||||
]
|
]
|
||||||
check checkBoard(game.board) == Mark.Free
|
check checkBoard(game.board) == Mark.Free
|
||||||
game = game.makeMove((2, 1), (2, 2))
|
game.makeMove((2, 1), (2, 2))
|
||||||
check game.result == Mark.Draw
|
check game.result == Mark.Draw
|
||||||
check game.currentPlayer == player1
|
check game.currentPlayer == player1
|
||||||
Reference in New Issue
Block a user