def test_no_winner(): b1 = [[0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 2], [0, 1, 2, 1, 2, 1, 1]] board1 = Board(board=b1) winner1 = Board.check_winner(board1) assert winner1 == -1
class Game: def __init__(self, player1: Player, player2: Player): self.board = Board(turn=1) self.player1 = player1 self.player2 = player2 def start(self): self.board.print_board() while not self.board.terminal: print("Turn:", self.board.turn) player = self.get_player() move = player.get_move(self.board) self.board = self.board.play_turn(move) self.board.print_board() print("Game over. Winner", self.board.winner) def get_player(self): """ Get the player """ if self.board.turn == 1: return self.player1 elif self.board.turn == 2: return self.player2
def test_rows(): b1 = [[0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 2, 0, 0, 0], [0, 1, 2, 1, 0, 0, 0], [0, 2, 1, 1, 1, 1, 2], [0, 1, 2, 1, 2, 1, 1]] board1 = Board(b1) winner1 = Board.check_winner(board1) assert winner1 == 1
def test_play_turn(): b = [[0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0], [0, 1, 2, 0, 0, 0, 0], [0, 2, 1, 2, 0, 0, 0], [0, 1, 2, 1, 2, 1, 1]] board = Board(board=b, turn=2) winner_before = Board.check_winner(board) assert winner_before == -1 assert board.terminal is False new_board = board.play_turn(1) assert new_board.winner == 2 assert new_board.terminal is True
def test_diagonal_right_to_left(): # winner 1 (1st diagonal) b1 = [[0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 1], [2, 1, 2, 1, 0, 1, 2], [1, 2, 1, 2, 1, 1, 2], [2, 1, 2, 1, 2, 1, 1]] # winner 2 (4th diagonal) b2 = [[0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 2], [1, 0, 0, 2, 0, 0, 2], [2, 1, 2, 1, 2, 1, 1], [1, 2, 2, 2, 1, 1, 2], [2, 1, 1, 1, 2, 1, 1]] board1 = Board(b1) winner1 = Board.check_winner(board1) assert winner1 == 1 board2 = Board(b2) winner2 = Board.check_winner(board2) assert winner2 == 2
def get_move(self, board: Board) -> int: possible_moves = board.possible_moves() print("possible moves", possible_moves) move = None while move is None: _input = input("Human, your turn! > ") try: _input = int(_input) except ValueError: print("Invalid input, not a number") continue if self.is_valid_move(_input, board): move = _input else: print("Invalid move") return move
def is_valid_move(move, board: Board) -> bool: return move in board.possible_moves()
def simulate(node): return Board.simulate(node.board)
def __init__(self, player1: Player, player2: Player): self.board = Board(turn=1) self.player1 = player1 self.player2 = player2
def search_move_minimax(raw_board, turn): board = Board(board=np.array(raw_board), turn=turn) mm = Minimax(8) move = mm.search(board) return move
def search_move_mc(raw_board, turn): board = Board(board=raw_board, turn=turn) mc = MonteCarlo(root=Node(board), nof_sims=1000) move = mc.search() return move
def minimax(self, board: Board, alpha, beta, is_maximizing_player, player, depth): if board.terminal: if board.winner == 0: return 0, -1 elif board.winner != player: return -1 * (self.discount**depth), -1 # value, move elif board.winner == player: return 1 * (self.discount**depth), -1 # value, move moves = board.possible_moves() if depth == self.MAX_DEPTH: return 0, -1 if len(moves) == 0: # probably no necessary return 0, -1 if is_maximizing_player: max_eval = -math.inf optimal_move = -1 pos_moves = board.possible_moves() new_boards = [board.play_turn(move) for move in pos_moves] new_boards = self.sort_boards(new_boards, board.turn, board.count_pieces(), self.random_move) for new_board in new_boards: _eval, _ = self.minimax(new_board, alpha, beta, False, player, depth + 1) if _eval > max_eval: max_eval = _eval optimal_move = new_board.previous_move # previous move led to this state alpha = max(alpha, _eval) if beta <= alpha: break return max_eval, optimal_move else: min_eval = math.inf optimal_move = -1 pos_moves = board.possible_moves() new_boards = [board.play_turn(move) for move in pos_moves] new_boards = self.sort_boards(new_boards, board.turn, board.count_pieces(), self.random_move) for new_board in new_boards: _eval, m = self.minimax(new_board, alpha, beta, True, player, depth + 1) if _eval < min_eval: min_eval = _eval optimal_move = new_board.previous_turn() beta = min(beta, _eval) if beta <= alpha: break return min_eval, optimal_move