From 64f8780e9658352572088b8bbc11c9fc54949ae3 Mon Sep 17 00:00:00 2001 From: luxick Date: Wed, 20 Nov 2019 20:29:01 +0100 Subject: [PATCH] Make "makeMove" return void. When doing moves the result must no longer be discarded. --- src/libmttt.nim | 55 +++++++++++++++++++++++--------------------- tests/testChecks.nim | 2 +- tests/testMoves.nim | 20 ++++++++-------- 3 files changed, 40 insertions(+), 37 deletions(-) diff --git a/src/libmttt.nim b/src/libmttt.nim index f72b6b3..3450cf7 100644 --- a/src/libmttt.nim +++ b/src/libmttt.nim @@ -50,7 +50,7 @@ proc newGameState*(player1: var Player, player2: var Player): GameState = players: [player1, player2], currentPlayer: player1, result: Mark.Free, - board: newBoard(newBoard(Mark.Free))) + board: newBoard(newBoard(Mark.Free))) # The meta board is a board of boards ################################################### # Board Checking @@ -70,6 +70,19 @@ proc selectResult(states: HashSet[Mark]): Mark = return Mark.Free 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 = ## Evaluates a single row of a board var tokens = toHashSet(row) @@ -93,40 +106,31 @@ proc checkRows(board: Board[Mark]): Mark = proc checkDiagonals(board: Board[Mark]): Mark = var states: HashSet[Mark] states.init() - var criss: array[3, Mark] # Top left to bottom right cell - var cross: array[3, Mark] # Bottom left to top right cell - for x in 0 .. 2: - criss[x] = board[x][x] - cross[x] = board[2-x][x] - states.incl(checkRow(criss)) - states.incl(checkRow(cross)) + # Construct a temporary row from the diagonal indices, so checkRow cann be used + var row: array[3, Mark] + # Flip the board so the other diagonal is checked too. + for b in [board, board.flipped]: + for x in 0 .. 2: + row[x] = b[x][x] + states.incl(checkRow(row)) return states.selectResult() proc checkBoard*(board: Board[Mark]): Mark = ## 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] states.init() 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)) return selectResult(states) proc checkBoard*(board: Board[Board[Mark]]): Mark = ## Perform a check on a metaboard to see the overall game result - # This temporary board will hold the intermediate results from each sub board var subResults = newBoard(Mark.Free) - var states: HashSet[Mark] - states.init() for x in 0 .. 2: for y in 0 .. 2: subResults[x][y] = checkBoard(board[x][y]) @@ -136,7 +140,7 @@ proc checkBoard*(board: Board[Board[Mark]]): Mark = # Process Player Moves ################################################### -proc makeMove*(state: GameState, cell: Coordinate): GameState = +proc makeMove*(state: GameState, cell: Coordinate): void = if state.result != Mark.Free: raise newException(IllegalMoveError, "The game has already ended") 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. if state.result != Mark.Free: - return state + state.currentBoard = none(Coordinate) + return let nextBoard = checkBoard(state.board[cell.x][cell.y]) if nextBoard == Mark.Free: @@ -166,10 +171,8 @@ proc makeMove*(state: GameState, cell: Coordinate): GameState = state.currentPlayer = state.players.filter(proc (p: Player): bool = 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: raise newException(IllegalMoveError, "The game has already ended") 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: raise newException(IllegalMoveError, "Player does not have free choice for board") state.currentBoard = boardChoice.some() - return state.makeMove(cell) \ No newline at end of file + state.makeMove(cell) \ No newline at end of file diff --git a/tests/testChecks.nim b/tests/testChecks.nim index 5c12f79..e2cc856 100644 --- a/tests/testChecks.nim +++ b/tests/testChecks.nim @@ -47,7 +47,7 @@ suite "Test the board result checker": ] check(checkBoard(game.board[0][0]) == Mark.Player1) - test "board is a draw": + test "board is a draw": game.board[0][0] = [ [Mark.Player1, Mark.Player2, Mark.Player1], [Mark.Player2, Mark.Player1, Mark.Player1], diff --git a/tests/testMoves.nim b/tests/testMoves.nim index b9abc8b..7bcc9ec 100644 --- a/tests/testMoves.nim +++ b/tests/testMoves.nim @@ -17,33 +17,33 @@ suite "Test the move procedures": check game.result == Mark.Free test "First move": - game = game.makeMove((1, 1), (1, 1)) + game.makeMove((1, 1), (1, 1)) check game.currentPlayer == player2 check game.turn == 1 check game.currentBoard == (1, 1).some() check game.result == Mark.Free test "Second move": - game = game.makeMove((1, 1), (1, 1)) - game = game.makeMove((0, 0)) + game.makeMove((1, 1), (1, 1)) + game.makeMove((0, 0)) check game.currentPlayer == player1 check game.turn == 2 check game.currentBoard == (0, 0).some() check game.result == Mark.Free test "Move on wrong board": - game = game.makeMove((1, 1), (1, 1)) + game.makeMove((1, 1), (1, 1)) expect(IllegalMoveError): - game = game.makeMove((0, 0), (2, 2)) + game.makeMove((0, 0), (2, 2)) test "Move on a taken cell": - game = game.makeMove((1, 1), (1, 1)) + game.makeMove((1, 1), (1, 1)) expect(IllegalMoveError): - game = game.makeMove((1, 1)) + game.makeMove((1, 1)) test "Move out of bounds": expect(IndexError): - game = game.makeMove((3, 0), (0, 0)) + game.makeMove((3, 0), (0, 0)) test "Player 1 wins the game": let winner = [ @@ -60,7 +60,7 @@ suite "Test the move procedures": [Mark.Player1, Mark.Free, 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.currentPlayer == player1 @@ -80,6 +80,6 @@ suite "Test the move procedures": [Mark.Player2, Mark.Free, Mark.Player2] ] 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.currentPlayer == player1 \ No newline at end of file