Example #1
0
 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
Example #2
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))
Example #3
0
    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))
Example #4
0
    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))
Example #5
0
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
Example #6
0
 def setUp(self):
     self.board = Board()
Example #7
0
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)