← Back to Blog & Guides

🛠️ Dev Blog · 7 min read

How We Built Maze Kingdom’s Procedural Generation

Every labyrinth in Maze Kingdom is generated on the fly by a recursive backtracking algorithm, not hand-drawn. Here's how it works, and why we made it deterministic.

Maze Kingdom needed a way to produce a fresh labyrinth every time a player starts a run, without us hand-designing thousands of layouts. The answer is procedural generation: a small algorithm that builds a brand-new, guaranteed-solvable maze from a grid of cells in a fraction of a millisecond.

Recursive backtracking, cell by cell

Every maze starts as a grid where every cell has all four walls up — top, right, bottom, left. The generator picks a starting cell, marks it visited, and then repeatedly looks at its unvisited neighbors. If there's an unvisited neighbor, it knocks down the wall between the current cell and that neighbor, moves into it, and recurses from there. When a cell has no unvisited neighbors left, the algorithm backtracks to the previous cell and tries a different direction — the same way you'd explore a real maze by always retreating to your last junction when you hit a dead end.

This approach is called a recursive backtracker, and it has a property that makes it perfect for a puzzle game: because every cell gets visited exactly once and walls are only removed between a cell and its unvisited neighbor, the result is always a perfect maze — there's exactly one path between the entrance and any other point, with no loops and no isolated, unreachable pockets.

Why the randomness is seeded

The order in which the generator picks a direction at each junction comes from a pseudo-random number generator (PRNG) — but it's not JavaScript's built-in Math.random(). We use a small seeded generator (a linear congruential generator, or LCG) so that the exact same seed always produces the exact same maze.

That determinism is what makes the Daily Challenge fair. When everyone plays "today's maze," they need to be navigating the identical layout — same walls, same exit, same crystal positions — so that the leaderboard is actually comparing skill and not who got an easier random layout. Feed the generator today's date as a seed, and every player around the world gets the same maze back.

Tuning difficulty per world

The generation algorithm itself doesn't change between worlds — what changes is the configuration we feed it. Each of the four Maze Kingdom worlds is a different difficulty preset:

WorldGrid sizeFog radiusTime limit
Goblin Woods (Forest)9×9None — fully lit75s
Stone Castle13×133.5 cells110s
Lava Dungeon17×173 cells150s
Ice Palace21×212.8 cells220s

The grid grows from 9×9 to 21×21 as you move from Forest to Ice, so there are simply more cells and more decision points to navigate. Fog radius controls how many cells around the player are actually lit at once — Forest has no fog at all, while Ice Palace only reveals about 2.8 cells in every direction, so most of the maze around you is invisible until you walk into it. Both the maze size and the fog radius are the two levers we use to make each world feel meaningfully harder than the last, without changing the generation algorithm itself.

💡

Because generation is fast and deterministic, we can also regenerate a maze for testing by just changing the seed — which is how we catch edge cases like a generated maze where the exit ends up directly adjacent to the entrance, before it ever reaches a player.

Want to see the algorithm in action? Play Maze Kingdom and watch how differently the four worlds feel even though they're built by the exact same code.