Algorithms · Graph Theory · Procedural Generation
📅 Квітень 2026 ⏱ ≈ 11 хв читання 🎯 Beginner–Intermediate

Maze Generation Algorithms — DFS, Prim's, Wilson's and More

A perfect maze (no loops, every cell reachable from every other) is exactly a spanning tree of a grid graph. The different maze generation algorithms are therefore different strategies for producing random spanning trees — and each strategy imprints a distinct visual "texture" on the resulting maze: long winding corridors (DFS), uniform branching (Prim's), or provably unbiased structure (Wilson's loop-erased random walk).

1. Mazes as Spanning Trees

Model a W×H grid as a graph where each cell is a vertex and adjacent cells share an edge. A perfect maze requires:

This is precisely a spanning tree — a connected, acyclic subgraph that visits every vertex. A W×H grid has W×H vertices and W(H−1) + H(W−1) = 2WH−W−H edges; a spanning tree uses exactly W×H − 1 edges. Each algorithm selects different edges to include, producing different spanning trees with different statistical properties.

Depth-first search produces mazes with long winding corridors and few dead ends — visually easy but computationally efficient to navigate. Breadth-first search spanning trees produce "fat" mazes with many short branches — harder for humans to solve. Wilson's algorithm produces unbiased random spanning trees, meaning every possible spanning tree is equally probable.

2. Recursive Backtracking (DFS)

The simplest and most popular maze algorithm. Start at a random cell, mark it visited, then repeatedly:

  1. Choose a random unvisited neighbour.
  2. Knock down the wall between the current cell and the chosen neighbour.
  3. Move to the chosen cell and repeat.
  4. If no unvisited neighbours, backtrack to the previous cell.
function generateDFS(grid, start) {
  const visited = new Set([start]);
  const stack = [start];
  while (stack.length) {
    const cell = stack[stack.length - 1];
    const unvisited = neighbours(cell).filter(n => !visited.has(n));
    if (unvisited.length === 0) { stack.pop(); continue; }
    const next = unvisited[randInt(0, unvisited.length)];
    removeWall(cell, next);
    visited.add(next);
    stack.push(next);
  }
}

Complexity: O(W×H). Character: Long, winding corridors with few junctions. Easy to solve by intuition following the main path. Memory usage: O(W×H) stack depth worst case.

3. Prim's Algorithm

Builds the spanning tree by always expanding the "cheapest" frontier edge. For random mazes, all edges have equal weight — so we pick uniformly at random from the current frontier:

  1. Start with one random cell in the maze set; add all its walls to the frontier list.
  2. Pick a random wall from the frontier. If the neighbour on the other side is not yet in the maze: remove the wall, add the neighbour to the maze, add its new walls to the frontier.
  3. Repeat until the frontier is empty.

Prim's produces mazes with uniform, tree-like branching. The maze spreads outward from the start like a growing crystal, with many short dead-end tentacles in all directions simultaneously — visually very different from DFS's long corridors.

4. Wilson's Loop-Erased Random Walk

Wilson's algorithm (1996) is the only simple algorithm that generates a uniformly random spanning tree — every possible perfect maze for the given grid is equally probable.

  1. Add one arbitrary cell to the maze set.
  2. Choose any unvisited cell as a starting walker.
  3. Perform a random walk until the walk hits any cell already in the maze.
  4. Erase all loops from the walk path (making it a simple path).
  5. Add the entire loop-erased path to the maze.
  6. Repeat from step 2 until all cells are in the maze.

The loop erasure step is critical: whenever the walk visits a cell it has visited before, erase everything since the previous visit to form a simple (non-self-crossing) path. This is the loop-erased random walk (LERW).

Expected complexity: O(N · t_cover) where t_cover is the expected cover time of a random walk on the grid On W×H grid: t_cover ≈ W²H²/π (for square grid: ~N²/π) Wilson's runs from near-linear for sparse mazes to O(N²) worst case. In practice: 2× slower than DFS for large grids, but produces unbiased structure with proper statistical properties.

5. Aldous-Broder

The simplest unbiased uniform spanning tree algorithm — but also the slowest:

  1. Start at a random cell. Mark it visited.
  2. Move to a random neighbour. If the neighbour has not been visited, remove the wall and mark it visited.
  3. Repeat until all cells are visited.

No loop erasure needed — any random walk eventually visits all cells by definition. The last edge leading to each newly-visited cell forms the spanning tree. Like Wilson's, this produces uniform random spanning trees, but it requires O(N log N) expected steps (the "coupon collector" problem) — typically 5–10× slower than DFS for large grids.

Use case: Aldous-Broder is used when statistical correctness is essential and performance is secondary — for example, generating benchmark maze datasets where algorithm bias must not affect results.

6. Kruskal's and Eller's

Kruskal's Algorithm

Assign random weights to all grid edges, then add edges in order of increasing weight while an edge connects two different components (using Union-Find). The result is a uniformly random spanning tree. Runtime O(E log E) = O(N log N) with efficient Union-Find implementation.

Eller's Algorithm

The unique row-by-row maze algorithm: generates mazes in O(W) memory regardless of height, making it the only algorithm suitable for generating arbitrarily tall mazes with very low memory:

7. Comparison and Bias

Algorithm Complexity Memory Bias Character ──────────────────────────────────────────────────────────────────── DFS Backtracking O(N) O(N) Long rivers Winding Prim's O(N log N) O(N) Near-start Branchy Kruskal's O(N log N) O(N) Uniform Balanced Aldous-Broder O(N log N) O(N) Unbiased Uniform Wilson's O(N·t_cover) O(N) Unbiased Uniform Eller's O(N) O(W) Slight vert. Practical Solving difficulty: Prim's > DFS > Kruskal/Wilson (for human solvers) Visual interest: DFS > Prim's > Kruskal/Wilson

The choice of algorithm is both aesthetic and mathematical. Game designers typically prefer DFS for satisfying playable mazes; researchers studying diffusion-limited aggregation or spatial models may need Wilson's unbiased trees. The maze simulation on this site lets you generate and compare all five families side-by-side.

🔍 Try the Maze Simulation →