Пример #1
0
    def perform_simulation(self, state):
        '''
        Performs the simulation until legal moves are available.
        If simulation ends by finding a solution, a root state starting from this simulation is returned
        '''

        solution_tiles_order = []
        depth = 0
        simulation_root_state = state  # in case simulation ends in solution; these states are the solution
        if len(state.tiles) == 0:
            print('perform_simulation called with empty tiles')
            return ALL_TILES_USED, simulation_root_state, solution_tiles_order
        val = self.val
        while True:
            val += 1
            if len(state.tiles) == 0:
                print('solution found in simulation')
                return ALL_TILES_USED, simulation_root_state, solution_tiles_order
            valid_moves = SolutionChecker.get_valid_next_moves(state, state.tiles, val=val, colorful_states=self.colorful_states)
            if not valid_moves:
                return depth, simulation_root_state, solution_tiles_order

            next_random_tile_index = random.randint(0, len(valid_moves) -1)
            success, new_board = SolutionChecker.get_next_turn(
                state, valid_moves[next_random_tile_index], val, destroy_state=True, 
                colorful_states=self.colorful_states
            )
            self.n_tiles_placed += 1
            solution_tiles_order.append(valid_moves[next_random_tile_index])

            if success == ALL_TILES_USED:
                print('grid is full')
                # no LFB on grid; probably means grid is full
                solution_tiles_order.append(valid_moves[next_random_tile_index])
                return ALL_TILES_USED, simulation_root_state, solution_tiles_order
            elif success == NO_NEXT_POSITION_TILES_UNUSED:
                print('no next position with unused tiles')
                return depth, simulation_root_state, solution_tiles_order
            elif success == TILE_CANNOT_BE_PLACED:
                # cannot place the tile. return depth reached
                return depth, simulation_root_state, solution_tiles_order
            else:
                new_tiles = SolutionChecker.eliminate_pair_tiles(state.tiles, valid_moves[next_random_tile_index])
                new_state = State(board=new_board, tiles=new_tiles, parent=state)

                new_state.score = -1  #  because no choice is performed for sequent actions
                state.children.append(new_state)
                state = new_state
            depth += 1
        return depth, simulation_root_state, solution_tiles_order
Пример #2
0
def play_using_prediction(nnet,
                          width,
                          height,
                          tiles,
                          grid,
                          n_tiles,
                          dg,
                          predict_move_index=False,
                          verbose=False,
                          scalar_tiles=False):
    if scalar_tiles:
        tiles = tiles
    else:
        tiles = state_to_tiles_dims(tiles, dg)
    while True:
        tiles_left = len(tiles)
        if tiles_left == 0:
            print(
                f"Success: game ended with {tiles_left / ORIENTATIONS} tiles left unplaced."
            )
            return 0

        _tiles_ints = SolutionChecker.get_possible_tile_actions_given_grid(
            grid, tiles)
        if len(_tiles_ints) == 0 and tiles_left:
            print(
                f"game ended with {tiles_left / ORIENTATIONS} tiles left unplaced."
            )
            return tiles_left / ORIENTATIONS
        np.random.shuffle(_tiles_ints)
        if scalar_tiles:
            _tiles = tiles_to_np_array(
                SolutionChecker.pad_tiles_with_zero_scalars(
                    _tiles_ints, ORIENTATIONS * n_tiles - len(_tiles_ints)))
            # state = state.squeeze()

            prediction = nnet.predict([grid, tiles_to_np_array(_tiles)])
        else:
            tiles_in_matrix_shape = dg._transform_instance_to_matrix(
                _tiles_ints, only_one_orientation=True)
            tiles_in_matrix_shape = pad_tiles_with_zero_matrices(
                tiles_in_matrix_shape,
                n_tiles * ORIENTATIONS - tiles_in_matrix_shape.shape[2], width,
                height)

            state = np.dstack((np.expand_dims(grid,
                                              axis=2), tiles_in_matrix_shape))
            prediction = nnet.predict(state)

        if not predict_move_index:
            if len(prediction) == 2:  # if we are also predicting v
                prediction, v = prediction

            prediction = np.reshape(prediction, (width, height))

            # get the  probability matrix
            prediction = get_prediction_masked(prediction, state[:, :, 0])

        if verbose:
            print('-' * 50)
            print(grid, prediction)
            print(tiles)
        if scalar_tiles:
            _ttiles = tiles
        else:
            _ttiles = state_to_tiles_dims(state, dg)
        solution_tile = get_best_tile_by_prediction(
            grid,
            _ttiles,
            prediction,
            dg,
            predict_move_index=predict_move_index)
        if verbose:
            print(solution_tile)
        if solution_tile is None:
            print(
                f"game ended with {tiles_left / ORIENTATIONS} tiles left unplaced."
            )
            return tiles_left / ORIENTATIONS

        success, grid = SolutionChecker.place_element_on_grid_given_grid(
            solution_tile[0],
            solution_tile[1],
            val=1,
            grid=grid,
            cols=width,
            rows=height)

        if not success:
            print(
                f"game ended with {tiles_left / ORIENTATIONS} tiles left unplaced."
            )
            return tiles_left / ORIENTATIONS

        if scalar_tiles:
            tiles = [tuple(x) for x in tiles]
        tiles = SolutionChecker.eliminate_pair_tiles(tiles, solution_tile[0])
    return 0
Пример #3
0
    def predict(self, temp=1, N=3000):
        initial_state = self.state
        state = self.state
        available_tiles = state.tiles
        prev_state = state
        solution_found = False

        depth = 0
        self.val = 1
        while len(state.tiles):
            tile_placed = False
            states = []
            print(len(state.tiles))
            best_score = 0
            for i, tile in enumerate(state.tiles):
                success, new_board = SolutionChecker.get_next_turn(state, tile, self.val, destroy_state=False)
                self.n_tiles_placed += 1

                if success == ALL_TILES_USED:
                    print('solution found!')
                    solution_found = True
                    return initial_state, depth, solution_found
                if success == TILE_CANNOT_BE_PLACED:
                    # cannot place the tile.  this branch will not be considered
                    states.append(None)
                    continue
                else:
                    tile_placed = True
                    new_tiles = SolutionChecker.eliminate_pair_tiles(state.tiles, tile)
                    new_state = State(
                        board=new_board, tiles=new_tiles, parent=state)
                    state.children.append(new_state)
                    simulation_result, solution_tiles_order = self.perform_simulations(new_state, N=N, record_simulations=False)
                    if simulation_result == ALL_TILES_USED:
                        print('solution found in simulation!')
                        print(tile)
                        solution_found = True

                        # update scores of states found in simulation
                        new_state.score = len(state.tiles) / ORIENTATIONS - 1
                        _state = new_state.children[0]
                        while _state.children:
                            _state.score = (len(_state.tiles) / ORIENTATIONS) - 1
                            _state = _state.children[0]

                        if state.tile_placed:
                            self.solution_tiles_order.extend([state.tile_placed] + [tile] + solution_tiles_order)
                        else:
                            self.solution_tiles_order.extend([tile] + solution_tiles_order)
                        return initial_state, depth, solution_found
                    new_state.score = simulation_result
                    if new_state.score > best_score:
                        best_tile = tile
                        best_score = new_state.score
                    new_state.tile_placed = tile
                    state.solution_tiles_order.append(tile)
                    states.append(new_state)
            if not tile_placed:
                # no tile was placed, it's a dead end; end game
                return initial_state, depth, solution_found

            # PERFORMANCE:
            # for visualization this can be changed
            # all tiles will be 1 inside the frame for performance reasons
            self.val += 1

            depth += 1
            best_action = get_max_index(states) 
            prev_state = state
            new_state = states[best_action]
            print(best_tile, prev_state.tile_placed)
            if prev_state.tile_placed:
                self.solution_tiles_order.append(prev_state.tile_placed)


            state = new_state

        print('Solution found!')
        solution_found = True
        return initial_state, depth, solution_found
Пример #4
0
    def test_eliminate_pair_tiles_when_pair_is_not_present(self):
        tiles_list = [(1, 8), (2, 1), (1, 1), (1, 1), (2, 1), (1, 1)]

        with self.assertRaises(ValueError):
            SolutionChecker.eliminate_pair_tiles(tiles_list, tile_to_remove=(1, 8))
Пример #5
0
    def test_eliminate_pair_tiles_3(self):
        tiles_list = [(1, 1), (2, 1), (1, 1), (1, 1), (2, 1), (1, 1)]

        new_tiles = SolutionChecker.eliminate_pair_tiles(tiles_list, tile_to_remove=(1, 1))
        self.assertEqual(new_tiles, [(2, 1), (1, 1), (2, 1), (1, 1)])