示例#1
0
 def determineWin(self, board: np.ndarray, player: BoardPiece) -> bool:
     """
     # Case 1: player == 1, and wins -> return true
     # Case 2: player == 2, and wins -> return false
     """
     if check_end_state(board, player) == GameState.IS_WIN:
         return True
     elif check_end_state(board, opponent(player)) == GameState.IS_WIN:
         return False
     else:  # draw
         return None
示例#2
0
 def rollout(self, board: np.ndarray, player: BoardPiece) -> BoardPiece:
     """
     Recursive call with opponent, determineWin() check for and return win
     :param board:
     :param player:
     :return: player if won, otherwise continue the rollout with recursive call
     """
     if self.isTerminal(board, player):
         if self.determineWin(board, player):  # if win
             return player
         elif self.determineWin(board, opponent(player)):  # if loss
             return opponent(player)
         else:  # if draw
             return BoardPiece(0)  # None
     else:  # generate a random move, create a new board state, apply random move
         random_move, saved_state = generate_move_random(board, player)
         random_board = apply_player_action(board, random_move, player,
                                            True)
         return self.rollout(random_board, opponent(
             player))  # recursive call, passing in new board & opponent
示例#3
0
 def create_child(self, avail_cols: list):
     """
     Create a new child node during Expansion at a random column within the available moves (columns)
     :param avail_cols:
     :return: the new child node
     """
     col = np.random.choice(avail_cols)
     board_copy = apply_player_action(self.board, col, self.nodePlayer,
                                      True)
     new_node = Node(board_copy, opponent(self.nodePlayer))
     new_node.parent = self
     self.children.append(new_node)
     return new_node
示例#4
0
def mcts(tree: Tree):
    """
    Run many iterations of the MCTS tree and build out its statistics
    :param tree:
    :return None
    """
    for _ in range(3000):
        node = tree.select(tree.root)
        test_node, test_player = tree.expand(node, node.nodePlayer)
        winner = test_node.rollout(
            test_node.board, opponent(test_player))  # rollout on opponent
        tree.update_Tree(test_node, winner)
    return
示例#5
0
def minimax(
    board: np.ndarray,
    player: BoardPiece,
    saved_state: Optional[SavedState] = None
) -> Tuple[int, Optional[SavedState]]:
    """
    This function returns the best position for the agent to play by returning the appropriate column index. The
    agent checks to see if there is a win in any of the available columns, and if so, makes that move. If not, it iterates
    through every column, makes a move there, and checks whether the opposing player can win subsequently. If the opposing
    player can win given the current player's first move, the current player chooses not to make that move in the first
    place.

    Keyword arguments:
        board: the board that the player is playing and trying to win
        player: current player
        saved_state: Optional Saved State

    Returns:
        Tuple: consisting of the location of the column of the best move, and the Optional Saved State
    """

    danger_col = []
    columns = [0, 1, 2, 3, 4, 5, 6]
    score = 0

    other_player = opponent(player)

    for i in available_columns(board):
        board_i = apply_player_action(board, i, player, True)
        if connected_four(board_i, player) == True:
            return i, saved_state
        else:
            danger_col = []
            for j in available_columns(board_i):
                board_i_j = apply_player_action(board_i, j, other_player, True)
                if connected_four(board_i_j, other_player) == True:
                    danger_col.append(
                        j
                    )  # these columns will lead to the opposing player's win

        if len(danger_col) != 0:
            columns.remove(
                i
            )  # don't use columns i in random.choice if they will lead to an other_player win
    cols = np.array(columns)
    action = np.random.choice(
        cols)  # randomly choose a column that will avoid a loss in the
    # opposing player's next move

    return action, saved_state
示例#6
0
 def isTerminal(self, board: np.ndarray, player: BoardPiece) -> bool:
     """
     Take in a board, and a player, and make a determination if the board is terminal or not.
     Check if no available columns (moves) or if either player has won.
     :param self:
     :param board:
     :param player:
     :return: True or False
     """
     if available_columns(board) == [] or self.determineWin(
             board, player) or self.determineWin(board, opponent(player)):
         return True
     else:
         return False
示例#7
0
 def expand(self, node: Node,
            player: BoardPiece) -> Tuple[Node, BoardPiece]:  # insert node
     """
     Create one child node of the given node. If no more children left to create, return self.
     :param: parent node
     :return: True
     """
     avail_cols = available_columns(node.board)
     if avail_cols is None:  # no available moves
         print('board is full')
         return node, player  # return self
     else:
         new_node = Node.create_child(node, avail_cols)
         return new_node, opponent(
             player)  # child node has board with opponent's turn to play