def test_get_next_turn_only_success(self): success, new_board, = SolutionChecker.get_next_turn( self.state, self.tile, val=1, get_only_success=True, destroy_state=True ) # assert board is destroyed i.e. equal to new_board self.assertIsNone(new_board)
def test_get_next_turn_destroy_board(self): success, new_board, = SolutionChecker.get_next_turn( self.state, self.tile, val=1, get_only_success=False, destroy_state=True ) self.assertEqual(success, True) # assert board is destroyed i.e. equal to new_board np.testing.assert_array_equal( self.state.board, new_board )
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
def test_get_next_turn(self): success, new_board, = SolutionChecker.get_next_turn( self.state, self.tile, val=1, get_only_success=False, destroy_state=False ) self.assertEqual(success, True) np.testing.assert_array_equal( new_board, np.array([ [1, 1, 1, 1], [1, 1, 1, 1], [0, 0, 0, 1] ]) ) # assert board is not destroyed np.testing.assert_array_equal( self.state.board, np.array([ [1, 1, 1, 1], [1, 1, 1, 0], [0, 0, 0, 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