def _run_ai_simulation(game_surface: pygame.Surface, size: int,
                       player1: Union[MobilityTreePlayer, PositionalTreePlayer, RandomPlayer,
                                      ReversiGame, MCTSTimeSavingPlayer],
                       player2: Union[MobilityTreePlayer, PositionalTreePlayer, RandomPlayer,
                                      ReversiGame, MCTSTimeSavingPlayer]) -> None:
    if size == 8:
        background = pygame.image.load('assets/gameboard8.png')
    elif size == 6:
        background = pygame.image.load('assets/gameboard6.png')
    else:
        raise ValueError("invalid size.")
    game_surface.blit(background, (0, 0))
    pygame.display.flip()
    game = ReversiGame(size)
    previous_move = '*'
    board = game.get_game_board()
    _draw_game_state(game_surface, background, size, board)
    pass_move = pygame.image.load('assets/pass.png')
    player1_side = BLACK
    while game.get_winner() is None:
        if previous_move == '*' or game.get_current_player() == player1_side:
            move = player1.make_move(game, previous_move)
        else:
            move = player2.make_move(game, previous_move)
        previous_move = move
        game.make_move(move)
        if move == 'pass':
            surface = game_surface
            game_surface.blit(pass_move, (300, 300))
            pygame.display.flip()
            pygame.time.wait(500)
            game_surface.blit(surface, (0, 0))
            pygame.display.flip()
        else:
            board = game.get_game_board()
            _draw_game_state(game_surface, background, size, board)
        pygame.time.wait(500)
    winner = game.get_winner()
    if winner == BLACK:
        victory = pygame.image.load('assets/player1_victory.png')
        game_surface.blit(victory, (300, 300))
        pygame.display.flip()
        pygame.time.wait(3000)
        return
    elif winner == WHITE:
        defeat = pygame.image.load('assets/player2_victory.png')
        game_surface.blit(defeat, (300, 300))
        pygame.display.flip()
        pygame.time.wait(3000)
        return
    else:
        draw = pygame.image.load('assets/draw.png')
        game_surface.blit(draw, (300, 300))
        pygame.display.flip()
        pygame.time.wait(3000)
        return
Exemple #2
0
    def _minimax(self, root_move: tuple[int, int], depth: int,
                 game: ReversiGame, alpha: float, beta: float) -> GameTree:
        """
        _minimax is a minimax function with alpha-beta pruning implemented that returns
        a full GameTree where each node stores the given evaluation

        Preconditions
            - depth >= 0
        """
        white_move = (game.get_current_player() == -1)
        ret = GameTree(move=root_move, is_white_move=white_move)
        # early return at max depth
        if depth == self.depth:
            ret.evaluation = heuristic(game, self.heuristic_list)
            return ret
        possible_moves = list(game.get_valid_moves())
        if not possible_moves:
            if game.get_winner() == 'white':
                ret.evaluation = 10000
            elif game.get_winner() == 'black':
                ret.evaluation = -10000
            else:
                ret.evaluation = 0
            return ret
        random.shuffle(possible_moves)
        best_value = float('-inf')
        if not white_move:
            best_value = float('inf')
        for move in possible_moves:
            new_game = game.copy_and_make_move(move)
            new_tree = self._minimax(move, depth + 1, new_game, alpha, beta)
            ret.add_subtree(new_tree)
            # we update the alpha value when the maximizer is playing (white)
            if white_move and best_value < new_tree.evaluation:
                best_value = new_tree.evaluation
                alpha = max(alpha, best_value)
                if beta <= alpha:
                    break
            # we update the beta value when the minimizer is playing (black)
            elif not white_move and best_value > new_tree.evaluation:
                best_value = new_tree.evaluation
                beta = min(beta, best_value)
                if beta <= alpha:
                    break
        ret.evaluation = best_value
        return ret
Exemple #3
0
 def _minimax(self, root_move: tuple[int, int], game: ReversiGame,
              depth: int) -> GameTree:
     """
     _minimax is a function that returns a tree where each node has a value determined by
     the minimax search algorithm
     """
     white_move = (game.get_current_player() == -1)
     ret = GameTree(move=root_move, is_white_move=white_move)
     # early return if we have reached max depth
     if depth == self.depth:
         ret.evaluation = heuristic(game, self.heuristic_list)
         return ret
     possible_moves = list(game.get_valid_moves())
     # game is over if there are no possible moves in a position
     if not possible_moves:
         # if there are no moves, then the game is over so we check for the winner
         if game.get_winner() == 'white':
             ret.evaluation = 10000
         elif game.get_winner() == 'black':
             ret.evaluation = -10000
         else:
             ret.evaluation = 0
         return ret
     # shuffle for randomness
     random.shuffle(possible_moves)
     # best_value tracks the best possible move that the player can make
     # this value is maximized by white and minimized by black
     best_value = float('-inf')
     if not white_move:
         best_value = float('inf')
     for move in possible_moves:
         new_game = game.copy_and_make_move(move)
         new_subtree = self._minimax(move, new_game, depth + 1)
         if white_move:
             best_value = max(best_value, new_subtree.evaluation)
         else:
             best_value = min(best_value, new_subtree.evaluation)
         ret.add_subtree(new_subtree)
     # update the evaluation value of the tree once all subtrees are added
     ret.evaluation = best_value
     return ret
Exemple #4
0
    def make_move(self, game: ReversiGame,
                  previous_move: Optional[str]) -> str:
        """Make a move given the current game.

        previous_move is the opponent player's most recent move, or None if no moves
        have been made.

        Preconditions:
            - There is at least one valid move for the given game state
            - len(game.get_valid_moves) > 0

        :param game: the current game state
        :param previous_move: the opponent player's most recent move, or None if no moves
        have been made
        :return: a move to be made
        """
        if self._tree is None:  # initialize a tree if there is no tree
            if previous_move is None:
                self._tree = MCTSTree(START_MOVE, copy.deepcopy(game))
            else:
                self._tree = MCTSTree(previous_move, copy.deepcopy(game))
        else:  # update tree with previous move if there is a tree
            if len(self._tree.get_subtrees()) == 0:
                self._tree.expand()
            if previous_move is not None:
                self._tree = self._tree.find_subtree_by_move(previous_move)

        assert self._tree.get_game_after_move().get_game_board(
        ) == game.get_game_board()
        assert self._tree.get_game_after_move().get_current_player(
        ) == game.get_current_player()

        for _ in range(self._n):
            self._tree.mcts_round(self._c)

        # update tree with the decided move
        move = self._tree.get_most_confident_move()
        self._tree = self._tree.find_subtree_by_move(move)
        return move
Exemple #5
0
    def make_move(self, game: ReversiGame,
                  previous_move: Optional[str]) -> str:
        """Make a move given the current game.

        previous_move is the opponent player's most recent move, or None if no moves
        have been made.

        Preconditions:
            - There is at least one valid move for the given game state
            - len(game.get_valid_moves) > 0

        :param game: the current game state
        :param previous_move: the opponent player's most recent move, or None if no moves
        have been made
        :return: a move to be made
        """
        piece = game.get_current_player()
        tree = self.build_minimax_tree(game,
                                       piece,
                                       depth=self._depth,
                                       find_max=True,
                                       previous_move=previous_move)
        return tree.get_best()
Exemple #6
0
    # Window loop
    while window.is_running():
        """ UPDATE STUFF """

        # Get game winner
        winner = game.get_winner()
        if winner is not None:
            results.append(winner)
            ui_handler.update_games_stored_text(len(results), window)
            increment_player_score(winner, window)
            game.start_game(human_player=game.get_human_player())

        # If the game is not paused, look for mouse clicks and process moves.
        if not ui_handler.get_game_paused():
            if game.get_human_player() == game.get_current_player():
                # Look at the mouse clicks and see if they are in the board.

                for event in window.get_events():
                    if event[0] == pygame.MOUSEBUTTONUP:
                        square = board_manager.check_mouse_press(
                            event[1], game.get_board())
                        if square != (-1, -1):
                            if game.try_make_move(square):
                                moves_made.append(square)
            elif game.get_winner() is None:
                next_move = colour_to_player[
                    game.get_current_player()].make_move(game, moves_made[-1])
                game.try_make_move(next_move)
                moves_made.append(next_move)
def _run_ai_game(game_surface: pygame.Surface, size: int,
                 ai_player: Union[MobilityTreePlayer, PositionalTreePlayer, RandomPlayer,
                                  ReversiGame, MCTSTimeSavingPlayer],
                 user_side: str = BLACK) -> None:
    if size == 8:
        background = pygame.image.load('assets/gameboard8.png')
    elif size == 6:
        background = pygame.image.load('assets/gameboard6.png')
    else:
        raise ValueError("invalid size.")
    game_surface.blit(background, (0, 0))
    pygame.display.flip()
    game = ReversiGame(size)
    previous_move = '*'
    if user_side == BLACK:
        ai_side: str = WHITE
    else:
        ai_side: str = BLACK
    board = game.get_game_board()
    _draw_game_state(game_surface, background, size, board)

    pass_move = pygame.image.load('assets/pass.png')

    while game.get_winner() is None:
        if (previous_move == '*' and user_side == WHITE) or game.get_current_player() == user_side:
            if game.get_valid_moves() == ['pass']:
                game.make_move('pass')
                previous_move = 'pass'

                surface = game_surface
                game_surface.blit(pass_move, (300, 300))
                pygame.display.flip()
                pygame.time.wait(1000)
                game_surface.blit(surface, (0, 0))
                pygame.display.flip()

                continue
            while True:
                event = pygame.event.wait()
                if event.type == pygame.MOUSEBUTTONDOWN:
                    mouse_pos = pygame.mouse.get_pos()
                    if 585 <= mouse_pos[0] <= 795 and 10 <= mouse_pos[1] <= 41:
                        return
                    else:
                        move = _search_for_move(mouse_pos, size)
                        print(move)
                        if move == '' or move not in game.get_valid_moves():
                            continue
                        else:
                            previous_move = move
                            game.make_move(move)
                            board = game.get_game_board()
                            _draw_game_state(game_surface, background, size, board)
                            pygame.time.wait(1000)
                            break
                if event.type == pygame.QUIT:
                    return
        else:
            move = ai_player.make_move(game, previous_move)
            previous_move = move
            game.make_move(move)
            if move == 'pass':
                surface = game_surface
                game_surface.blit(pass_move, (300, 300))
                pygame.display.flip()
                pygame.time.wait(1000)
                game_surface.blit(surface, (0, 0))
                pygame.display.flip()
            else:
                board = game.get_game_board()
                _draw_game_state(game_surface, background, size, board)
    winner = game.get_winner()
    if winner == user_side:
        victory = pygame.image.load('assets/victory.png')
        game_surface.blit(victory, (300, 300))
        pygame.display.flip()
        pygame.time.wait(3000)
        return
    elif winner == ai_side:
        defeat = pygame.image.load('assets/defeat.png')
        game_surface.blit(defeat, (300, 300))
        pygame.display.flip()
        pygame.time.wait(3000)
        return
    else:
        draw = pygame.image.load('assets/draw.png')
        game_surface.blit(draw, (300, 300))
        pygame.display.flip()
        pygame.time.wait(3000)
        return