class TestTicTacToe(unittest.TestCase): def setUp(self): self.board = TTTBoard() def test_legal_moves(self): self.assertEqual(self.board.legal_moves, list(range(9))) n_moves = randint(0, 9) list_of_moves = list(range(9)) # make random moves and test legal moves for i in range(n_moves): idx = randint(0, len(list_of_moves) - 1) position = list_of_moves[idx] self.board = self.board.move(position) del (list_of_moves[idx]) self.assertEqual(self.board.legal_moves, list_of_moves) def test_win(self): # this is a win for X for move in [0, 1, 4, 2, 8]: self.assertFalse(self.board.is_win) self.board = self.board.move(move) self.assertTrue(self.board.is_win) def test_draw(self): def is_draw(board): return (not board.is_win) and (board.legal_moves == []) for move in [0, 1, 2, 3, 5, 8, 4, 6, 7]: self.assertFalse(is_draw(self.board)) self.board = self.board.move(move) # The game is drawn now self.assertTrue(is_draw(self.board))
def __init__(self, screen): self._screen = screen self._board = TTTBoard() self._grid = Grid(self._screen) self._msgBox = MsgBox(self._screen) self._msgStatus = STATUS.HIDE self._game_over = False
def minmax(board: TTTBoard, player, maxDepth=8): if maxDepth == 0 or board.evaluate(player): return board.evaluate(player) legal = board.legal_moves if player == "O": x = [] for i in legal: x.append((minmax(board.move(i), "X", maxDepth=len(legal) - 1), i)) # print(board) x = sorted(x, key=lambda x: x[0], reverse=False) else: x = [] for i in legal: x.append((minmax(board.move(i), "O", maxDepth=len(legal) - 1), i)) # print(board) x = sorted(x, key=lambda x: x[0], reverse=True) # print(c4t) for i in x: if i[1] in legal: return i[0] if len(x) == 0: if player == "O": return 100 else: return -100
def test_block_position(self): # must block O's win to_block_position: List[TTTPiece] = [TTTPiece.X, TTTPiece.E, TTTPiece.E, TTTPiece.E, TTTPiece.E, TTTPiece.O, TTTPiece.E, TTTPiece.X, TTTPiece.O] test_board2: TTTBoard = TTTBoard(to_block_position, TTTPiece.X) answer2: Move = find_best_move(test_board2) self.assertEqual(answer2, 2)
def test_hard_position(self): # find the best move to win 2 moves to_win_hard_position: List[TTTPiece] = [TTTPiece.X, TTTPiece.E, TTTPiece.E, TTTPiece.E, TTTPiece.E, TTTPiece.O, TTTPiece.O, TTTPiece.X, TTTPiece.E] test_board3: TTTBoard = TTTBoard(to_win_hard_position, TTTPiece.X) answer3: Move = find_best_move(test_board3) self.assertEqual(answer3, 1)
def test_easy_position(self): # win in 1 move to_win_easy_position: List[TTTPiece] = [TTTPiece.X, TTTPiece.O, TTTPiece.X, TTTPiece.X, TTTPiece.E, TTTPiece.O, TTTPiece.E, TTTPiece.E, TTTPiece.O] test_board1: TTTBoard = TTTBoard(to_win_easy_position, TTTPiece.X) answer1: Move = find_best_move(test_board1) self.assertEqual(answer1, 6)
class GuiBoard(): def __init__(self, screen): self._screen = screen self._board = TTTBoard() self._grid = Grid(self._screen) self._msgBox = MsgBox(self._screen) self._msgStatus = STATUS.HIDE self._game_over = False def draw(self): self._grid.draw() self._msgBox.draw() def setMove(self, value): mx, my = value player_move = (my // CELL_HEIGHT * 3) + (mx // CELL_WIDTH) if player_move in self._board.legal_moves: self._board = self._board.move(Move(player_move)) self._grid.pic(PLAYER, player_move) if self._board.is_win: self._game_over = True self._msgBox.active = STATUS.WIN elif self._board.is_draw: self._game_over = True self._msgBox.active = STATUS.DRAW if not self._game_over: computer_move = find_best_move(self._board) self._board = self._board.move(Move(computer_move)) self._grid.pic(COMPUTER, computer_move) if self._board.is_win: self._game_over = True self._msgBox.active = STATUS.LOS elif self._board.is_draw: self._game_over = True self._msgBox.active = STATUS.DRAW def reset(self): self._board.reset() self._grid.reset() self._msgBox.active = STATUS.HIDE self._game_over = False @property def game_over(self): return self._game_over
def test_hard_position(self): # X走一步之后,下一步无论O怎么走都无法阻止X赢 to_win_hard_position: List[TTTPiece] = [TTTPiece.X,TTTPiece.E,TTTPiece.E, TTTPiece.E,TTTPiece.E,TTTPiece.O, TTTPiece.O,TTTPiece.X,TTTPiece.E] test_board3: TTTBoard = TTTBoard(to_win_hard_position, TTTPiece.X) answer3: Move = find_best_move(test_board3) self.assertEqual(answer3, 1)
def test_hard_position(self) -> None: to_win: List[TTTPiece] = [ TTTPiece.X, TTTPiece.E, TTTPiece.E, TTTPiece.E, TTTPiece.E, TTTPiece.O, TTTPiece.O, TTTPiece.X, TTTPiece.E ] test_board3: TTTBoard = TTTBoard(to_win, TTTPiece.X) answer3: Move = find_best_move(test_board3) self.assertEqual(answer3, 1)
def test_block_position(self) -> None: to_block: List[TTTPiece] = [ TTTPiece.X, TTTPiece.E, TTTPiece.E, TTTPiece.E, TTTPiece.E, TTTPiece.O, TTTPiece.E, TTTPiece.X, TTTPiece.O ] test_board2: TTTBoard = TTTBoard(to_block, TTTPiece.X) answer2: Move = find_best_move(test_board2) self.assertEqual(answer2, 2)
def test_starting_position(self): starting_position: List[TTTPiece] = [ TTTPiece.E, TTTPiece.E, TTTPiece.E, TTTPiece.E, TTTPiece.E, TTTPiece.E, TTTPiece.E, TTTPiece.E, TTTPiece.E ] test_board1: TTTBoard = TTTBoard(starting_position, TTTPiece.X) answer1: Move = find_best_move(test_board1) print(f"Best 1st move: {answer1}") self.assertTrue(True)
def test_block_position(self): # must block O's to win to_block_position: List[TTTPiece] = [ TTTPiece.X, TTTPiece.E, TTTPiece.E, TTTPiece.E, TTTPiece.E, TTTPiece.O, TTTPiece.E, TTTPiece.X, TTTPiece.O, ] test_board2: TTTBoard = TTTBoard(to_block_position, TTTPiece.X) answer2: Move = find_best_move(test_board2) # the best move is to block at Sq 2, the top right sq self.assertEqual(answer2, 2)
def test_easy_position(self): # win in 1 move to_win_easy_position: List[TTTPiece] = [ TTTPiece.X, TTTPiece.O, TTTPiece.X, TTTPiece.X, TTTPiece.E, TTTPiece.O, TTTPiece.E, TTTPiece.E, TTTPiece.O, ] # pass in the current positions and turn to the TTTBoard test_board1: TTTBoard = TTTBoard(to_win_easy_position, TTTPiece.X) # use find_best_move function to find the best move answer1: Move = find_best_move(test_board1) # the winning move should be Sq 6, the bottom left sq self.assertEqual(answer1, 6)
from tictactoe import TTTBoard game = TTTBoard() def minmax(board: TTTBoard, player, maxDepth=8): if maxDepth == 0 or board.evaluate(player): return board.evaluate(player) legal = board.legal_moves if player == "O": x = [] for i in legal: x.append((minmax(board.move(i), "X", maxDepth=len(legal) - 1), i)) # print(board) x = sorted(x, key=lambda x: x[0], reverse=False) else: x = [] for i in legal: x.append((minmax(board.move(i), "O", maxDepth=len(legal) - 1), i)) # print(board) x = sorted(x, key=lambda x: x[0], reverse=True) # print(c4t) for i in x: if i[1] in legal: return i[0] if len(x) == 0: if player == "O": return 100 else: return -100
from minimax import find_best_move from tictactoe import TTTBoard from board import Move, Board board: Board = TTTBoard() def get_player_move() -> Move: player_move: Move = Move(-1) while player_move not in board.legal_moves: play: int = int(input("Enter a legal square (0-8):")) player_move = Move(play) return player_move if __name__ == "__main__": while True: human_move: Move = get_player_move() board = board.move(human_move) if board.is_win: print("Human wins!") break elif board.is_draw: print("Draw!") break computer_move: Move = find_best_move(board) print(f"Computer move is {computer_move}") board = board.move(computer_move) print(board) if board.is_win: print("Computer wins!")
def board_factory(game) -> Board: if game == 'tictactoe': return TTTBoard() else: return C4Board()
def setUp(self): self.board = TTTBoard()