def __init__(self): self.board = Board() self.board.board_init() self.memory = Memory() self.qlearn = QLearningTable(actions=ACTION_SPACE) self.previous_action = None self.previous_state = None self.previous_score = 0 self.states_seen = 0 self.game_count = 0 self.max_points = 0
def test_swipe_right_initialized_board(self): self.board.board_init(test=True) self.expectedboard = Board() self.expectedboard.tiles = [[Tile(0), Tile(0), Tile(0), Tile(3)], [Tile(0), Tile(1), Tile(2), Tile(3)], [Tile(0), Tile(3), Tile(2), Tile(1)], [Tile(0), Tile(2), Tile(1), Tile(0)]] self.board.swipe("right", add_new_tile=False) self.assertTrue(boards_match(self.board, self.expectedboard))
def test_swipe_right_one_tile_on_edge(self): # With the board initialized, I swipe up on the board, and the tiles # all move correctly. # Start with just one 1 tile on the top wall, see if it moves properly. self.board.tiles = [[Tile(0), Tile(0), Tile(0), Tile(0)], [Tile(0), Tile(0), Tile(0), Tile(0)], [Tile(0), Tile(0), Tile(0), Tile(1)], [Tile(0), Tile(0), Tile(0), Tile(0)]] self.expectedboard = Board() self.expectedboard.tiles = [[Tile(0), Tile(0), Tile(0), Tile(0)], [Tile(0), Tile(0), Tile(0), Tile(0)], [Tile(0), Tile(0), Tile(0), Tile(1)], [Tile(0), Tile(0), Tile(0), Tile(0)]] self.board.swipe("right", add_new_tile=False) # Check if the 1 tile moved up properly. self.assertTrue(boards_match(self.board, self.expectedboard))
def test_swipe_up_one_tile_on_edge(self): # With the board initialized, I swipe up on the board, and the tiles # all move correctly. # Start with just one 1 tile on the top wall, see if it moves properly. self.board.tiles = [[Tile(0), Tile(1), Tile(0), Tile(0)], [Tile(0), Tile(0), Tile(0), Tile(0)], [Tile(0), Tile(0), Tile(0), Tile(0)], [Tile(0), Tile(0), Tile(0), Tile(0)]] self.expectedboard = Board() self.expectedboard.tiles = [[Tile(0), Tile(1), Tile(0), Tile(0)], [Tile(0), Tile(0), Tile(0), Tile(0)], [Tile(0), Tile(0), Tile(0), Tile(0)], [Tile(0), Tile(0), Tile(0), Tile(0)]] self.board.swipe("up", add_new_tile=False) # Check if the 1 tile moved up properly. # for index, board_row in enumerate(self.board.tiles): # self.assertEqual([tile.value for tile in board_row], [ # tile.value for tile in self.expectedboard.tiles[index]]) self.assertTrue(boards_match(self.board, self.expectedboard))
class BasicAgent(): def __init__(self): self.board = Board() self.board.board_init() self.memory = Memory() self.qlearn = QLearningTable(actions=ACTION_SPACE) self.previous_action = None self.previous_state = None self.previous_score = 0 self.states_seen = 0 self.game_count = 0 self.max_points = 0 def step(self): obs = self.board.read_board() # flatten our state into one list state = [item for sublist in obs["tiles"] for item in sublist] score = obs["points"] # Give reward based on increased score for that single step # I wonder if lower reward values (closer to ~1 range) are better? score_difference = score - self.previous_score # last step of game if obs["last"]: final_point_total = obs["points"] # print("Game", self.game_count, # "ended with a score of", final_point_total) if final_point_total > self.max_points: print("New high score! Previous max was", self.max_points) self.max_points = final_point_total # loop through all saved states one by one and train on them # memory entries are of form [state, action, reward] current_memory = self.memory.pop() next_memory = self.memory.pop() while next_memory is not None: self.qlearn.learn(str(current_memory[0]), current_memory[1], final_point_total + current_memory[2], str(next_memory[0])) current_memory = next_memory # print(str(final_point_total + current_memory[2])) next_memory = self.memory.pop() # last memory gets a terminal code self.qlearn.learn(str(current_memory[0]), current_memory[1], final_point_total + current_memory[2], 'terminal') # print(str(self.qlearn.q_table)) # reset board self.board.board_init() self.memory.reset() self.previous_state = None self.previous_action = None self.previous_score = 0 self.states_seen = len(self.qlearn.q_table.index) # take no action return final_point_total if obs["first"]: self.game_count += 1 # return self.previous_score else: self.memory.push(self.previous_state, self.previous_action, score_difference) # self.qlearn.learn(str(self.previous_state), self.previous_action, # score_difference, str(state)) action = self.qlearn.choose_action(str(state)) # take action valid_move = self.board.swipe(action) # if not valid_move: # print("invalid move", action) # print(self.board) # print(score, 'points') # print(' ') # prepare for next step self.previous_state = state self.previous_action = action self.previous_score = score
def setUp(self): self.board = Board()
class BoardAndTileTest(unittest.TestCase): def setUp(self): self.board = Board() def test_board_read_board_method_returns_4_by_4_list_and_array_of_possible_tiles(self): # I go to make a board. boardoutput = self.board.read_board() # It contains four arrays of length four, tiles = boardoutput["tiles"] for row in tiles: self.assertEqual(len(row), 4) # and one array of length 1 to 3 to indicate the next possible tile(s) next_tiles = boardoutput["next"] self.assertIn(len(next_tiles), [1, 2, 3]) def test_board_read_board_method_returns_a_4_by_4_list_of_integers_and_array_of_integers(self): # The board contains four arrays, where each element is a Tile object # I go to make a board. boardoutput = self.board.read_board() tiles = boardoutput["tiles"] # It contains four arrays with four Tiles each, for row in tiles: for element in row: self.assertIsInstance(element, int) next_tiles = boardoutput["next"] # and one array of integers denoting the possible next tiles. for number in next_tiles: self.assertIsInstance(number, int) def test_initialized_board_has_three_of_each_starting_tile(self): # I start the game and initialize the board. self.board.board_init() boardoutput = self.board.read_board() ones = twos = threes = zeros = 0 for row in boardoutput["tiles"]: ones += row.count(1) twos += row.count(2) threes += row.count(3) zeros += row.count(0) # There are three 1s, three 2s, and three 3s to start, and thus 7 # zeros remaining. self.assertEqual(ones, 3) self.assertEqual(twos, 3) self.assertEqual(threes, 3) self.assertEqual(zeros, 7) def test_create_tile_with_default_value(self): # I create a tile object with default value of 0 self.test_tile = Tile() self.assertEqual(self.test_tile.value, 0) def test_create_tile_with_nondefault_value(self): # I create a tile object with value 3 instead of the default 0 self.test_tile = Tile(3) self.assertEqual(self.test_tile.value, 3) def test_tile_combinations_work(self): # Given different combos of tiles, they combine properly. self.tile1 = Tile(0) self.tile2 = Tile(0) # Two empty tiles can combine. self.assertTrue(can_combine(self.tile1, self.tile2)) self.tile1 = Tile(1) self.tile2 = Tile(2) # 1s and 2s can combine. self.assertTrue(can_combine(self.tile1, self.tile2)) self.tile1 = Tile(2) self.tile2 = Tile(1) # 1s and 2s can combine, regardless of order. self.assertTrue(can_combine(self.tile1, self.tile2)) self.tile1 = Tile(3) self.tile2 = Tile(3) # Twins can combine. self.assertTrue(can_combine(self.tile1, self.tile2)) self.tile1 = Tile(1) self.tile2 = Tile(3) # 1 and 3 cannot combine. self.assertFalse(can_combine(self.tile1, self.tile2)) def test_swipe_up_one_tile_not_on_edge(self): # With the board initialized, I press up on the board, and the tiles # all move correctly. # Start with just one 1 tile in the middle, see if it moves properly. self.board.tiles = [[Tile(0), Tile(0), Tile(0), Tile(0)], [Tile(0), Tile(0), Tile(0), Tile(0)], [Tile(0), Tile(1), Tile(0), Tile(0)], [Tile(0), Tile(0), Tile(0), Tile(0)]] self.expectedboard = Board() self.expectedboard.tiles = [[Tile(0), Tile(0), Tile(0), Tile(0)], [Tile(0), Tile(1), Tile(0), Tile(0)], [Tile(0), Tile(0), Tile(0), Tile(0)], [Tile(0), Tile(0), Tile(0), Tile(0)]] self.board.swipe("up", add_new_tile=False) # Check if the 1 tile moved up properly. self.assertTrue(boards_match(self.board, self.expectedboard)) def test_swipe_up_one_tile_on_edge(self): # With the board initialized, I swipe up on the board, and the tiles # all move correctly. # Start with just one 1 tile on the top wall, see if it moves properly. self.board.tiles = [[Tile(0), Tile(1), Tile(0), Tile(0)], [Tile(0), Tile(0), Tile(0), Tile(0)], [Tile(0), Tile(0), Tile(0), Tile(0)], [Tile(0), Tile(0), Tile(0), Tile(0)]] self.expectedboard = Board() self.expectedboard.tiles = [[Tile(0), Tile(1), Tile(0), Tile(0)], [Tile(0), Tile(0), Tile(0), Tile(0)], [Tile(0), Tile(0), Tile(0), Tile(0)], [Tile(0), Tile(0), Tile(0), Tile(0)]] self.board.swipe("up", add_new_tile=False) # Check if the 1 tile moved up properly. # for index, board_row in enumerate(self.board.tiles): # self.assertEqual([tile.value for tile in board_row], [ # tile.value for tile in self.expectedboard.tiles[index]]) self.assertTrue(boards_match(self.board, self.expectedboard)) def test_swipe_up_initialized_board(self): self.board.board_init(test=True) self.expectedboard = Board() self.expectedboard.tiles = [[Tile(1), Tile(0), Tile(2), Tile(6)], [Tile(3), Tile(2), Tile(1), Tile(0)], [Tile(2), Tile(1), Tile(0), Tile(0)], [Tile(0), Tile(0), Tile(0), Tile(0)]] self.board.swipe("up", add_new_tile=False) self.assertTrue(boards_match(self.board, self.expectedboard)) def test_swipe_down_one_tile_not_on_edge(self): # With the board initialized, I press up on the board, and the tiles # all move correctly. # Start with just one 1 tile in the middle, see if it moves properly. self.board.tiles = [[Tile(0), Tile(0), Tile(0), Tile(0)], [Tile(0), Tile(0), Tile(0), Tile(0)], [Tile(0), Tile(1), Tile(0), Tile(0)], [Tile(0), Tile(0), Tile(0), Tile(0)]] self.expectedboard = Board() self.expectedboard.tiles = [[Tile(0), Tile(0), Tile(0), Tile(0)], [Tile(0), Tile(0), Tile(0), Tile(0)], [Tile(0), Tile(0), Tile(0), Tile(0)], [Tile(0), Tile(1), Tile(0), Tile(0)]] self.board.swipe("down", add_new_tile=False) # Check if the 1 tile moved up properly. self.assertTrue(boards_match(self.board, self.expectedboard)) def test_swipe_down_one_tile_on_edge(self): # With the board initialized, I swipe up on the board, and the tiles # all move correctly. # Start with just one 1 tile on the top wall, see if it moves properly. self.board.tiles = [[Tile(0), Tile(0), Tile(0), Tile(0)], [Tile(0), Tile(0), Tile(0), Tile(0)], [Tile(0), Tile(0), Tile(0), Tile(0)], [Tile(0), Tile(1), Tile(0), Tile(0)]] self.expectedboard = Board() self.expectedboard.tiles = [[Tile(0), Tile(0), Tile(0), Tile(0)], [Tile(0), Tile(0), Tile(0), Tile(0)], [Tile(0), Tile(0), Tile(0), Tile(0)], [Tile(0), Tile(1), Tile(0), Tile(0)]] self.board.swipe("down", add_new_tile=False) # Check if the 1 tile moved up properly. self.assertTrue(boards_match(self.board, self.expectedboard)) def test_swipe_down_initialized_board(self): self.board.board_init(test=True) self.expectedboard = Board() self.expectedboard.tiles = [[Tile(0), Tile(0), Tile(0), Tile(0)], [Tile(1), Tile(0), Tile(0), Tile(3)], [Tile(3), Tile(0), Tile(2), Tile(3)], [Tile(2), Tile(3), Tile(1), Tile(0)]] self.board.swipe("down", add_new_tile=False) self.assertTrue(boards_match(self.board, self.expectedboard)) def test_swipe_left_one_tile_not_on_edge(self): # With the board initialized, I press up on the board, and the tiles # all move correctly. # Start with just one 1 tile in the middle, see if it moves properly. self.board.tiles = [[Tile(0), Tile(0), Tile(0), Tile(0)], [Tile(0), Tile(0), Tile(0), Tile(0)], [Tile(0), Tile(1), Tile(0), Tile(0)], [Tile(0), Tile(0), Tile(0), Tile(0)]] self.expectedboard = Board() self.expectedboard.tiles = [[Tile(0), Tile(0), Tile(0), Tile(0)], [Tile(0), Tile(0), Tile(0), Tile(0)], [Tile(1), Tile(0), Tile(0), Tile(0)], [Tile(0), Tile(0), Tile(0), Tile(0)]] self.board.swipe("left", add_new_tile=False) # Check if the 1 tile moved up properly. self.assertTrue(boards_match(self.board, self.expectedboard)) def test_swipe_left_one_tile_on_edge(self): # With the board initialized, I swipe up on the board, and the tiles # all move correctly. # Start with just one 1 tile on the top wall, see if it moves properly. self.board.tiles = [[Tile(0), Tile(0), Tile(0), Tile(0)], [Tile(0), Tile(0), Tile(0), Tile(0)], [Tile(1), Tile(0), Tile(0), Tile(0)], [Tile(0), Tile(0), Tile(0), Tile(0)]] self.expectedboard = Board() self.expectedboard.tiles = [[Tile(0), Tile(0), Tile(0), Tile(0)], [Tile(0), Tile(0), Tile(0), Tile(0)], [Tile(1), Tile(0), Tile(0), Tile(0)], [Tile(0), Tile(0), Tile(0), Tile(0)]] self.board.swipe("left", add_new_tile=False) # Check if the 1 tile moved up properly. self.assertTrue(boards_match(self.board, self.expectedboard)) def test_swipe_left_initialized_board(self): self.board.board_init(test=True) self.expectedboard = Board() self.expectedboard.tiles = [[Tile(0), Tile(0), Tile(3), Tile(0)], [Tile(1), Tile(2), Tile(3), Tile(0)], [Tile(3), Tile(3), Tile(0), Tile(0)], [Tile(3), Tile(0), Tile(0), Tile(0)]] self.board.swipe("left", add_new_tile=False) self.assertTrue(boards_match(self.board, self.expectedboard)) def test_swipe_right_one_tile_not_on_edge(self): # With the board initialized, I press up on the board, and the tiles # all move correctly. # Start with just one 1 tile in the middle, see if it moves properly. self.board.tiles = [[Tile(0), Tile(0), Tile(0), Tile(0)], [Tile(0), Tile(0), Tile(0), Tile(0)], [Tile(0), Tile(1), Tile(0), Tile(0)], [Tile(0), Tile(0), Tile(0), Tile(0)]] self.expectedboard = Board() self.expectedboard.tiles = [[Tile(0), Tile(0), Tile(0), Tile(0)], [Tile(0), Tile(0), Tile(0), Tile(0)], [Tile(0), Tile(0), Tile(1), Tile(0)], [Tile(0), Tile(0), Tile(0), Tile(0)]] self.board.swipe("right", add_new_tile=False) # Check if the 1 tile moved up properly. self.assertTrue(boards_match(self.board, self.expectedboard)) def test_swipe_right_one_tile_on_edge(self): # With the board initialized, I swipe up on the board, and the tiles # all move correctly. # Start with just one 1 tile on the top wall, see if it moves properly. self.board.tiles = [[Tile(0), Tile(0), Tile(0), Tile(0)], [Tile(0), Tile(0), Tile(0), Tile(0)], [Tile(0), Tile(0), Tile(0), Tile(1)], [Tile(0), Tile(0), Tile(0), Tile(0)]] self.expectedboard = Board() self.expectedboard.tiles = [[Tile(0), Tile(0), Tile(0), Tile(0)], [Tile(0), Tile(0), Tile(0), Tile(0)], [Tile(0), Tile(0), Tile(0), Tile(1)], [Tile(0), Tile(0), Tile(0), Tile(0)]] self.board.swipe("right", add_new_tile=False) # Check if the 1 tile moved up properly. self.assertTrue(boards_match(self.board, self.expectedboard)) def test_swipe_right_initialized_board(self): self.board.board_init(test=True) self.expectedboard = Board() self.expectedboard.tiles = [[Tile(0), Tile(0), Tile(0), Tile(3)], [Tile(0), Tile(1), Tile(2), Tile(3)], [Tile(0), Tile(3), Tile(2), Tile(1)], [Tile(0), Tile(2), Tile(1), Tile(0)]] self.board.swipe("right", add_new_tile=False) self.assertTrue(boards_match(self.board, self.expectedboard)) def test_board_knows_max_tile_value_after_swipe(self): # I swipe a direction on the board, and the board's # max_tile_value is updated. self.board.board_init(test=True) # this should be 3 oldmaxvalue = self.board.max_tile_value self.assertEqual(oldmaxvalue, 3) self.board.swipe("up") newmaxvalue = self.board.max_tile_value self.assertEqual(newmaxvalue, 6) def test_board_next_tiles_varies_by_max_tile(self): self.board.board_init() self.board.tiles = [[Tile(3), Tile(2), Tile(3), Tile(12)], [Tile(768), Tile(768), Tile(12), Tile(48)], [Tile(12), Tile(6), Tile(96), Tile(48)], [Tile(3), Tile(24), Tile(1), Tile(3)]] self.board.set_max_tile_value() self.board.possible_new_tiles = get_possible_tiles( self.board.max_tile_value) self.assertEqual(self.board.possible_new_tiles, [1, 2, 3, [96, 48, 24]]) self.board.swipe("left") self.assertEqual(self.board.possible_new_tiles, [1, 2, 3, [192, 96, 48]]) def test_swipe_down_adds_new_tile(self): # With the board initialized, I swipe on the board, and a new tile # is added properly at the opposite edge # Start with all zeroes. self.board.tiles = [[Tile(0), Tile(0), Tile(0), Tile(0)], [Tile(0), Tile(1), Tile(0), Tile(0)], [Tile(0), Tile(0), Tile(0), Tile(0)], [Tile(0), Tile(0), Tile(0), Tile(0)]] self.board.swipe("down") non_zero = [] for tile in self.board.tiles[0]: if tile.value != 0: non_zero.append(tile.value)3 # Check if a new tile has been generated. self.assertTrue(len(non_zero) > 0) def test_swipe_down_with_illegal_move_doesnt_add_new_tile(self): # Swiping down in an illegal move, a new tile # is NOT added at the opposite edge # Start with a full column self.board.tiles = [[Tile(0), Tile(0), Tile(0), Tile(99)], [Tile(0), Tile(0), Tile(0), Tile(98)], [Tile(0), Tile(0), Tile(0), Tile(97)], [Tile(0), Tile(0), Tile(0), Tile(96)]] self.board.swipe("down") non_zero = [] for tile in self.board.tiles[0]: if tile.value != 0: non_zero.append(tile.value) # Check if a new tile has been generated. self.assertTrue(len(non_zero) == 1 and non_zero[0] == 99) def test_swipe_down_adds_new_tile_in_correct_spot(self): # With the board initialized, I swipe on the board, and a new tile # is initilalized properly at the opposite edge in the only open slot # Start with all zeroes. self.board.tiles = [[Tile(0), Tile(1), Tile(1), Tile(1)], [Tile(2), Tile(1), Tile(1), Tile(1)], [Tile(1), Tile(1), Tile(1), Tile(1)], [Tile(1), Tile(1), Tile(1), Tile(1)]] self.board.swipe("down") non_zero = [] for tile in self.board.tiles[0]: if tile.value != 0: non_zero.append(tile.value) # Check if a new tile has been generated. self.assertTrue(len(non_zero) == 4) def test_game_score_is_accurate(self): self.board.tiles = [[Tile(2), Tile(6), Tile(12), Tile(2)], [Tile(3), Tile(48), Tile(24), Tile(6)], [Tile(48), Tile(24), Tile(384), Tile(768)], [Tile(1), Tile(3), Tile(1), Tile(24)]] self.assertEqual(self.board.read_board()["points"], 27024) self.board.tiles = [[Tile(3), Tile(2), Tile(3), Tile(12)], [Tile(1536), Tile(12), Tile(48), Tile(24)], [Tile(12), Tile(6), Tile(96), Tile(48)], [Tile(3), Tile(24), Tile(1), Tile(3)]] self.assertEqual(self.board.read_board()["points"], 60528)