Example #1
0
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
Example #2
0
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