Пример #1
0
 def setUp(self):
     players = [{
         "color": "blue",
         "score": 0,
         "places": []
     }, {
         "color": "yellow",
         "score": 0,
         "places": []
     }, {
         "color": "red",
         "score": 0,
         "places": []
     }]
     tiles = [[1, 1, 1, 1, 1], [1, 1, 1, 1, 1], [1, 1, 1, 1, 1],
              [1, 1, 1, 1, 1], [1, 1, 1, 1, 1]]
     self.state = State(players, tiles)
     self.state.place_penguin((4, 4))
     self.state.place_penguin((4, 3))
     self.state.place_penguin((4, 2))
     self.state.place_penguin((3, 4))
     self.state.place_penguin((3, 3))
     self.state.place_penguin((3, 2))
     self.state.place_penguin((2, 4))
     self.state.place_penguin((2, 3))
     self.state.place_penguin((2, 2))
     self.tree = GameTreeNode(self.state)
Пример #2
0
 def test_place_penguin(self):
     players = [{
         "color": "blue",
         "score": 0,
         "places": []
     }, {
         "color": "yellow",
         "score": 0,
         "places": []
     }]
     tiles = [[1, 0, 1, 0, 1], [1, 0, 1, 0, 1], [1, 0, 1, 0, 1],
              [1, 0, 1, 0, 1], [1, 0, 1, 0, 1]]
     self.state = State(players, tiles)
     placement = place_penguin(self.state)
     self.assertEqual(placement, [(0, 0)])
     self.state = GameTreeNode(self.state).generate_successor(placement)
     placement = place_penguin(self.state)
     self.assertEqual(placement, [(0, 2)])
     self.state = GameTreeNode(self.state).generate_successor(placement)
     placement = place_penguin(self.state)
     self.assertEqual(placement, [(0, 4)])
     self.state = GameTreeNode(self.state).generate_successor(placement)
     placement = place_penguin(self.state)
     self.assertEqual(placement, [(1, 0)])
     self.state = GameTreeNode(self.state).generate_successor(placement)
     placement = place_penguin(self.state)
     self.assertEqual(placement, [(1, 2)])
Пример #3
0
    def test_get_optimal_action_game_over(self):
        players = [{
            "color": "blue",
            "score": 0,
            "places": [(0, 0), (0, 2), (1, 0), (1, 2)]
        }, {
            "color": "yellow",
            "score": 0,
            "places": [(0, 1), (0, 3), (1, 1), (1, 3)]
        }]
        tiles = [[1, 1, 1, 1], [1, 1, 1, 1], [0, 0, 0, 0], [0, 0, 0, 0]]
        self.state = State(players, tiles)
        node = GameTreeNode(self.state)
        self.assertEqual(get_optimal_action(node), None)

        players = [{
            "color": "blue",
            "score": 0,
            "places": [(0, 0)]
        }, {
            "color": "yellow",
            "score": 0,
            "places": []
        }]
        tiles = [[1, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]
        self.state = State(players, tiles)
        node = GameTreeNode(self.state)
        self.assertEqual(get_optimal_action(node), None)
Пример #4
0
    def generate_successor(self, action):
        """
            generate_successor - returns the next state for the referee given that the action was valid.  Returns None otherwise.

            Parameters:
            action - An action is a list containing either:
                - a single tuple [(row,col)] representing the row and col coordinates of the players next penguin
                  placement one the board
                - two tuples [(origin-row, origin-col),(dest-row,dest-col)] where the first tuple represents the current
                  position of the penguin and the second tuple represents the destination of the move.

            Output ->
                Either
                    A State represnting the new state after the given action has taken placement
                Or
                    None if the action is an invalid move.

        """
        node = GameTreeNode(self.state)
        return node.generate_successor(action)
Пример #5
0
    def get_minimum_score(self, state: State, max_depth: int, player_idx: int):
        """
        get_minimum_score: Helper function for minimax that gets the min score of all possible moves from the given state,
                        looking forward the specified number of turns.

        Params:
            state: State - A state in which no more penguins will be placed.
            max_depth: int - An integer representing the number of turns that minimax will look forward to calculate the
                            optimal reward
            player_idx: int - An integer representing the turn index corresponding to the maximizing agent in the State
                            representation

        Output -> An integer representing the min reward for the given state after a certain number of turns (max_depth)
        """
        min_score = float("inf")
        node = GameTreeNode(state)
        for action in node.check_available_actions():
            min_score = min(
                self.minimax(node.generate_successor(action), max_depth,
                             player_idx), min_score)
        return min_score
Пример #6
0
    def get_optimal_action(self, node: GameTreeNode):
        # TODO: Make this actually use node.generate_tree() so it caches data!
        """
        get_optimal_action: Runs a minimax search on the provided GameTreeNode to the provided depth "d to determine the move
                            with the optimal "reward" (player score) for the current player after D moves, assuming that all
                            other players will play with the intent to minimize the current player's score. This function
                            takes in a GameTreeNode and evaluates the "reward" for each available action with a recursive
                            minimax evaluation function. This method returns an Action, which is a list of tuples in the
                            form [(w, x), (y, z)], where the first pair of coordinates represents the current position of
                            the penguin and the second pair of coordinates represents the intended destination.
                            In the case of a tiebreaker, a tiebreaker method gets called that will prioritize by origin
                            row coord, origin column coord, destination row coord, and destination column coord in that order.
        Params:
            node: GameTreeNode - The initial node, to which no more players will be added. This node should contain a state with
                                game phase PLAYING.

        Output -> A list of tuples in the form [(a, b), (c, d)] representing the optimal action. (a, b) represents the origin
                and (c, d) represents the destination. If the game is over, then this method returns None.
        """

        if not node or node.get_state().game_over():
            return None
        max_score = float("-inf")
        optimal_actions = []
        idx = node.get_state().get_turn_idx()
        for action in node.check_available_actions():
            successor_state = node.generate_successor(action)
            successor_score = self.minimax(successor_state, self.depth - 1,
                                           idx)
            if successor_score > max_score:
                max_score = successor_score
                optimal_actions = [action]
            elif successor_score == max_score:
                optimal_actions.append(action)
        if len(optimal_actions) > 1:
            return self.tiebreak(optimal_actions)[0]
        return optimal_actions[0] if len(optimal_actions) > 0 else False
Пример #7
0
 def test_generate_successor_placement(self):
     players = [{
         "color": "blue",
         "score": 0,
         "places": []
     }, {
         "color": "yellow",
         "score": 0,
         "places": []
     }, {
         "color": "red",
         "score": 0,
         "places": []
     }]
     tiles = [[1, 1, 1, 1, 1], [1, 1, 1, 1, 1], [1, 1, 1, 1, 1],
              [1, 1, 1, 1, 1], [1, 1, 1, 1, 1]]
     state = State(players, tiles)
     node = GameTreeNode(state)
     successor = node.generate_successor([(0, 0)])
     node = GameTreeNode(successor)
     successor = node.generate_successor([(0, 1)])
     node = GameTreeNode(successor)
     successor = node.generate_successor([(0, 2)])
     players = [{
         "color": "blue",
         "score": 0,
         "places": [[0, 0]]
     }, {
         "color": "yellow",
         "score": 0,
         "places": [[0, 1]]
     }, {
         "color": "red",
         "score": 0,
         "places": [[0, 2]]
     }]
     tiles = [[1, 1, 1, 1, 1], [1, 1, 1, 1, 1], [1, 1, 1, 1, 1],
              [1, 1, 1, 1, 1], [1, 1, 1, 1, 1]]
     expected_state = State(players, tiles, turn_index=0)
     self.assertEqual(successor, expected_state)
Пример #8
0
 def get_move(self, state: State, actions: list):
     return self.get_optimal_action(GameTreeNode(state))
Пример #9
0
class TestGameTreeNode(unittest.TestCase):
    def __init__(self, *args, **kwargs):
        unittest.TestCase.__init__(self, *args, **kwargs)
        self.state = None

    def setUp(self):
        players = [{
            "color": "blue",
            "score": 0,
            "places": []
        }, {
            "color": "yellow",
            "score": 0,
            "places": []
        }, {
            "color": "red",
            "score": 0,
            "places": []
        }]
        tiles = [[1, 1, 1, 1, 1], [1, 1, 1, 1, 1], [1, 1, 1, 1, 1],
                 [1, 1, 1, 1, 1], [1, 1, 1, 1, 1]]
        self.state = State(players, tiles)
        self.state.place_penguin((4, 4))
        self.state.place_penguin((4, 3))
        self.state.place_penguin((4, 2))
        self.state.place_penguin((3, 4))
        self.state.place_penguin((3, 3))
        self.state.place_penguin((3, 2))
        self.state.place_penguin((2, 4))
        self.state.place_penguin((2, 3))
        self.state.place_penguin((2, 2))
        self.tree = GameTreeNode(self.state)

    def test_check_valid_move(self):
        self.assertTrue(self.tree.check_valid_move((2, 4), (0, 4)))
        self.assertFalse(self.tree.check_valid_move((3, 4), (0, 4)))

    def test_generate_successor(self):
        successor = self.tree.generate_successor([(2, 4), (0, 4)])
        players = [{
            "color": "blue",
            "score": 1,
            "places": [(4, 4), (3, 4), (0, 4)]
        }, {
            "color": "yellow",
            "score": 0,
            "places": [(4, 3), (3, 3), (2, 3)]
        }, {
            "color": "red",
            "score": 0,
            "places": [(4, 2), (3, 2), (2, 2)]
        }]
        tiles = [[1, 1, 1, 1, 1], [1, 1, 1, 1, 1], [1, 1, 1, 1, 0],
                 [1, 1, 1, 1, 1], [1, 1, 1, 1, 1]]
        expected_state = State(players, tiles, turn_index=1)
        self.assertEqual(successor, expected_state)

    def test_generate_successor_placement(self):
        players = [{
            "color": "blue",
            "score": 0,
            "places": []
        }, {
            "color": "yellow",
            "score": 0,
            "places": []
        }, {
            "color": "red",
            "score": 0,
            "places": []
        }]
        tiles = [[1, 1, 1, 1, 1], [1, 1, 1, 1, 1], [1, 1, 1, 1, 1],
                 [1, 1, 1, 1, 1], [1, 1, 1, 1, 1]]
        state = State(players, tiles)
        node = GameTreeNode(state)
        successor = node.generate_successor([(0, 0)])
        node = GameTreeNode(successor)
        successor = node.generate_successor([(0, 1)])
        node = GameTreeNode(successor)
        successor = node.generate_successor([(0, 2)])
        players = [{
            "color": "blue",
            "score": 0,
            "places": [[0, 0]]
        }, {
            "color": "yellow",
            "score": 0,
            "places": [[0, 1]]
        }, {
            "color": "red",
            "score": 0,
            "places": [[0, 2]]
        }]
        tiles = [[1, 1, 1, 1, 1], [1, 1, 1, 1, 1], [1, 1, 1, 1, 1],
                 [1, 1, 1, 1, 1], [1, 1, 1, 1, 1]]
        expected_state = State(players, tiles, turn_index=0)
        self.assertEqual(successor, expected_state)