def test_check_line_horizontal(self): w, h = 5, 3 board = Board(w, h) token = 'x' # Check empty row for y in range(h): self.assertTrue(board.check_line_horizontal(0, y, [None])) self.assertTrue(board.check_line_horizontal(1, y, [None, None])) self.assertFalse(board.check_line_horizontal(2, y, [token])) self.assertTrue(board.check_line_horizontal(3, y, [None, None])) # |-|x|-|x|-| self.assertTrue(board.add_token(Point(1, 1), token)) self.assertTrue(board.add_token(Point(3, 1), token)) self.assertTrue(board.check_line_horizontal(1, 1, [token])) self.assertTrue(board.check_line_horizontal(3, 1, [token])) self.assertTrue(board.check_line_horizontal( 1, 1, [token, None, token])) self.assertTrue(board.check_line_horizontal( 2, 1, [token, None, token])) self.assertTrue(board.check_line_horizontal( 3, 1, [token, None, token])) self.assertFalse(board.check_line_horizontal(2, 1, [token, token])) # |-|x|x|x|-| self.assertTrue(board.add_token(Point(2, 1), token)) self.assertTrue(board.check_line_horizontal( 2, 1, [token, token, token])) self.assertTrue(board.check_line_horizontal( 3, 1, [token, token, token])) self.assertTrue(board.check_line_horizontal( 1, 1, [token, token, token]))
def test_evaluate_d1(self): ''' X|X|X O|O|- -|-|- ''' ai_player = Player("AI_1", Token.A, True) game = TicTacToe(p1=ai_player) minmax = Minmax(ai_player, 7) depth = 10 self.assertEqual(minmax._evaluate(game, depth, Token.A), Minmax.DRAW_POINT) self.assertEqual(minmax._evaluate(game, depth, Token.B), Minmax.DRAW_POINT) game.play(Point(0, 0)) game.play(Point(0, 1)) game.play(Point(1, 0)) game.play(Point(1, 1)) game.play(Point(2, 0)) self.assertEqual(minmax._evaluate(game, depth, Token.A), Minmax.WIN_POINT + depth) self.assertEqual(minmax._evaluate(game, depth, Token.B), Minmax.LOOSE_POINT - depth)
def test_x_y_order(self): w, h = 5, 3 board = Board(w, h) self.assertTrue(board.add_token(Point(2, 1), 'x')) self.assertTrue(board.add_token(Point(4, 0), 'x')) self.assertTrue(board.add_token(Point(4, 2), 'o')) self.assertTrue(board.add_token(Point(0, 2), 'u')) # print(board) self.assertEqual(board.column_count, w) self.assertEqual(board.row_count, h)
def test_win_vertical_player1(self): game = TicTacToe() self.assertTrue(game.play(Point(0, 0))) self.assertTrue(game.play(Point(1, 0))) self.assertTrue(game.play(Point(0, 1))) self.assertTrue(game.play(Point(1, 1))) self.assertTrue(game.play(Point(0, 2))) self.assertTrue(game.is_over) self.assertEqual(game.winner, game._p1)
def test_minmax_d1(self): ''' XX- OO- XO- Simulate max loop and calling min evaluation ''' ai_player = Player("AI_1", Token.A, True) game = TicTacToe(p1=ai_player) depth = 1 minmax = Minmax(ai_player, depth) game.play(Point(0, 0)) game.play(Point(0, 1)) game.play(Point(1, 0)) game.play(Point(1, 1)) game.play(Point(0, 2)) game.play(Point(1, 2)) game.play(Point(2, 0)) val, _ = minmax._min(game, depth) self.assertEqual(val, Minmax.WIN_POINT + depth) game.undo() game.play(Point(2, 1)) val, _ = minmax._min(game, depth) self.assertEqual(val, Minmax.DRAW_POINT) game.undo() game.play(Point(2, 2)) val, _ = minmax._min(game, depth) self.assertEqual(val, Minmax.LOOSE_POINT) game.undo()
def test_next_player(self): game = Gomoku() self.assertEqual(game._current_player, game._p1) self.assertTrue(game.play(Point(0, 0))) self.assertEqual(game._current_player, game._p2) self.assertTrue(game.play(Point(1, 0))) self.assertEqual(game._current_player, game._p1) # Cell not free, do not change current player self.assertFalse(game.play(Point(1, 0))) self.assertEqual(game._current_player, game._p1)
def test_has_winner_diag_down(self): board = Board(7, 6) token = Token.A board.add_token(Point(0, 2), token) board.add_token(Point(1, 3), token) board.add_token(Point(2, 4), token) board.add_token(Point(3, 5), token) game = ConnectFour() self.assertEqual(game._has_winner_diagonal(board, Point(3, 5)), (True, token))
def test_minmax_d2(self): ''' O|-|X X|X|O O|-|- ''' ai_player = Player("AI_1", Token.A, True) game = TicTacToe(p1=ai_player) depth = 2 minmax = Minmax(ai_player, depth) game.play(Point(2, 0)) game.play(Point(0, 0)) game.play(Point(0, 1)) game.play(Point(0, 2)) game.play(Point(1, 1)) game.play(Point(2, 1)) game.play(Point(1, 0)) val, _ = minmax._min(game, depth) self.assertEqual(val, Minmax.DRAW_POINT) game.undo() game.play(Point(1, 2)) val, _ = minmax._min(game, depth) self.assertEqual(val, Minmax.DRAW_POINT) game.undo()
def test_win_vertical_player2(self): game = Gomoku() self.assertTrue(game.play(Point(0, 0))) self.assertTrue(game.play(Point(1, 0))) self.assertTrue(game.play(Point(0, 1))) self.assertTrue(game.play(Point(1, 1))) self.assertTrue(game.play(Point(0, 2))) self.assertTrue(game.play(Point(1, 2))) self.assertTrue(game.play(Point(0, 3))) self.assertTrue(game.play(Point(1, 3))) self.assertTrue(game.play(Point(2, 4))) self.assertTrue(game.play(Point(1, 4))) self.assertTrue(game.is_over) self.assertEqual(game.winner, game._p2)
def test_is_leaf(self): ai_player = Player("AI_1", Token.A, True) game = TicTacToe(p1=ai_player) minmax = Minmax(ai_player, 7) self.assertFalse(minmax._is_leaf(game, 1)) self.assertTrue(minmax._is_leaf(game, 0)) game.play(Point(0, 0)) game.play(Point(0, 1)) game.play(Point(1, 0)) game.play(Point(1, 1)) game.play(Point(2, 0)) self.assertTrue(minmax._is_leaf(game, 1)) self.assertTrue(minmax._is_leaf(game, 0))
def test_undo(self): board = Board(4, 2) token = "X" # Add 2 token self.assertTrue(board.add_token(Point(0, 0), token)) self.assertTrue(board.add_token(Point(1, 0), token)) self.assertEqual(board.cell_used_count, 2) # Undo last one board.undo(Point(1, 0)) self.assertEqual(board.cell_used_count, 1) # Check value in grid self.assertEqual(board.grid[0][0], token) self.assertEqual(board.grid[0][1], None)
def test_win_horizontal_player2(self): game = Gomoku() self.assertTrue(game.play(Point(0, 0))) self.assertTrue(game.play(Point(0, 1))) self.assertTrue(game.play(Point(1, 0))) self.assertTrue(game.play(Point(1, 1))) self.assertTrue(game.play(Point(2, 0))) self.assertTrue(game.play(Point(2, 1))) self.assertTrue(game.play(Point(3, 0))) self.assertTrue(game.play(Point(3, 1))) self.assertTrue(game.play(Point(0, 2))) self.assertTrue(game.play(Point(4, 1))) self.assertTrue(game.is_over) self.assertEqual(game.winner, game._p2)
def test_get_column(self): import numpy as np w, h = 5, 3 board = Board(w, h) # Len self.assertEqual(len(board.get_column(0)), h) # Default to None a = [None for i in range(h)] self.assertTrue(np.array_equal(board.get_column(0), a)) # Insert a[2] = 'x' board.add_token(Point(0, 2), 'x') self.assertTrue(np.array_equal(board.get_column(0), a)) # Exception board.get_column(0) board.get_column(1) board.get_column(2) board.get_column(3) board.get_column(4) with self.assertRaises(IndexError): board.get_row(5)
def test_get_diag_down(self): ''' 00|10|20|30|40| 01|11|21|31|41| 02|12|22|32|42| ''' import numpy as np w, h = 5, 3 board = Board(w, h) for y in range(h): for x in range(w): board.add_token(Point(x, y), str(x) + str(y)) line = board.get_diag_down(0, 0) self.assertTrue(np.array_equal(line, ['00', '11', '22'])) line = board.get_diag_down(3, 0) self.assertTrue(np.array_equal(line, ['30', '41'])) line = board.get_diag_down(4, 2) self.assertTrue(np.array_equal(line, ['20', '31', '42'])) line = board.get_diag_down(0, 1) self.assertTrue(np.array_equal(line, ['01', '12'])) line = board.get_diag_down(1, 2) self.assertTrue(np.array_equal(line, ['01', '12']))
def test_win_diag_up_player1(self): game = Gomoku() self.assertTrue(game.play(Point(4, 0))) self.assertTrue(game.play(Point(0, 0))) self.assertTrue(game.play(Point(3, 1))) self.assertTrue(game.play(Point(1, 0))) self.assertTrue(game.play(Point(2, 2))) self.assertTrue(game.play(Point(2, 0))) self.assertTrue(game.play(Point(1, 3))) self.assertTrue(game.play(Point(0, 1))) self.assertTrue(game.play(Point(0, 4))) self.assertTrue(game.is_over) self.assertEqual(game.winner, game._p1)
def test_draw(self): game = TicTacToe() self.assertTrue(game.play(Point(0, 0))) self.assertTrue(game.play(Point(1, 0))) self.assertTrue(game.play(Point(2, 0))) self.assertTrue(game.play(Point(0, 1))) self.assertTrue(game.play(Point(1, 1))) self.assertTrue(game.play(Point(2, 2))) self.assertTrue(game.play(Point(1, 2))) self.assertTrue(game.play(Point(0, 2))) self.assertTrue(game.play(Point(2, 1))) self.assertTrue(game.is_over) self.assertEqual(game.winner, None)
def test_generate_moves(self): game = TicTacToe() moves = game.generate_moves() self.assertEqual(moves, [ Point(0, 0), Point(1, 0), Point(2, 0), Point(0, 1), Point(1, 1), Point(2, 1), Point(0, 2), Point(1, 2), Point(2, 2) ])
def test_has_free_cell(self): board = Board(3, 3) for x in range(3): for y in range(3): self.assertTrue(board.has_free_cell()) self.assertTrue(board.add_token(Point(x, y), "X")) self.assertFalse(board.has_free_cell())
def test_win_horizontal_player1(self): game = Gomoku() self.assertTrue(game.play(Point(0, 0))) self.assertTrue(game.play(Point(0, 1))) self.assertTrue(game.play(Point(1, 0))) self.assertTrue(game.play(Point(1, 1))) self.assertTrue(game.play(Point(2, 0))) self.assertTrue(game.play(Point(2, 1))) self.assertTrue(game.play(Point(3, 0))) self.assertTrue(game.play(Point(3, 1))) self.assertTrue(game.play(Point(4, 0))) # Cannot play anymore, game is over self.assertFalse(game.play(Point(4, 1))) self.assertTrue(game.is_over) self.assertEqual(game.winner, game._p1)
def test_win_diag_down_player1(self): x, y = 0, 1 game = Gomoku() self.assertTrue(game.play(Point(x + 0, y + 0))) self.assertTrue(game.play(Point(x + 1, y + 0))) self.assertTrue(game.play(Point(x + 1, y + 1))) self.assertTrue(game.play(Point(x + 2, y + 0))) self.assertTrue(game.play(Point(x + 2, y + 2))) self.assertTrue(game.play(Point(x + 3, y + 0))) self.assertTrue(game.play(Point(x + 3, y + 3))) self.assertTrue(game.play(Point(x + 4, y + 0))) self.assertTrue(game.play(Point(x + 4, y + 4))) # print(game._board) self.assertTrue(game.is_over) self.assertEqual(game.winner, game._p1)
def test_win_vertical_all(self): for len in [7, 9, 11]: for x in range(len - 1): for y in range(len - GOMOKU_LINE_WIN_SIZE + 1): game = Gomoku(size=len) self.assertTrue(game.play(Point(x + 0, y + 0))) self.assertTrue(game.play(Point(x + 1, y + 0))) self.assertTrue(game.play(Point(x + 0, y + 1))) self.assertTrue(game.play(Point(x + 1, y + 1))) self.assertTrue(game.play(Point(x + 0, y + 2))) self.assertTrue(game.play(Point(x + 1, y + 2))) self.assertTrue(game.play(Point(x + 0, y + 3))) self.assertTrue(game.play(Point(x + 1, y + 3))) self.assertTrue(game.play(Point(x + 0, y + 4))) self.assertTrue(game.is_over) self.assertEqual(game.winner, game._p1)
def test_win_diag_up_all(self): for len in [7, 9, 11]: for x in range(len - 5 + 1): for y in range(len - 5 + 1): game = Gomoku(size=len) self.assertTrue(game.play(Point(x + 4, y + 0))) self.assertTrue(game.play(Point(x + 0, y + 0))) self.assertTrue(game.play(Point(x + 3, y + 1))) self.assertTrue(game.play(Point(x + 1, y + 0))) self.assertTrue(game.play(Point(x + 2, y + 2))) self.assertTrue(game.play(Point(x + 2, y + 0))) self.assertTrue(game.play(Point(x + 1, y + 3))) self.assertTrue(game.play(Point(x + 0, y + 1))) self.assertTrue(game.play(Point(x + 0, y + 4))) self.assertTrue(game.is_over) self.assertEqual(game.winner, game._p1)
def test_win_horizontal_all(self): for len in [7, 9, 11]: for x in range(len - GOMOKU_LINE_WIN_SIZE + 1): for y in range(len - 1): game = Gomoku(size=len) self.assertTrue(game.play(Point(x + 0, y + 0))) self.assertTrue(game.play(Point(x + 0, y + 1))) self.assertTrue(game.play(Point(x + 1, y + 0))) self.assertTrue(game.play(Point(x + 1, y + 1))) self.assertTrue(game.play(Point(x + 2, y + 0))) self.assertTrue(game.play(Point(x + 2, y + 1))) self.assertTrue(game.play(Point(x + 3, y + 0))) self.assertTrue(game.play(Point(x + 3, y + 1))) self.assertTrue(game.play(Point(x + 4, y + 0))) # Cannot play anymore, game is over self.assertFalse(game.play(Point(4, 1))) self.assertTrue(game.is_over) self.assertEqual(game.winner, game._p1)
def main(): pr = cProfile.Profile() pr.enable() depth = 4 p1 = Player("AI_1", Token.A, True) game = Gomoku(p1=p1, size=9) minmax = Minmax_AlphaBeta(p1, depth) moves = [ Point(4, 4), Point(3, 3), Point(4, 3), Point(3, 4), Point(3, 2), Point(4, 5) ] for m in moves: game.play(m) minmax.compute(game) pr.disable() # Construct stats ps = pstats.Stats(pr) ps.strip_dirs() # ps.sort_stats(SortKey.CUMULATIVE) ps.sort_stats('tottime') ps.print_stats()
def test_gomoku(self): from game.gomoku import Gomoku n = 2 depth = 4 p1 = Player("AI_1", Token.A, True) duration = 0 for i in range(n): game = Gomoku(p1=p1, size=9) minmax = Minmax_AB_Parallel(p1, depth) moves = [ Point(4, 4), Point(3, 3), Point(4, 3), Point(3, 4), Point(3, 2), Point(4, 5) ] for m in moves: game.play(m) start = time.time() minmax.compute(game) duration += time.time() - start print('Duration {}'.format(duration / n)) r = expected['gomoku'] delta = r * 3 / 100 self.assertAlmostEqual(duration / n, r, delta=delta)
def undo(self, x=None): point = None if x is not None: y = self._cell_free_column_count[x] point = Point(x, y) if not super().undo(point): return False self._cell_free_column_count[x] += 1 return True
def test_draw(self): history = [(0, 0), (0, 1), (0, 2), (0, 3), (0, 4), (0, 5), (0, 6), (1, 0), (1, 1), (1, 2), (1, 3), (1, 4), (1, 5), (1, 6), (2, 0), (2, 1), (2, 2), (2, 3), (2, 4), (3, 2), (4, 1), (3, 3), (2, 5), (2, 6), (3, 0), (3, 1), (3, 4), (3, 5), (3, 6), (4, 0), (4, 2), (4, 3), (5, 4), (4, 4), (5, 3), (4, 5), (4, 6), (5, 0), (5, 1), (5, 2), (5, 5), (5, 6), (6, 0), (6, 1), (6, 2), (6, 3), (6, 4), (6, 5), (6, 6)] game = Gomoku(size=7) for x, y in history: self.assertTrue(game.play(Point(x, y))) self.assertTrue(game.is_over) self.assertEqual(game.winner, None)
def __init__(self, p1=None, p2=None, size=9, line_win_size=5): self._board = Board(size, size) self._line_win_size = line_win_size self._p1 = p1 if not p1 is None else Player("Player 1", Token.A) self._p2 = p2 if not p2 is None else Player("Player 2", Token.B) assert (not (self._p1.token == self._p2.token)) self._current_player = self._p1 self._winner_player = None self._is_over = False self._history = list() self._moves_remaining = set( [Point(x, y) for y in range(size) for x in range(size)]) self._patterns = [ np.full(self._line_win_size, token) for token in [Token.A, Token.B] ]
def test_anti_diag(self): import numpy as np w, h = 5, 3 board = Board(w, h) for y in range(h): for x in range(w): board.add_token(Point(x, y), str(x) + str(y)) line = np.flipud(board._grid).diagonal(0) self.assertTrue(np.array_equal(line, ['02', '11', '20'])) line = np.flipud(board._grid).diagonal(1) self.assertTrue(np.array_equal(line, ['12', '21', '30'])) line = np.flipud(board._grid).diagonal(-1) self.assertTrue(np.array_equal(line, ['01', '10']))
def main(game_name, player_mode, level): if not game_name or not player_mode or not level: game_name = menu_list('Select game', ['TicTacToe', 'Connect Four', 'Gomoku'], 0) player_mode = menu_list('Select player mode', ['H_H', 'AI_H', 'H_AI', 'AI_AI'], 3) level = select_level(game_name) if not (player_mode == 'H_H') else None print('{} {} {}'.format(game_name, player_mode, level)) p1, p2 = make_player(player_mode) ai1, ai2 = make_ai(player_mode, level, p1, p2) game = make_game(game_name, p1, p2) view = ASCII_View(game.grid) view.welcome(game_name, VERSION) while game.is_over == False: view.current_player = game.current_player view.display() if game.current_player.is_ai: if game.current_player == p1: ai = ai1 elif game.current_player == p2: ai = ai2 move = ai.compute(game) view.add_message("Move: {} ({}s)".format(move, ai.computation_time)) else: if game_name == "Connect Four": move = view.ask_input(1) else: x, y = view.ask_input(2) move = Point(x, y) if not game.play(move): view.add_message("Input is invalid") if game.winner is None: view.add_message("Game is finished. Draw") else: view.add_message("Game is finished") view.add_message("Winner is {}".format(game.winner.name)) view.display()