Beispiel #1
0
    def get_next_turn(self, state, tile, val=1):
        new_board = np.copy(state.board)
        next_position = SolutionChecker.get_next_lfb_on_grid(new_board)
        # one without the other should not be possible
        if not next_position and len(state.tiles) == 0:
            print('solution found!')
            return ALL_TILES_USED, None
        elif not next_position:
            return NO_NEXT_POSITION_TILES_UNUSED, None

        success, new_board = SolutionChecker.place_element_on_grid_given_grid(
            tile, SolutionChecker.get_next_lfb_on_grid(new_board), val,
            new_board, get_cols(new_board), get_rows(new_board))

        if not success:
            # cannot place the tile. this branch will not be considered
            return TILE_CANNOT_BE_PLACED, None
        return True, new_board
Beispiel #2
0
def get_examples(given_examples,
                 n_tiles,
                 height,
                 width,
                 dg,
                 from_file=False,
                 return_binary_mask=False,
                 predict_v=False,
                 predict_move_index=True,
                 scalar_tiles=False,
                 shuffle_tiles_times=20):
    examples = []
    for i, _example in enumerate(given_examples):
        # print(f'{i}/{len(given_examples)}')
        if scalar_tiles:
            state, tiles, solution = _example
            state = state.squeeze()
        else:
            state, solution = _example
        grid = np.zeros([height, width])
        for solution_index, solution_tile in enumerate(solution):
            solution_copy = np.copy(solution)
            solution_order = np.array(solution_copy[solution_index:])
            solution_tile_dims = solution_tile[:2]
            orig_solution_order = solution_order

            for i in range(shuffle_tiles_times):  # tile permutations
                solution_order = np.copy(orig_solution_order)
                _tiles_ints = [x[:ORIENTATIONS] for x in solution_order]
                _tiles_ints = get_tiles_with_orientation(_tiles_ints)
                _tiles_ints = SolutionChecker.get_possible_tile_actions_given_grid(
                    grid, _tiles_ints)
                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)))
                else:
                    tiles = dg._transform_instance_to_matrix(
                        _tiles_ints, only_one_orientation=True)
                    tiles = pad_tiles_with_zero_matrices(
                        tiles, ORIENTATIONS * n_tiles - tiles.shape[2], width,
                        height)
                    state = np.dstack((np.expand_dims(grid, axis=2), tiles))
                pi = solution_to_solution_matrix(
                    solution_tile,
                    cols=width,
                    rows=height,
                    return_binary_mask=False).flatten()

                # v = N_TILES - solution_index
                v = 1
                if solution_index == len(solution) - 1:
                    continue

                if predict_move_index:
                    n_possible_tiles = SolutionChecker.get_n_nonplaced_tiles(
                        _tiles_ints)
                    if n_possible_tiles == 1:  # if only one action-tile placement is possible
                        pass
                    else:
                        _tiles_ints = SolutionChecker.np_array_to_tiles(
                            _tiles_ints)
                        solution_index = _tiles_ints.index(solution_tile_dims)
                        if scalar_tiles:
                            if INDIVIDUAL_TILES:
                                split_tiles = np.array(tiles)
                                split_tiles = np.split(split_tiles,
                                                       split_tiles.shape[0])
                            else:
                                split_tiles = tiles
                            example = [
                                grid.copy(), split_tiles,
                                one_hot_encode(_tiles_ints, solution_tile_dims,
                                               len(tiles))
                            ]
                        else:
                            example = [
                                state,
                                one_hot_encode(_tiles_ints, solution_tile_dims,
                                               state.shape[2] - 1)
                            ]
                        examples.append(example)
                        # print(_tiles_ints, solution_tile_dims, one_hot_encode(_tiles_ints, solution_tile_dims, state))
                else:
                    example = [state, pi]
                    if predict_v:
                        example.append(v)

                    examples.append(example)

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

    return examples
Beispiel #3
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
Beispiel #4
0
def get_best_tile_by_prediction(grid,
                                tiles,
                                prediction,
                                dg,
                                predict_move_index=True):
    '''
    1. mask invalid moves
    2. renormalize the probability distribution
    3. for each tile sum up which would be the probability of placing that tile in LFB
    4. return the new grid 

    Returns the tile which is the best in format [(rows, cols), position_to_place]
    '''
    next_lfb = SolutionChecker.get_next_lfb_on_grid(grid)
    max_probability = -math.inf
    max_index = 0
    best_tile = None
    rows, cols = grid.shape

    tile_probabilities = defaultdict(int)
    tile_counts = defaultdict(int)
    tiles_to_iterate_on = tiles

    SOFTMAX = False
    best_tile_individual = None
    best_prediction = 0

    for i, tile in enumerate(tiles_to_iterate_on):
        tile = tuple(tile)
        success, _ = SolutionChecker.place_element_on_grid_given_grid(
            tile,
            next_lfb,
            val=1,
            grid=grid,
            cols=cols,
            rows=rows,
            get_only_success=True)
        if not success:
            continue

        if predict_move_index and SOFTMAX:
            '''
            The best tile is predicted by taking the sum of the tiles
            with the same (width, height)
            '''
            if tuple(tile) == (0, 0):
                continue
            tile_probabilities[tile] += prediction[i]
            tile_counts[tile] += 1
        elif predict_move_index:
            if tuple(tile) == (0, 0):
                continue
            if prediction[i] > best_prediction:
                best_tile_individual = tile
                best_prediction = prediction[i]

            # if tile[0] * tile[1] > best_prediction:
            #     best_tile_individual = tile
            #     best_prediction = tile[0] * tile[1]
        else:
            probability = np.sum(prediction[next_lfb[0]:next_lfb[0] + tile[0],
                                            next_lfb[1]:next_lfb[1] + tile[1]])

            # scale with area
            # probability = probability / (tile[0] * tile[1])

            if probability > max_probability:
                max_index = i
                max_probability = probability
                best_tile = [tile, next_lfb]

    if predict_move_index and SOFTMAX:
        max_tile = None
        max_val = -math.inf
        for k in tile_probabilities.keys():
            v = tile_probabilities[k] / tile_counts[k]
            if True:
                if v > max_val:
                    max_tile = k
                    max_val = v
            else:
                if k[0] * k[1] > max_val:
                    max_tile = k
                    max_val = k[0] * k[1]
        if max_tile:
            best_tile = [max_tile, next_lfb]
    elif predict_move_index:
        best_tile = [best_tile_individual, next_lfb]

    # print(tile_probabilities)
    # print(tile_counts)
    if not best_tile:
        print('No valid tile placement found')
    return best_tile