def can_traverse(self, layer, previous_block_position, current_block_position, next_block_position): if not Level.is_position_within_layer_bounds(layer, next_block_position): return False push_direction = next_block_position - current_block_position push_from_position = current_block_position - push_direction current_player_position = self.get_current_player_position( previous_block_position) if not self.is_tile_empty(layer, push_from_position): return False if not self.is_tile_empty(layer, next_block_position): return False player_to_push_position_moves = self.can_player_reach_push_position( layer, push_from_position, current_block_position, current_player_position) if player_to_push_position_moves is None: return False else: if previous_block_position is not None: previous_block_position = tuple(previous_block_position) move_key = (previous_block_position, tuple(current_block_position), tuple(next_block_position)) player_to_push_position_moves.append(push_direction) self.player_moves[move_key] = player_to_push_position_moves return True
def can_traverse(layer, previous_position, current_position, next_position): if not Level.is_position_within_layer_bounds(layer, next_position): return False current_tile = layer[tuple(current_position)] next_tile = layer[tuple(next_position)] if next_tile == Tiles.wall: # We can never walk through walls return False if current_tile in [Tiles.finish, Tiles.required_collectable_barrier, Tiles.sokoban_block]: return False # We can't have the player go past a lock because we can't have the level change as we # are performing A* and if we go past a lock, then we have to change our key count and # that changes which locks we could open. # However, we can see if we end up on a lock to tell if it is reachable. for lock_tile in lock_tiles: if current_tile == lock_tile: return False # Similarly, we want to see if hazards are reachable without making them passable. # So we allow the player to traverse onto a hazard but not off of it. # The player can only traverse off of a hazard if they have the item to do so. for hazard_tile in hazard_tiles: if current_tile == hazard_tile and next_tile != hazard_tile: return False return True
def is_tile_empty(self, layer, next_block_position): if not Level.is_position_within_layer_bounds(layer, next_block_position): return False return layer[tuple(next_block_position)] in { Tiles.empty, Tiles.sokoban_goal, Tiles.player, Tiles.collectable, Tiles.fire_boots, Tiles.flippers, Tiles.key_blue, Tiles.key_green, Tiles.key_red, Tiles.key_yellow }
def spread_hazard(layer, hazard_tile, position, aesthetic_settings): offsets = [ np.array([-1, 0]), np.array([1, 0]), np.array([0, -1]), np.array([0, 1]) ] spread_probability = aesthetic_settings.hazard_spread_probability[ hazard_tile] hazard_tile_positions = [position] while len(hazard_tile_positions) > 0: hazard_tile_position = hazard_tile_positions.pop() layer[tuple(hazard_tile_position)] = hazard_tile for offset in offsets: if np.random.random() < spread_probability: neighbor_hazard_tile_position = tuple( hazard_tile_position + offset) if Level.is_position_within_layer_bounds( layer, neighbor_hazard_tile_position ) and layer[neighbor_hazard_tile_position] == Tiles.empty: hazard_tile_positions.append( neighbor_hazard_tile_position)