A simple map generation algorithm

By Victor Hurdugaci on Nov 17, 2025

In Few Shall Return, every map you dive into is split into two distinct areas: the Outer Dungeon and the Inner Dungeon.

Players always start in the Outer Dungeon and the goal is to find a way to unlock the Inner Dungeon (in the current demo, that means tracking down three keys). Unlocking the inner dungeon also triggers the Exit Door to open. At that point, you have a major decision: do you extract right away, or do you push into the Inner Dungeon? It’s a real gamble because the Inner Dungeon has much better loot, but the enemies are far more punishing.

And here’s the kicker that makes it really intense: not everyone can escape. Roughly half of the players who start a map will actually be able to get out alive. This means you have to constantly watch what the other players are up to. If everyone else is making a frantic dash for the exit, you might want to follow their lead, or you could end up stuck inside forever.

Every map in the game is procedurally generated. This means we have an infinite number of dungeons to play in (well, technically 264 maps, but you get the idea!). The map generation algorithm we use today isn’t our first crack at it, and I doubt it will be the last. But I wanted to give you a quick peek under the hood at how it works right now.

The Map

We design every single room you’ll encounter on the map by hand. Then, the map generation algorithm’s job is to stitch all those rooms together to form a coherent map. We can’t just randomly toss rooms onto a canvas and hope for the best, though. The maps need to meet certain structural rules and limitations. For instance, we absolutely must have one, and only one, boss room every time.

So, the overall map has basic limits it must adhere to:

On top of that, each individual room type can define its own rules:

Our Initial Attempts

Our very first idea was pretty straightforward: place rooms randomly on the map and then connect them using corridors.

Unfortunately, connecting rooms with random, twisty corridors is incredibly difficult to pull off. The moment those corridors start crossing over each other, trying to enforce rules like “minimum distance from the start room” becomes a nightmare.

Plus, some of our rooms only have doors on specific walls. We’d end up with bizarre corridors wrapping around rooms unnecessarily just because there was no clean way to align a door.

We also gave Binary Space Partitioning (BSP) a shot, but we hit the same snag. If a room had multiple doors, the corridor connections often ended up looking strange and unwieldy. We didn’t want to limit our room designs to just one or two doors, and we definitely didn’t want to have to cut random holes in the walls, which wouldn’t work for certain room assets anyway.

The Current Approach

After several attempts, we found the best and most reliable results by building the dungeon from the ground up, starting with the initial spawn room and placing one room at a time, moving outwards.

We know exactly how many doors each room has and where they are located. So, instead of randomly placing a room and then trying to connect it with a winding corridor, we do this: we pick a room that is already on the map, look for one of its open (unconnected) doors, and then place the next room so that one of its doors perfectly touches the open door. We simply repeat this process until we either have no more open doors left (success!) or we can’t find a valid room to place (error). The illustration below shows this process for a successful map (the purple represents areas that will be filled with a random texture to create a bit of variety):

When deciding which room to place at an open door, the algorithm asks two simple questions:

  1. Does the room satisfy all of its constraints (like the distance from the start, or max instances)?
  2. Is there a valid rotation and position for the room to fit into the empty space without overlapping anything already placed, while also connecting its door to the open one?

If we find multiple rooms that satisfy both points, we just pick one at random.

The algorithm isn’t foolproof—it can definitely lead to invalid maps—but we can always tell it to start over. We’ve found that most of the time, we only need about 10-20 retries before a working map seed is found.

Current Limitations

Our current algorithm is admittedly pretty “dumb,” but it does the job well enough for us. If it gets stuck, it won’t try to backtrack or recover; it just gives up. You can see an example of it getting cornered here, placing a four-way corridor and then having no more space left to place rooms off of it:

Enforcing constraints like “this room must appear at least N times” is a particularly tricky problem. In the current setup, the algorithm might finish a map (no open doors left) but fail that specific constraint. So, before we call a map “good,” we do one final check to make sure all constraints across all rooms have been satisfied.

Conclusion

Finally, to give you an idea of the finished product, here is a video showing the previous successful map in the game (it’s sped up a bit so you can see more of the map):

And 3 successful maps all generated by only changing the seed. Notice how the size and complexity varies a lot with a single parameter change?

Map 1

Map 1

Map 1


This article is part of The Tales of a Small Indie Studio series. Click here to check out out the other articles.

Subscribe