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_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)
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)])
def get_state(self): """ get_state - returns the state that this playerAI is currently using. Output -> A State representing this players current gamestate. """ return State.from_state(self.state)
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)
def place_penguin(self, state: State): """ place_penguins: Takes a State and modifies the state in place to automatically place player penguins on the board until each player has 6-N penguins. This method starts from the top left corner (0, 0) and goes from left to right until each row is filled up, at which point it will move down a row. This method assumes that the board contained in the game state is large enough to accommodate all penguins. Params: state: State - The provided state. """ if not state: return None rows, columns = state.get_board_size() for i in range(rows): for j in range(columns): if state.valid_placement((i, j)): return [(i, j)] return None
def makestate(self): """ makestate - Makes a Random Starting Gamestate for this referee. Output -> A Gamestate with a random 5x5 board for this referee. """ new_player_list = [] for i in range(len(self.players)): player = {'color': colors[i], 'score': 0, 'places': []} new_player_list.append(player) return State(new_player_list, Board.make_random_board(5, 5).get_board())
def test_can_player_move(self): players = [{ "color": "blue", "score": 0, "places": [[0, 0]] }, { "color": "yellow", "score": 0, "places": [[1, 1]] }, { "color": "red", "score": 0, "places": [[2, 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]] state = State(players, tiles) self.assertTrue(state.can_player_move(0)) self.assertTrue(state.can_player_move(1)) self.assertTrue(state.can_player_move(2))
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)
def minimax(self, state: State, max_depth: int, player_idx: int): """ minimax: Returns the optimal "reward" for a player after max_depth number of turns, where the reward is the total score of the maximizing agent (current player). Minimax assumes both a minimizing and maximizing agents, where minimizing agents (other players) are trying to minimize the maximizing agent's reward, whereas maximizing agents are trying to maximize their own reward. 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 reward for the given state after a certain number of turns (max_depth) """ if not state or max_depth == 0 or state.game_over(): return state.get_players()[player_idx].get_score() elif state.get_turn_idx() == player_idx: return self.get_maximum_score(state, max_depth - 1, player_idx) else: return self.get_minimum_score(state, max_depth, player_idx)
def test_equality(self): players = [{ "color": "blue", "score": 0, "places": [(0, 0), (0, 3), (1, 1)] }, { "color": "yellow", "score": 0, "places": [(0, 1), (0, 4), (1, 2)] }, { "color": "red", "score": 0, "places": [(0, 2), (1, 0), (1, 3)] }] 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, game_phase=Game_Phase.PLAYING) player = PlayerAI(0) player.update_state(state) players2 = [{ "color": "blue", "score": 0, "places": [(0, 0), (0, 3), (1, 1)] }, { "color": "yellow", "score": 0, "places": [(0, 1), (0, 4), (1, 2)] }, { "color": "red", "score": 0, "places": [(0, 2), (1, 0), (1, 3)] }] tiles2 = [[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]] state2 = State(players2, tiles2, game_phase=Game_Phase.PLAYING) player2 = PlayerAI(0) player2.update_state(state2) self.assertEqual(player, player2)
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 __init__(self, state: State, moves = []): """ __init__ - Creates a GameTreeNode given either the players, tiles, and parent, or given a State and parent. Parameters: Mandatory Either: players - List of Player objects, in order of turn. tiles - List of tiles representing the full structure of the board. Tile should be represented in a MxN list of list of ints, where each int represents the number of fish on the tile. Or: state - A complete State. This state will be used as the starting state for this node. Optional: parent - The parent node of this GameTreeNode. Output -> A Tree_node object with the provided players, tiles, and parent. """ self.state = State.from_state(state) self.previous_moves = moves # TODO: children should be a dict to make finding pregenerated children easier self.children = []
def make_referee_same_fish(players, row, col, fish_per_tile, holes=None): if holes is None: holes = [] tile_list = [] for i in range(0, row): cur_row = [] for j in range(0, col): cur_row.append(fish_per_tile) tile_list.append(cur_row) valid_val = lambda x, max_val: x > 0 and x < max_val for coord in holes: if valid_val(coord[0], row) and valid_val(coord[1], col): tile_list[coord[0]][coord[1]] = 0 new_player_list = [] for i in range(len(players)): player = {'color': colors[i], 'score': 0, 'places': []} new_player_list.append(player) state = State(new_player_list, tile_list) ref = Referee(players) ref.state = state return ref
def generate_successor(self, action: list): """ generate_successor - Query function that takes in a GameTreeNode, penguin position, and destination coordinates and either signals that the action is illegal by returning None or returns the resulting state from the action. Parameters: action: list - An action is one of: - A list containing one tuple [(row, col)]. This represents a placement. - A list containing 2 tuples [(origin-row, origin-col), (dest-row, dest-col)], representing a movement. """ state = State.from_state(self.state) try: if len(action) == 0: return state if self.state.get_game_phase() == Game_Phase.PLACEMENT: state.place_penguin(action[0]) elif self.state.get_game_phase() == Game_Phase.PLAYING: state.move_penguin(action[0], action[1]) else: raise ValueError("") return state except (ValueError, IndexError): return None
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)
def get_state(self): return State.from_state(self.state)
class TestState(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) def test_from_state(self): new_state = State.from_state(self.state) self.assertTrue(self.state == new_state) def test_can_player_move(self): players = [{ "color": "blue", "score": 0, "places": [[0, 0]] }, { "color": "yellow", "score": 0, "places": [[1, 1]] }, { "color": "red", "score": 0, "places": [[2, 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]] state = State(players, tiles) self.assertTrue(state.can_player_move(0)) self.assertTrue(state.can_player_move(1)) self.assertTrue(state.can_player_move(2)) def test_place_penguin(self): self.state.place_penguin((4, 4)) self.state.place_penguin((4, 3)) self.state.place_penguin((4, 2)) players = self.state.get_players() self.assertEqual(players[0].get_penguin_locations(), [(4, 4)]) self.assertEqual(players[1].get_penguin_locations(), [(4, 3)]) self.assertEqual(players[2].get_penguin_locations(), [(4, 2)]) self.assertFalse(self.state.board.check_valid_tile(4, 4)) self.assertFalse(self.state.board.check_valid_tile(4, 3)) self.assertFalse(self.state.board.check_valid_tile(4, 2)) def test_move_penguin(self): self.state.place_penguin((4, 4)) self.state.place_penguin((4, 3)) self.state.place_penguin((4, 2)) self.assertRaises(ValueError, self.state.move_penguin, (4, 3), (2, 3)) 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.state.move_penguin((2, 4), (0, 4)) self.assertEqual(self.state.get_turn_idx(), 1) self.assertEqual(self.state.players[0].get_penguin_locations(), [(4, 4), (3, 4), (0, 4)]) self.assertEqual(self.state.players[0].get_score(), 1) self.assertFalse(self.state.board.check_valid_tile(2, 4)) self.state.move_penguin((2, 3), (0, 3)) self.assertEqual(self.state.get_turn_idx(), 2) self.assertEqual(self.state.players[1].get_penguin_locations(), [(4, 3), (3, 3), (0, 3)]) self.assertEqual(self.state.players[1].get_score(), 1) self.assertFalse(self.state.board.check_valid_tile(2, 3)) self.state.move_penguin((2, 2), (0, 2)) self.assertEqual(self.state.get_turn_idx(), 0) self.assertEqual(self.state.players[2].get_penguin_locations(), [(4, 2), (3, 2), (0, 2)]) self.assertEqual(self.state.players[2].get_score(), 1) self.assertFalse(self.state.board.check_valid_tile(2, 2)) def test_get_valid_moves(self): 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)) expected = [[(3, 4), (1, 4)], [(2, 4), (0, 4)], [(2, 4), (1, 4)], [(2, 4), (1, 3)], [(2, 4), (0, 3)]] self.assertEqual(self.state.get_valid_moves(), expected)
def test_from_state(self): new_state = State.from_state(self.state) self.assertTrue(self.state == new_state)