def generate(width: int, height: int) -> GameMap: ROOMS = {'min_size': 7, 'max_size': 10, 'max': 30} gm = GameMap(width, height) gm.tiles[...] = WALL rooms: List[Room] = [] for _ in range(ROOMS['max']): w = randint(ROOMS['min_size'], ROOMS['max_size']) h = randint(ROOMS['min_size'], ROOMS['max_size']) x = randint(0, width - w - 1) y = randint(0, height - h - 1) new_room = Room(x, y, w, h) if any(new_room.intersects(other) for other in rooms): continue gm.tiles[new_room.inner] = FLOOR if rooms: other_room = rooms[-1] t_start = new_room.center t_end = other_room.center t_middle = t_start[0], t_end[1] gm.tiles[tcod.line_where(*t_start, *t_middle)] = FLOOR gm.tiles[tcod.line_where(*t_middle, *t_end)] = FLOOR rooms.append(new_room) for room in rooms: room.place_entities(gm) gm.player = spawn_entity(entities_db.player(), gm[rooms[0].center]) gm.entities.append(gm.player) gm.update_fov() return gm
def generate_dungeon_kruskals(map_width: int, map_height: int): dungeon = GameMap(map_width, map_height) import math maze_width = math.floor((map_width - 1) / 2) maze_height = math.floor((map_height - 1) / 2) edges = set() unlabeled_nodes = set() edge_directions = ( (1, 0), # east/right/l (0, 1), # south/down/j ) for x1 in range(maze_width): for y1 in range(maze_height): node1 = Node(x1, y1) unlabeled_nodes.add(node1) for dx, dy in edge_directions: x2 = x1 + dx y2 = y1 + dy node2 = Node(x2, y2) if x2 >= 0 and x2 < maze_width and y2 >= 0 and y2 < maze_height: edges.add(Edge(node1, node2)) # Sort the edges randomly. # Processing the edges in random order randomizes the maze. edge_list = list(edges) random.shuffle(edge_list) # We'll assign each node an integer label as we first encounter it labeled_nodes = defaultdict(set) # Now we iterate the randomly sorted edges maze_edges = [] for edge in edge_list: # If the labels for the nodes connected by the edge don't match, # we'll use the edge and merge the node labels. node1_label = None node2_label = None for label, nodes in labeled_nodes.items(): if edge.nodes[0] in nodes: node1_label = label if edge.nodes[1] in nodes: node2_label = label if node1_label and node2_label: break used_edge = False # both are none, new label including both if node1_label is None and node2_label is None: #print('a') maze_edges.append(edge) # When assigning a new label, use one greater than the current max or # zero if no labels have been assigned yet label = max(labeled_nodes) + 1 if labeled_nodes else 0 labeled_nodes[label] |= edge.nodeset used_edge = True elif node1_label is None: #print('b') maze_edges.append(edge) label = node2_label labeled_nodes[label] |= edge.nodeset used_edge = True elif node2_label is None: #print('c') maze_edges.append(edge) label = node1_label labeled_nodes[label] |= edge.nodeset used_edge = True elif node1_label != node2_label: #print('d') maze_edges.append(edge) label = node1_label labeled_nodes[label].update(labeled_nodes.pop(node2_label)) used_edge = True if used_edge: node1, node2 = edge.nodes #tile = str(label) #tile = ' ' #map_[2*node1.y + 1][2*node1.x + 1] = tile #map_[2*node2.y + 1][2*node2.x + 1] = tile dungeon.tiles[2 * node1.x + 1, 2 * node1.y + 1] = tile_types.floor dungeon.tiles[2 * node2.x + 1, 2 * node2.y + 1] = tile_types.floor if node1.x == node2.x: dungeon.tiles[2 * node1.x + 1][2 * node1.y + 2] = tile_types.floor elif node1.y == node2.y: dungeon.tiles[2 * node1.x + 2][2 * node1.y + 1] = tile_types.floor # Remove any nodes present in the unlabeled set since we've labeled them all unlabeled_nodes -= edge.nodeset assert not unlabeled_nodes assert len(labeled_nodes) == 1 assert len(maze_edges) < len(edges) walkable_positions = np.where(dungeon.tiles["walkable"]) # Put the player in the first open tile (top left) px, py = walkable_positions[0][0], walkable_positions[1][0] dungeon.player = entity_factories.player.spawn(dungeon, px, py) # Put the stairs in the last open tile (bottom right) sx, sy = walkable_positions[0][-1], walkable_positions[1][-1] dungeon.stairs = entity_factories.stairs.spawn(dungeon, sx, sy) # Spawn some initial entities for _ in range(10): # Choose a random walkable coordinate pair i = random.randint(0, walkable_positions[0].size - 1) ex, ey = walkable_positions[0][i], walkable_positions[1][i] # If not occupied, place an entitiy there if not any(e.x == ex and e.y == ey for e in dungeon.entities): if random.random() < 0.8: entity_factories.orc.spawn(dungeon, ex, ey) else: entity_factories.troll.spawn(dungeon, ex, ey) return dungeon