Exemplo n.º 1
0
 def test_create_initial_state(self):
     """
     Purpose:Test creating an initial game state where only the ref can remove
             penguins (no players yet)
     Signature: Void -> Void
     """
     board = FishBoardModel.create_with_same_fish_amount(4, 3, 3)
     game_state = FishGameState(
         board, player_colors=[PlayerColor.RED, PlayerColor.BROWN])
     self.assertEqual([PlayerColor.RED, PlayerColor.BROWN],
                      game_state.get_player_order())
     self.assertEqual(PlayerColor.RED, game_state.get_current_turn())
     self.assertEqual(GamePhase.PLACE_PENGUINS, game_state.get_game_phase())
Exemplo n.º 2
0
 def _any_player_has_penguin(state: FishGameState,
                             coord: Coordinate) -> bool:
     """
     Purpose: To check if any of the players have a penguin on a given valid coordinate on the board
     Signature: FishGameState Coordinate -> Boolean
     :param state: The current state of the game
     :param coord: A valid coordinate on the board in the state
     :return: Boolean representing if any of the players have a penguin in the given coord
     """
     for player in state.get_player_order():
         penguins = state.get_penguins_for_player(player)
         if penguins:
             if coord in penguins:
                 return True
     return False
 def render_penguins(cls, state: FishGameState, canvas: Canvas) -> None:
     """
     Purpose: Display the penguins on the board
     Signature: FishGameState TkCanvas -> Void
     :param state: State that we want to render penguins for
     :param canvas: Canvas that we want to display penguins on
     """
     order = state.get_player_order()
     penguins = dict()
     for color in order:
         penguins[color] = state.get_penguins_for_player(color)
     for color, coordinates in penguins.items():
         for coord in coordinates:
             x_offset, y_offset = FishBoardView.offset_coordinate(*coord)
             FishAvatarView.add_avatar_to_canvas(canvas, x_offset, y_offset,
                                                 color.value)
 def convert_state_to_json(state: FishGameState):
     board = TestHarnessTransformationHelper.convert_board_to_json(
         state.get_board())
     player_order = state.get_player_order()
     current_player_index = player_order.index(state.get_current_turn())
     players = [{
         "color":
         color.value,
         "score":
         state.get_fish_for_player(color),
         "places": [
             TestHarnessTransformationHelper.convert_back_to_posn(
                 coordinate[0], coordinate[1])
             for coordinate in state.get_penguins_for_player(color)
         ]
     } for color in player_order[current_player_index:] +
                player_order[:current_player_index]]
     return {"players": players, "board": board}
 def create_state_window(cls, state: FishGameState) -> Tuple[Tk, Canvas]:
     """
     Purpose: Display the game state overall
     Signature: FishGameState -> TkWindow TkCanvas
     :param state: current state of the game to display
     :return: the state window and canvas the board is drawn on
     """
     board = state.get_board()
     window, canvas = FishBoardView.create_board_window(Tk(), board)
     FishGameStateView.render_penguins(state, canvas)
     order = state.get_player_order()
     fish_dict = dict()
     for color in order:
         fish_dict[color] = state.get_fish_for_player(color)
     FishGameStateView.render_order(order, window)
     FishGameStateView.render_fish(fish_dict, window)
     FishGameStateView.render_game_phase(state.get_game_phase(), window)
     FishGameStateView.render_turn(state.get_current_turn(), window)
     return window, canvas
Exemplo n.º 6
0
 def __init__(self, state: FishGameState, depth: int = 0,
              parent_action: Action = None):
     """
     Purpose: Initialize a game state tree. Has a certain state and turn color plus all
              of the turns for a certain player, also controls information about the other nodes
              it may be related to
     Signature: FishGameState PlayerColor -> FishGameTree
     :param state: the state that we are initializing this tree with
     :param depth: How deep in the tree this node of the tree is
     :param parent_action: What action was taken by the parent to get to this node
     """
     if not state.get_game_phase() == GamePhase.MOVE_PENGUINS:
         raise ValueError('Must be in moving penguins phase')
     self.state: FishGameState = state
     self.possible_moves: List[Action] = self.find_actions()
     self.depth: int = depth
     self.parent_action = parent_action
     self.end_game_state = False
     if not self.possible_moves:
         self.end_game_state = not state.can_any_player_move()
Exemplo n.º 7
0
 def find_next_placement(self, state: FishGameState) -> Coordinate:
     """
     Purpose: To find the next valid coordinate where a player can place a penguin, going left to right on the board
     rows
     Signature: FishGameState -> Coordinate
     :param state: The current state of the game
     :return: Coordinate representing a position where a penguin can be placed
     """
     board = state.get_board()
     sorted_coords = board.get_coords_sorted_by_row()
     for coord in sorted_coords:
         if not FishBasicStrategy._any_player_has_penguin(state, coord):
             return coord
     raise ValueError("Board cannot accommodate all penguins.")
Exemplo n.º 8
0
    def find_next_move(self, state: FishGameState) -> Action:
        """
        Purpose: Find best move for player whose turn it is in the current state
        after going N turns ahead for that player in the current turn, or as many possible.
        This assumes that a player using this will have at least 1 possible move on their
        turn. This holds because the referee would never ask for a move for a player who
        has a turn skipped. N turns ahead means that we will look at the current players moves for that many
        turns ahead. We could, and in some cases should look at their opponents move for that final turn where
        turn=N, but for this particular maximin evaluation we only have to look to the depth where the player
        we are checking has made their Nth move and not look at their opponents moves also.

        This is because the evaluation function only checks the amount of fish that the maximizing player has, which means that
        the opponents moves in the Nth round cannot impact the amount of fish that the strategizing player has,
        and thus is wasted computation. If we had another maximin evaluation function that took into account other
        factors that could change turn-by-turn, we would also checks the opponents moves in the Nth round.
        Signature: FishGameState Int -> Action
        :param state: The state for which we are looking for a move. This state includes the current
                      turn so we know which player to look for
        :return: The action representing a from and to position that is the player best
                 move according to the maximin algorithm
        """
        game_tree = FishGameTree(state=state)
        max_value = float("-inf")
        best_children = []
        for child in game_tree.generate_direct_children():
            # we have already gone one turn down, so
            # depth is amount of players there are * the number of turns - 1
            depth = (self.look_ahead_turns - 1) * len(state.get_player_order())
            minimax_value = FishBasicStrategy._find_maximin_value(
                child, False, depth, game_tree.get_turn_color())
            if minimax_value > max_value:
                best_children = [child]
                max_value = minimax_value
            elif minimax_value == max_value:
                best_children.append(child)
        if len(best_children) == 1:
            best_action = best_children[0].parent_action
        else:
            best_action = FishBasicStrategy._break_ties(
                [tree.get_parent_action() for tree in best_children])
        return best_action