Maze generation algorithm
From Wikipedia, the free encyclopedia
There are a number of different maze generation algorithms, that is, automated methods for the creation of mazes.
The maze shown on the right has been generated by the modified version of Prim's algorithm, below. For the source code for a Java applet that was responsible, click on the maze.
Contents |
[edit] Theory
A maze is basically a graph which presents a traversal challenge between two points. If the graph is not connected, then there are regions of the graph that are wasted because they do not contribute to the search space. If the graph contains loops, then there may be multiple paths between the chosen paths. Because of this, maze generation is often approached as generating a random spanning tree on a connected graph. Loops which can confound naive maze solvers may be introduced by adding random edges to the result during the course of the algorithm.
Common algorithms are based on search or minimal spanning tree algorithms for connected graphs, with edge weights chosen randomly. Because mazes are often approached from a different paradigm to traditional graph theory, different nomenclature is commonly used: graph edges not included in the resultant spanning tree are called "walls"; edges in the spanning tree are called "passages"; and vertices are typically called "cells" or "rooms". Although maze algorithms are often presented in the context of rectangular or hexagonal arrays, typically they perform equally well on any connected graph.
[edit] Depth-first search
This algorithm is a randomized version of the depth-first search algorithm.
- Start at a particular cell and call it the "exit."
- Mark the current cell as visited, and get a list of its neighbors. For each neighbor, starting with a randomly selected neighbor:
- If that neighbor hasn't been visited, remove the wall between this cell and that neighbor, and then recurse with that neighbor as the current cell.
If your computer architecture has a small stack and cannot effectively use recursion, you can store the backtracking information in the maze itself; this also provides a quick way to display a solution, by starting at any given point and backtracking to the exit.
Mazes generated with a depth-first search have a low branching factor and contain many long corridors, which makes depth-first a good algorithm for generating mazes in video games.
In mazes generated by that algorithm, it will typically be relatively easy to find the way to the square that was first picked at the beginning of the algorithm, since most paths lead to or from there, but hard to find the way out.
[edit] Randomized Kruskal's algorithm
This algorithm is simply a randomized version of Kruskal's algorithm.
- Create a list of all walls, and create a set for each cell, each containing just that one cell.
- For each wall, in some random order:
- If the cells divided by this wall belong to distinct sets:
- Remove the current wall.
- Join the sets of the formerly divided cells.
- If the cells divided by this wall belong to distinct sets:
There are several data structures that can be used to model the sets of cells. An efficient implementation using a disjoint-set data structure can perform each union and find operation on two sets in nearly-constant amortized time (specifically, O(α(V)) time; α(x) < 5 for any plausible value of x), so the running time of this algorithm is essentially proportional to the number of walls available to the maze.
It matters little whether the list of walls is initially randomized or if a wall is randomly chosen from a nonrandom list, either way is just as easy to code.
Because the effect of this algorithm is to produce a minimal spanning tree from a graph with equally-weighted edges, it tends to produce regular patterns which are fairly easy to solve.
[edit] Randomized Prim's algorithm
This algorithm is a randomized version of Prim's algorithm.
- Pick a cell, mark it as part of the maze. Add the walls of the cell to the wall list.
- While there are walls in the list:
- Pick a random wall from the list, and make it a passage.
- Mark the cell on the opposite side as part of the maze.
- Add the neighbouring walls of the cell to the wall list.
Like the depth-first algorithm, it will usually be relatively easy to find the way to the starting cell, but hard to find the way anywhere else.
Note that simply running classical Prim's on a graph with random weights would create mazes stylistically identical to Kruskal's, because they are both minimal spanning tree algorithms. Instead, this algorithm introduces stylistic variation because the edges closer to the starting point have a lower effective weight.
[edit] Recursive backtracker
- Mark the current cell as 'Visited'
- If the current cell has any neighbours which have not been visited
- Choose one of the unvisited neighbours
- Push the current cell on the stack
- Knock down the wall between the current cell and the chosen cell
- Make the chosen cell the current cell
- Recursively call this function
- else
- Pop the last current cell off the stack
- Backtrack to the previous execution of this function
[edit] Modified version
Although the classical Prim's algorithm keeps a list of edges, for maze generation we could instead maintain a list of adjacent cells. If the randomly chosen cell has multiple edges that connect it to the existing maze, select one of these edges at random. This will tend to branch slightly more than the edge-based version above.
[edit] Small-memory algorithm
Other algorithms exist that require only enough memory to store one line of a 2D maze or one plane of a 3D maze; they work by storing which cells in the current line are connected through cells in the previous lines. This algorithm never knocks down a wall between any two cells already connected.
[edit] Simple algorithms
Most maze generation algorithms require maintaining relationships between cells within it, to ensure the end result will be solvable. Valid simply connected mazes can however be generated by focusing on each cell independently. A binary tree maze is a standard orthogonal maze where each cell always has a passage leading up or leading left, but never both. To create a binary tree maze, for each cell flip a coin to decide whether to add a passage leading up or left. Always pick the same direction for cells on the boundary, and the end result will be a valid simply connected maze that looks like a binary tree, with the upper left corner its root.
A related form of flipping a coin for each cell is to create an image using a random mix of forward slash and backslash characters. This doesn't generate a valid simply connected maze, but rather a selection of closed loops and unicursal passages. The maze generator at edepot's algorithms, authored by Po-Han Lin in just 5 lines of code, implements this where the maze generated is tilted at an angle because of the slashes.
original chamber | division by two walls | holes in walls | continue subdividing... | completed |
---|---|---|---|---|
Another simple algorithm for rectangular mazes, recursive division, works as follows. Begin with a rectangular space with no walls. Call this a chamber. Build at random points two walls that are perpendicular to each other. These two walls divide the large chamber into four smaller chambers separated by four walls. Choose three of the four walls at random, and open a one cell-wide hole at a random point in each of the three. Continuing in this manner recursively, until every chamber has a width of one cell in either of the two directions, one can easily generate interesting mazes that avoid the ease of solution of binary tree mazes.
[edit] Non-cell-based algorithm
A maze can also be generated without the use of cells. In year 2000, a shareware called AmorphousMaze, appeared on the Internet that creates mazes with walls placed at totally random angles. Sample picture: [1] The algorithm is based on extending the wall by a small segment at a time without crossing over a pre-existing one. Algorithm detail: [2] The disadvantage of this algorithm is that the number of tests for intersection is O(E2), where E is the number of line segments being drawn.
[edit] External links
- Kruskal's and Prim's algorithms illustrated by a Java applet, Hilbert and Moore's mazes
- techniques and an excellent Java applet
- Think Labyrinth: Maze algorithms (details on these and other maze generation algorithms)
- Explanation of an Obfuscated C maze algorithm done in a single physical line of code.