def rat_in_fully_connected_grid() -> Rat: """Return a rat in a fully connected dungeon of 20 by 20 rooms""" start = Room("0,0", 1, 0, 0) d = Dungeon(start) for row in range(0, 20): for col in range(0, 20): if row > 0 or col > 0: d.add_room(Room(str(row) + "," + str(col), 1, col, row)) for row in range(0, 20): for col in range(0, 20): connect_neighbors(d, row, col) rat = Rat(d, start) return rat
def rat_in_three_room_dungeon() -> Rat: """Return a rat object ready to explore a dungeon with three rooms in a row.""" r0 = Room('start here', 1, 0, 1) d = Dungeon(r0) r1 = Room('one', 1, 0, 2) r2 = Room('two', 2, 0, 3) r0.add_neighbor(r1, Direction.NORTH) r1.add_neighbor(r2, Direction.NORTH) d.add_room(r1) d.add_room(r2) rat = Rat(d, r0) return rat
def _dfs_search(self, current: Room, target_location: Room, path: List[Room], table: set, max_depth: int) -> bool: """ Recursively searches rooms until it finds the target room. """ # Using a Python Set to check if a room # has already been visited. if current in table: return False else: table.add(current) # Echo visiting message if self._echo_rooms_searched: print("Visiting:", current.name) if current == target_location: # Base case path.append(current) return True elif max_depth < 0 or max_depth > 0: for neighbor in current.neighbors(): if self._dfs_search(neighbor, target_location, path, table, max_depth - 1): path.append(current) return True return False
def __recursive_id_search(self, target_location: Room, current_location: Room, visited: List[Room], max_depth: int, current_depth: int, is_searchable: bool): """ Recursive iterative deepening search of rooms, which searches all rooms in a dungeon, or stops searching once depth of search has reached its specified max search distance.""" self.__optional_echo(current_location) visited.append(current_location) current_depth += 1 if current_depth < max_depth: for neighbor in current_location.neighbors(): if neighbor is not None: if neighbor == target_location: self.__optional_echo(neighbor) visited.append(neighbor) return visited, is_searchable elif neighbor not in visited: visited, is_searchable = self.__recursive_id_search( target_location, neighbor, visited.copy(), max_depth, current_depth, is_searchable) current_depth += 1 if (visited is not None and visited[-1] == target_location): return visited, is_searchable elif visited is not None: visited.pop() current_depth -= 1 else: is_searchable = True return visited, is_searchable
def _astar_search(self, start_location: Room, target_location: Room) -> List[Room]: """ Breadth first search it finds the target room. """ queue = [] self._astar_visited_nodes = set() n = _astar_node(start_location, None) depth = 0 est_cost = start_location.estimated_cost_to(target_location) while n.room != target_location: if n.room.name not in self._astar_visited_nodes: self._astar_visited_nodes.add(n.room.name) if self._echo_rooms_searched: print("Visiting:", n.room.name) for i in range(len(n.room.neighbors())): neighbor = n.room.neighbors()[i] queue.append((_astar_node(neighbor, n), depth + 1, neighbor.estimated_cost_to(target_location))) queue = self._astar_sort(queue) if len(queue) > 0: n, depth, est_cost = queue.pop(0) else: return [] path = [] while n != None: path.append(n.room) n = n.previous return reversed(path)
def test_rat_8(debug: bool = False) -> str: """Test a rat traveling from 0,0 to 19,19. When debug is true, makes the rat echo rooms as they are searched. """ rat = rat_in_none_dungeon() if debug: rat.set_echo_rooms_searched() path = rat.directions_to(Room("Imaginary Room")) print(path) assert len(path) == 0 return str(path)
def test_rat_6(algorithm, debug: bool = False) -> str: """Test a rat traveling from center to a room with food in it. In this case, there's been a cave-in in stair1 and south2 now goes to a new room, forcing a path through downstairs. When debug is true, makes the rat echo rooms as they are searched. """ rat = rat_in_dungeon_x() south2 = rat.dungeon.find('south2') new_stairs = Room("hidden stairway", 3, 5, 3) rat.dungeon.add_room(new_stairs) south2.add_neighbor(new_stairs, Direction.UP) if debug: rat.set_echo_rooms_searched() goal = rat.dungeon.find("food") path = directions_for_rat(rat, algorithm, goal) expected_path = ['center', 'downstairs', 'west1', 'sw2', 'sw3', 'food'] check_paths_are_similar(rat.dungeon, path, expected_path) return str(path)
def __recursive_dfs_search(self, target_location: Room, current_location: Room, visited: List[Room]): """ Recursive depth first search of rooms, which searches all rooms in a dungeon. However, in order to be recursive it must always return something, as such, its sometimes returns a list of rooms that doesn't contain the target""" self.__optional_echo(current_location) visited.append(current_location) for neighbor in current_location.neighbors(): if neighbor is not None: if neighbor == target_location: self.__optional_echo(neighbor) visited.append(neighbor) return visited elif neighbor not in visited: visited = self.__recursive_dfs_search( target_location, neighbor, visited.copy()) if visited is not None and visited[-1] == target_location: return visited elif visited is not None: visited.pop() return visited
def rat_in_square_dungeon() -> Rat: """Return a rat object ready to explore a dungeon with 4 rooms in a square.""" top_left_room = Room('top left', 1, 1, 0) bottom_left_room = Room('bottom left', 1, 0, 0) top_right_room = Room('top right', 1, 1, 1) bottom_right_room = Room('bottom right', 1, 0, 1) d = Dungeon(top_left_room) d.add_room(bottom_left_room) d.add_room(top_right_room) d.add_room(bottom_right_room) top_left_room.add_neighbor(top_right_room, Direction.EAST) top_left_room.add_neighbor(bottom_left_room, Direction.SOUTH) bottom_right_room.add_neighbor(bottom_left_room, Direction.WEST) bottom_right_room.add_neighbor(top_right_room, Direction.NORTH) rat = Rat(d, top_left_room) return rat
def rat_in_dungeon_x() -> Rat: """Return a rat in a dungeon with several long paths and one loop.""" # The following pseudo-map describes the basic structure of the # dungeon, where rooms next to each other and dashed lines indicate # neighbors. # north2 # north1 # west1 downstairs center east1 # | south1 # sw2 south2 stair1 upstairs-east1 # sw3 -----------------------------> food # center = Room("center", 1, 5, 5) d = Dungeon(center) north1 = Room("north1", 1, 5, 6) north2 = Room("north2", 1, 5, 7) east1 = Room("east1", 1, 6, 5) down = Room("downstairs", 0, 5, 5) west1 = Room("west1", 0, 5, 4) sw2 = Room("sw2", 0, 4, 4) sw3 = Room("sw3", 0, 4, 3) south1 = Room("south1", 1, 5, 4) south2 = Room("south2", 1, 5, 3) stair1 = Room("stair1", 2, 5, 3) upstairs_east1 = Room("upstairs-east1", 2, 6, 3) food_room = Room("food", 1, 6, 2) d.add_room(north1) d.add_room(north2) d.add_room(east1) d.add_room(down) d.add_room(west1) d.add_room(sw2) d.add_room(sw3) d.add_room(south1) d.add_room(south2) d.add_room(stair1) d.add_room(upstairs_east1) d.add_room(food_room) center.add_neighbor(north1, Direction.NORTH) north1.add_neighbor(north2, Direction.NORTH) center.add_neighbor(down, Direction.DOWN) down.add_neighbor(west1, Direction.WEST) west1.add_neighbor(sw2, Direction.SOUTH) sw2.add_neighbor(sw3, Direction.SOUTH) sw3.add_neighbor(food_room, Direction.UP) center.add_neighbor(east1, Direction.EAST) center.add_neighbor(south1, Direction.SOUTH) south1.add_neighbor(south2, Direction.SOUTH) south2.add_neighbor(stair1, Direction.UP) stair1.add_neighbor(upstairs_east1, Direction.EAST) upstairs_east1.add_neighbor(food_room, Direction.DOWN) rat = Rat(d, center) return rat
def rat_in_looped_dungeon() -> Rat: """Return a rat object ready to explore a dungeon with 6 rooms where there are two paths from the start to the finish. """ r0 = Room('start', 0, 9, 9) d = Dungeon(r0) r1 = Room('one', 1, 9, 8) r2 = Room('two', 1, 9, 7) r3 = Room('three', 1, 9, 6) r4 = Room('four', 1, 9, 5) r5 = Room('five', 1, 9, 4) unconnected = Room('unconnected', 1, 8, 8) # r0 -> r1, r1 -> r2, r3; r2 -> r0, r3 -> r4, r4 -> r5 r0.add_neighbor(r1, Direction.DOWN) r1.add_neighbor(r2, Direction.NORTH) r1.add_neighbor(r3, Direction.SOUTH) r2.add_neighbor(r0, Direction.UP) r3.add_neighbor(r4, Direction.EAST) r4.add_neighbor(r5, Direction.SOUTH) d.add_room(r1) d.add_room(r2) d.add_room(r3) d.add_room(r4) d.add_room(r5) d.add_room(unconnected) rat = Rat(d, r0) return rat
def __to_list_item(self, specified_room: Room, target_location: Room, cost: int) -> Tuple[Room, Tuple[str, int, int]]: room_tuple = (specified_room, (specified_room.name, cost, specified_room.estimated_cost_to(target_location))) return room_tuple
def make_a_room(layouts, tilesets): layout = choice(list(layouts.items())) r = Room(layout_path=layout[1], tilesets=tilesets) r.layout_name = layout[0] return r
def rat_in_none_dungeon() -> Rat: """Returns a Rat object in a Dungeon that doesn't have anything more than a main room""" room_1 = Room('main room') d = Dungeon(room_1) rat = Rat(d, room_1) return rat