|
|
(598 intermediate revisions by more than 100 users not shown) |
Line 1: |
Line 1: |
| {{refimprove|date=August 2012}}
| | This is a preview for the new '''MathML rendering mode''' (with SVG fallback), which is availble in production for registered users. |
| '''Maze generation [[algorithm]]s''' are automated methods for the creation of [[maze]]s. | |
|
| |
|
| [[Image:Prim Maze.svg|right|frame|This maze generated by modified version of [[Prim's algorithm]], below.]] | | If you would like use the '''MathML''' rendering mode, you need a wikipedia user account that can be registered here [[https://en.wikipedia.org/wiki/Special:UserLogin/signup]] |
| | * Only registered users will be able to execute this rendering mode. |
| | * Note: you need not enter a email address (nor any other private information). Please do not use a password that you use elsewhere. |
|
| |
|
| == Graph theory based methods ==
| | Registered users will be able to choose between the following three rendering modes: |
|
| |
|
| [[File:Graph_based_maze_animation.gif|thumb|Animation of Graph theory based method]]
| | '''MathML''' |
| | :<math forcemathmode="mathml">E=mc^2</math> |
|
| |
|
| A maze can be generated by starting with a predetermined arrangement of cells (most commonly a rectangular grid but other arrangements are possible) with wall sites between them. This predetermined arrangement can be considered as a [[connected graph]] with the edges representing possible wall sites and the nodes representing cells. The purpose of the maze generation algorithm can then be considered to be making a subgraph where it is challenging to find a route between two particular nodes.
| | <!--'''PNG''' (currently default in production) |
| | :<math forcemathmode="png">E=mc^2</math> |
|
| |
|
| If the subgraph is not [[connected graph|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 nodes. Because of this, maze generation is often approached as generating a random [[spanning tree (mathematics)|spanning tree]]. Loops which can confound naive maze solvers may be introduced by adding random edges to the result during the course of the algorithm.
| | '''source''' |
| | :<math forcemathmode="source">E=mc^2</math> --> |
|
| |
|
| The animation shows the maze generation steps for a
| | <span style="color: red">Follow this [https://en.wikipedia.org/wiki/Special:Preferences#mw-prefsection-rendering link] to change your Math rendering settings.</span> You can also add a [https://en.wikipedia.org/wiki/Special:Preferences#mw-prefsection-rendering-skin Custom CSS] to force the MathML/SVG rendering or select different font families. See [https://www.mediawiki.org/wiki/Extension:Math#CSS_for_the_MathML_with_SVG_fallback_mode these examples]. |
| graph that is not on a rectangular grid.
| |
| First, the computer creates a random [[planar graph]] G
| |
| shown in blue, and its [[Dual_graph|dual]] F
| |
| shown in yellow. Second, computer traverses F using a chosen
| |
| algorithm, such as a depth-first search, coloring the path red.
| |
| During the traversal, whenever a red edge crosses over a blue edge,
| |
| the blue edge is removed.
| |
| Finally, when all vertices of F have been visited, F is erased
| |
| and two edges from G, one for the entrance and one for the exit, are removed.<br />
| |
|
| |
|
| === Depth-first search === | | ==Demos== |
| [[File:Depth-First_Search_Animation.ogv|thumb|right|Animation of generator's thinking process using Depth-First Search]]
| |
|
| |
|
| This algorithm is a randomized version of the [[depth-first search]] algorithm. Frequently implemented with a stack, this approach is one of the simplest ways to generate a maze using a computer. Consider the space for a maze being a large grid of cells (like a large chess board), each cell starting with four walls. Starting from a random cell, the computer then selects a random neighbouring cell that has not yet been visited. The computer removes the 'wall' between the two cells and adds the new cell to a stack (this is analogous to drawing the line on the floor). The computer continues this process, with a cell that has no unvisited neighbours being considered a dead-end. When at a dead-end it backtracks through the path until it reaches a cell with an unvisited neighbour, continuing the path generation by visiting this new, unvisited cell (creating a new junction). This process continues until every cell has been visited, causing the computer to backtrack all the way back to the beginning cell. This approach guarantees that the maze space is completely visited.
| | Here are some [https://commons.wikimedia.org/w/index.php?title=Special:ListFiles/Frederic.wang demos]: |
|
| |
|
| As stated, the algorithm is very simple and does not produce over-complex mazes. More specific refinements to the algorithm can help to generate mazes that are harder to solve.
| |
|
| |
|
| # Start at a particular cell and call it the "exit."
| | * accessibility: |
| # Mark the current cell as visited, and get a list of its neighbors. For each neighbor, starting with a randomly selected neighbor:
| | ** Safari + VoiceOver: [https://commons.wikimedia.org/wiki/File:VoiceOver-Mac-Safari.ogv video only], [[File:Voiceover-mathml-example-1.wav|thumb|Voiceover-mathml-example-1]], [[File:Voiceover-mathml-example-2.wav|thumb|Voiceover-mathml-example-2]], [[File:Voiceover-mathml-example-3.wav|thumb|Voiceover-mathml-example-3]], [[File:Voiceover-mathml-example-4.wav|thumb|Voiceover-mathml-example-4]], [[File:Voiceover-mathml-example-5.wav|thumb|Voiceover-mathml-example-5]], [[File:Voiceover-mathml-example-6.wav|thumb|Voiceover-mathml-example-6]], [[File:Voiceover-mathml-example-7.wav|thumb|Voiceover-mathml-example-7]] |
| ## If that neighbor hasn't been visited, remove the wall between this cell and that neighbor, and then [[recursion|recur]] with that neighbor as the current cell.
| | ** [https://commons.wikimedia.org/wiki/File:MathPlayer-Audio-Windows7-InternetExplorer.ogg Internet Explorer + MathPlayer (audio)] |
| | ** [https://commons.wikimedia.org/wiki/File:MathPlayer-SynchronizedHighlighting-WIndows7-InternetExplorer.png Internet Explorer + MathPlayer (synchronized highlighting)] |
| | ** [https://commons.wikimedia.org/wiki/File:MathPlayer-Braille-Windows7-InternetExplorer.png Internet Explorer + MathPlayer (braille)] |
| | ** NVDA+MathPlayer: [[File:Nvda-mathml-example-1.wav|thumb|Nvda-mathml-example-1]], [[File:Nvda-mathml-example-2.wav|thumb|Nvda-mathml-example-2]], [[File:Nvda-mathml-example-3.wav|thumb|Nvda-mathml-example-3]], [[File:Nvda-mathml-example-4.wav|thumb|Nvda-mathml-example-4]], [[File:Nvda-mathml-example-5.wav|thumb|Nvda-mathml-example-5]], [[File:Nvda-mathml-example-6.wav|thumb|Nvda-mathml-example-6]], [[File:Nvda-mathml-example-7.wav|thumb|Nvda-mathml-example-7]]. |
| | ** Orca: There is ongoing work, but no support at all at the moment [[File:Orca-mathml-example-1.wav|thumb|Orca-mathml-example-1]], [[File:Orca-mathml-example-2.wav|thumb|Orca-mathml-example-2]], [[File:Orca-mathml-example-3.wav|thumb|Orca-mathml-example-3]], [[File:Orca-mathml-example-4.wav|thumb|Orca-mathml-example-4]], [[File:Orca-mathml-example-5.wav|thumb|Orca-mathml-example-5]], [[File:Orca-mathml-example-6.wav|thumb|Orca-mathml-example-6]], [[File:Orca-mathml-example-7.wav|thumb|Orca-mathml-example-7]]. |
| | ** From our testing, ChromeVox and JAWS are not able to read the formulas generated by the MathML mode. |
|
| |
|
| As given above this algorithm involves deep recursion which may cause stack overflow issues on some computer architectures. The algorithm can be rearranged into a loop by storing 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.
| | ==Test pages == |
|
| |
|
| [[File:Horizontally_Influenced_Depth-First_Search_Generated_Maze.png|thumb|right|Horizontal Influence]] | | To test the '''MathML''', '''PNG''', and '''source''' rendering modes, please go to one of the following test pages: |
| | *[[Displaystyle]] |
| | *[[MathAxisAlignment]] |
| | *[[Styling]] |
| | *[[Linebreaking]] |
| | *[[Unique Ids]] |
| | *[[Help:Formula]] |
|
| |
|
| Mazes generated with a depth-first search have a low branching factor and contain many long corridors, because the algorithm explores as far as possible along each branch before backtracking. Also mazes 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 it is hard to find the way out.{{Why|date=October 2014}}
| | *[[Inputtypes|Inputtypes (private Wikis only)]] |
| | | *[[Url2Image|Url2Image (private Wikis only)]] |
| To add difficulty and a fun factor to depth-first search generated mazes, you can influence the likelihood of which neighbor you should visit, instead of it being completely random. By making it more likely to visit neighbors to your sides, you can have a more horizontal maze generation. Experimenting with directional "influence" in certain places could lead to creating fun designs, such as a checkerboard pattern, an X, and more.
| | ==Bug reporting== |
| | | If you find any bugs, please report them at [https://bugzilla.wikimedia.org/enter_bug.cgi?product=MediaWiki%20extensions&component=Math&version=master&short_desc=Math-preview%20rendering%20problem Bugzilla], or write an email to math_bugs (at) ckurs (dot) de . |
| ==== Recursive backtracker ====
| |
| The depth-first search algorithm of maze generation is frequently implemented using [[backtracking]]:
| |
| | |
| # Make the initial cell the current cell and mark it as visited
| |
| # While there are unvisited cells
| |
| ## If the current cell has any neighbours which have not been visited
| |
| ### Choose randomly one of the unvisited neighbours
| |
| ### Push the current cell to the stack
| |
| ### Remove the wall between the current cell and the chosen cell
| |
| ### Make the chosen cell the current cell and mark it as visited
| |
| ## Else if stack is not empty
| |
| ### Pop a cell from the stack
| |
| ### Make it the current cell
| |
| ## Else
| |
| ### Pick a random unvisited cell, make it the current cell and mark it as visited
| |
| | |
| === Randomized Kruskal's algorithm ===
| |
| [[File:KruskalGeneratedMaze.webm|thumb|An animation of generating a 30 by 20 maze using Kruskal's algorithm.]] | |
| This algorithm is 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.
| |
| | |
| 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, <math>O(\alpha(V))</math> time; <math>\alpha(x) < 5</math> for any plausible value of <math>x</math>), 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.
| |
| | |
| === Randomized Prim's algorithm ===
| |
| [[File:MAZE 30x20 Prim.ogv|thumb|upright=1.6|An animation of generating a 30 by 20 maze using Prim's algorithm.]]
| |
| This algorithm is a randomized version of [[Prim's algorithm]].
| |
| | |
| # Start with a grid full of walls.
| |
| # 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. If the cell on the opposite side isn't in the maze yet:
| |
| ### Make the wall a passage and mark the cell on the opposite side as part of the maze.
| |
| ### Add the neighboring walls of the cell to the wall list.
| |
| ## Remove the wall from the 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.
| |
| | |
| ==== 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.
| |
| | |
| ==Recursive division method==
| |
| {| class="wikitable" align="right"
| |
| |+ '''Illustration of Recursive Division'''
| |
| |-
| |
| ! width="110px" | ''original chamber''
| |
| ! width="110px" | ''division by two walls''
| |
| ! width="110px" | ''holes in walls''
| |
| ! width="110px" | ''continue subdividing...''
| |
| ! width="110px" | ''completed''
| |
| |-
| |
| | align="center" | [[Image:Chamber.png|101px]]
| |
| | align="center" | [[Image:Chamber division.png|101px]]
| |
| | align="center" | [[Image:Chamber divided.png|101px]]
| |
| | align="center" | [[Image:Chamber subdivision.png|101px]]
| |
| | align="center" | [[Image:Chamber finished.png|101px]]
| |
| |}
| |
| | |
| Mazes can be created with ''recursive division'', an algorithm which works as follows: Begin with the maze's space with no walls. Call this a chamber. Divide the chamber with a randomly positioned wall (or multiple walls) where each wall contains a randomly positioned passage opening within it. Then recursively repeat the process on the subchambers until all chambers are minimum sized. This method results in mazes with long straight walls crossing their space, making it easier to see which areas to avoid.
| |
| | |
| For example, in a rectangular maze, 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. Continue in this manner recursively, until every chamber has a width of one cell in either of the two directions.
| |
| <br clear=all>
| |
| | |
| == Simple algorithms ==
| |
| [[File:Prim Maze 3D.svg|right|thumb|300px|3D version of Prim's algorithm. Vertical layers are labeled 1 through 4 from bottom to top. Stairs up are indicated with "/"; stairs down with "\", and stairs up-and-down with "x". Source code is included with the image description.]]
| |
| Other algorithms exist that require only enough memory to store one line of a 2D maze or one plane of a 3D maze. They prevent loops by storing which cells in the current line are connected through cells in the previous lines, and never remove walls between any two cells already connected.
| |
| | |
| 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 manual for the [[Commodore 64]] presents a BASIC program using this algorithm, but using [[PETSCII]] diagonal line graphic characters instead for a smoother graphic appearance.)
| |
| | |
| == Cellular automaton algorithms ==
| |
| Certain types of [[cellular automata]] can be used to generate mazes.<ref name=ca>{{cite web|url=http://www.conwaylife.com/wiki/index.php?title=Maze|title=Maze - LifeWiki |author=[http://www.conwaylife.com/wiki/index.php?title=User:Nathaniel Nathaniel Johnston] ''et al'' |date=21 August 2010 |publisher=LifeWiki |accessdate=1 March 2011}}</ref> Two well-known such cellular automata, Maze and Mazectric, have rulestrings B3/S12345 and B3/S1234.<ref name=ca /> In the former, this means that cells survive from one generation to the next if they have at least one and at most five [[Moore neighbourhood|neighbours]]. In the latter, this means that cells survive if they have one to four neighbours. If a cell has exactly three neighbours, it is born. It is similar to [[Conway's Game of Life]] in that patterns that do not have a living cell adjacent to 1, 4, or 5 other living cells in any generation will behave identically to it.<ref name=ca /> However, for large patterns, it behaves very differently.<ref name=ca />
| |
| | |
| For a random starting pattern, these maze-generating cellular automata will evolve into complex mazes with well-defined walls outlining corridors. Mazecetric, which has the rule B3/S1234 has a tendency to generate longer and straighter corridors compared with Maze, with the rule B3/S12345.<ref name=ca /> Since these cellular automaton rules are [[deterministic]], each maze generated is uniquely determined by its random starting pattern. This is a significant drawback since the mazes tend to be relatively predictable.
| |
| | |
| Like some of the graph-theory based methods described above, these cellular automata typically generate mazes from a single starting pattern; hence it will usually be relatively easy to find the way to the starting cell, but harder to find the way anywhere else.
| |
| | |
| ==Python code example{{clarify|reason=Which algorithm does this code implement??|date=October 2014}}==
| |
| <source lang="python">
| |
| import numpy
| |
| from numpy.random import random_integers as rand
| |
| import matplotlib.pyplot as pyplot
| |
| | |
| def maze(width=81, height=51, complexity=.75, density=.75):
| |
| # Only odd shapes
| |
| shape = ((height // 2) * 2 + 1, (width // 2) * 2 + 1)
| |
| # Adjust complexity and density relative to maze size
| |
| complexity = int(complexity * (5 * (shape[0] + shape[1])))
| |
| density = int(density * (shape[0] // 2 * shape[1] // 2))
| |
| # Build actual maze
| |
| Z = numpy.zeros(shape, dtype=bool)
| |
| # Fill borders
| |
| Z[0, :] = Z[-1, :] = 1
| |
| Z[:, 0] = Z[:, -1] = 1
| |
| # Make aisles
| |
| for i in range(density):
| |
| x, y = rand(0, shape[1] // 2) * 2, rand(0, shape[0] // 2) * 2
| |
| Z[y, x] = 1
| |
| for j in range(complexity):
| |
| neighbours = []
| |
| if x > 1: neighbours.append((y, x - 2))
| |
| if x < shape[1] - 2: neighbours.append((y, x + 2))
| |
| if y > 1: neighbours.append((y - 2, x))
| |
| if y < shape[0] - 2: neighbours.append((y + 2, x))
| |
| if len(neighbours):
| |
| y_,x_ = neighbours[rand(0, len(neighbours) - 1)]
| |
| if Z[y_, x_] == 0:
| |
| Z[y_, x_] = 1
| |
| Z[y_ + (y - y_) // 2, x_ + (x - x_) // 2] = 1
| |
| x, y = x_, y_
| |
| return Z
| |
| | |
| pyplot.figure(figsize=(10, 5))
| |
| pyplot.imshow(maze(80, 40), cmap=pyplot.cm.binary, interpolation='nearest')
| |
| pyplot.xticks([]), pyplot.yticks([])
| |
| pyplot.show()
| |
| </source>
| |
| | |
| ==See also==
| |
| * [[Maze solving algorithm]]
| |
| | |
| ==References==
| |
| {{reflist}}
| |
| | |
| ==External links==
| |
| * [http://www.jamisbuck.org/presentations/rubyconf2011/index.html Jamis Buck: HTML 5 Presentation with Demos of Maze generation Algorithms]
| |
| * [http://www.astrolog.org/labyrnth/algrithm.htm#perfect Think Labyrinth: Maze algorithms] (details on these and other maze generation algorithms)
| |
| * [http://www.martinfoltin.sk/mazes Maze Generation ] - Master's Thesis (Java Applet enabling users to have a maze created using various algorithms and human solving of mazes)
| |
| * [http://rosettacode.org/wiki/Maze Collection of maze generation code] in different languages in Rosetta Code
| |
| * [http://totologic.blogspot.com/2013/04/maze-generation-in-3d.html Maze generation and navigation in 3D]
| |
| * [http://totologic.blogspot.com/2014/09/triangulated-circular-maze-generation.html Triangulated circular maze generation] with Daedalus Lib
| |
| | |
| [[Category:Mazes]]
| |
| [[Category:Algorithms]]
| |
| [[Category:Random graphs]]
| |
| [[Category:Articles with example Python code]]
| |