04 — Rooms & Doors

Giving the space a structure

A connected floor plan is one big undivided cave. To feel like a dungeon it needs distinct rooms, doorways that always lead somewhere, and a sense that each room is for something. All of it comes from one idea: treat the floor as a graph.

Step 1 — Partition into rooms

Remember the floor seeds from the last chapter? Each is a nucleus. We run a multi-source breadth-first search outward from all nuclei at once: every floor cell joins whichever nucleus reaches it first. A single big blob is thus sliced into several rooms — like territories growing from capitals — instead of one shapeless cavern. Corridor cells stay separate and flood into their own regions.

Step 2 — A region adjacency graph

Now treat every region — room or corridor — as a node, with an edge between any two regions that share a border. This little graph is what every later decision reasons about: which rooms touch, how deep each is, where the doors go.

Step 3 — One door per pair

For each pair of adjacent regions we keep exactly one cell of their shared border as a door — the one nearest the middle of that border — and turn the rest of the border into solid dividing wall.

Two guarantees for free: every door joins two real regions, so there are never doors-to-nowhere; and since the floor was already connected, keeping one door per adjacency leaves it connected — and pleasantly cyclic, with loops rather than a single dead-ending path.

Step 4 — Name the rooms

Finally, give each room a type. BFS from the entrance (the room nearest the map edge) gives every room a depth; the deepest dead-end becomes the boss room. The rest are typed by shape and depth — long rooms become processional halls and libraries, big square ones become throne rooms or shrines — filtered to what the current depth theme allows.

Step through it, change the theme, and reshape with the seeds slider.

The dungeon is now a structured, named, fully connected place. All that’s missing is something living in it — Monster Behaviour.