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
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
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
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