Perfect Maze Creation & Path Finding Algorithms
There are a number of ways of creating perfect Mazes, each with its own characteristics. Here’s a list of specific algorithms. All of these describe creating the Maze by carving passages, however unless otherwise specified each can also be done by adding walls:
- Recursive backtracker: This is somewhat related to the recursive backtracker solving method described below, and requires stack up to the size of the Maze. When carving, be as greedy as possible, and always carve into an unmade section if one is next to the current cell. Each time you move to a new cell, push the former cell on the stack. If there are no unmade cells next to the current position, pop the stack to the previous position. The Maze is done when you pop everything off the stack. This algorithm results in Mazes with about as high a “river” factor as possible, with fewer but longer dead ends, and usually a very long and twisty solution. It runs quite fast, although Prim’s algorithm is a bit faster. Recursive backtracking doesn’t work as a wall adder, because doing so tends to result in a solution path that follows the outside edge, where the entire interior of the Maze is attached to the boundary by a single stem.
- Prim’s algorithm: This requires storage proportional to the size of the Maze. During creation, each cell is one of three types: (1) “In”: The cell is part of the Maze and has been carved into already, (2) “Frontier”: The cell is not part of the Maze and has not been carved into yet, but is next to a cell that’s already “in”, and (3) “Out”: The cell is not part of the Maze yet, and none of its neighbors are “in” either. Start by picking a cell, making it “in”, and setting all its neighbors to “frontier”. Proceed by picking a “frontier” cell at random, and carving into it from one of its neighbor cells that are “in”. Change that “frontier” cell to “in”, and update any of its neighbors that are “out” to “frontier”. The Maze is done when there are no more “frontier” cells left (which means there are no more “out” cells left either, so they’re all “in”). This algorithm results in Mazes with a very low “river” factor, with many short dead ends, and the solution is usually pretty direct as well. It also runs very fast when implemented right, with only Eller’s algorithm being faster.
- Kruskal’s algorithm: This algorithm is interesting because it doesn’t “grow” the Maze like a tree, but rather carves passage segments all over the Maze at random, but yet still results in a perfect Maze in the end. It requires storage proportional to the size of the Maze, along with the ability to enumerate each edge or wall between cells in the Maze in random order (which usually means creating a list of all edges and shuffling it randomly). Label each cell with a unique id, then loop over all the edges in random order. For each edge, if the cells on either side of it have different id’s, then erase the wall, and set all the cells on one side to have the same id as those on the other. If the cells on either side of the wall already have the same id, then there already exists some path between those two cells, so the wall is left alone so as to not create a loop. This algorithm yields Mazes with a low “river” factor, but not as low as Prim’s algorithm. Merging the two sets on either side of the wall will be a slow operation if each cell just has a number and are merged by a loop. Merging as well as lookup can be done in near constant time by giving each cell a node in a tree structure, with the id at the root, where merging is done quickly by splicing the trees together. Done right, this algorithm runs reasonably fast, but not as fast as either of the above two, because of the edge list and set management.
- Aldous-Broder algorithm: The interesting thing about this algorithm is it generates all possible Mazes of a given size with equal probability. It also requires no extra storage or stack. Pick a point, and move to a neighboring cell at random. If an uncarved cell is entered, carve into it from the previous cell. Keep moving to neighboring cells until all cells have been carved into. This algorithm yields Mazes with a low “river” factor, only slightly higher than Kruskal’s algorithm. (This means for a given size there are more Mazes with a low “river” factor than high “river”, since an average equal probability Maze has low “river”.) The bad thing about this algorithm is that it’s very slow, since it doesn’t do any intelligent hunting for the last cells, where in fact it’s not even guaranteed to terminate. However since the algorithm is simple it can move over many cells quickly, so finishes faster than one might think. On average it takes about seven times longer to run than the above algorithms, although in bad cases it can take much longer if the random number generator keeps making it avoid the last few cells. This can be done as a wall adder if the boundary wall is treated as a single vertex, i.e. if a move goes to the boundary wall, teleport to a random point along the boundary before moving again. As a wall adder this runs nearly twice as fast, because the boundary wall teleportation allows quicker access to distant parts of the Maze.
- Wilson’s algorithm: This is an improved version of the Aldous-Broder algorithm, in that it produces Mazes exactly like that algorithm, with all possible Mazes generated with equal probability, except that Wilson’s algorithm runs much faster. It requires storage up to the size of the Maze. Begin by making a random starting cell part of the Maze. Proceed by picking a random cell not already part of the Maze, and doing a random walk until a cell is found which is already part of the Maze. Once the already created part of the Maze is hit, go back to the random cell that was picked, and carve along the path that was taken, adding those cells to the Maze. More specifically, when retracing the path, at each cell carve along the direction that the random walk most recently took when it left that cell. That avoids adding loops along the retraced path, resulting in a single long passage being appended to the Maze. The Maze is done when all cells have been appended to the Maze. This has similar performance issues as Aldous-Broder, where it may take a long time for the first random path to find the starting cell, however once a few paths are in place, the rest of the Maze gets carved quickly. On average this runs five times faster than Aldous-Broder, and takes less than twice as long as the top algorithms. Note this runs twice as fast when implemented as a wall adder, because the whole boundary wall starts as part of the Maze, so the first walls are connected much quicker.
- Hunt and kill algorithm: This algorithm is nice because it requires no extra storage or stack, and is therefore suited to creating the largest Mazes or Mazes on the most limited systems, since there are no issues of running out of memory. Since there are no rules that must be followed all the time, it’s also the easiest to modify and to get to create Mazes of different textures. It’s most similar to the recursive backtracker, except when there’s no unmade cell next to the current position, you enter “hunting” mode, and systematically scan over the Maze until an unmade cell is found next to an already carved into cell, at which point you start carving again at that new location. The Maze is done when all cells have been scanned over once in “hunt” mode. This algorithm tends to make Mazes with a high “river” factor, but not as high as the recursive backtracker. You can make this generate Mazes with a lower river factor by choosing to enter “hunt” mode more often. It runs slower due to the time spent hunting for the last cells, but isn’t much slower than Kruskal’s algorithm. This can be done as a wall adder if you randomly teleport on occasion, to avoid the issues the recursive backtracker has.
- Growing tree algorithm: This is a general algorithm, capable of creating Mazes of different textures. It requires storage up to the size of the Maze. Each time you carve a cell, add that cell to a list. Proceed by picking a cell from the list, and carving into an unmade cell next to it. If there are no unmade cells next to the current cell, remove the current cell from the list. The Maze is done when the list becomes empty. The interesting part that allows many possible textures is how you pick a cell from the list. For example, if you always pick the most recent cell added to it, this algorithm turns into the recursive backtracker. If you always pick cells at random, this will behave similarly but not exactly to Prim’s algorithm. If you always pick the oldest cells added to the list, this will create Mazes with about as low a “river” factor as possible, even lower than Prim’s algorithm. If you usually pick the most recent cell, but occasionally pick a random cell, the Maze will have a high “river” factor but a short direct solution. If you randomly pick among the most recent cells, the Maze will have a low “river” factor but a long windy solution.
- Eller’s algorithm: This algorithm is special because it’s not only faster than all the others that don’t have obvious biases or blemishes, but its creation is also the most memory efficient. It doesn’t even require the whole Maze to be in memory, only using storage proportional to the size of a row. It creates the Maze one row at a time, where once a row has been generated, the algorithm no longer looks at it. Each cell in a row is contained in a set, where two cells are in the same set if there’s a path between them through the part of the Maze that’s been made so far. This information allows passages to be carved in the current row without creating loops or isolations. This is actually quite similar to Kruskal’s algorithm, just this completes one row at a time, while Kruskal’s looks over the whole Maze. Creating a row consists of two parts: Randomly connecting adjacent cells within a row, i.e. carving horizontal passages, then randomly connecting cells between the current row and the next row, i.e. carving vertical passages. When carving horizontal passages, don’t connect cells already in the same set (as that would create a loop), and when carving vertical passages, you must connect a cell if it’s a set of size one (as abandoning it would create an isolation). When carving horizontal passages, when connecting cells union the sets they’re in (since there’s now a path between them), and when carving vertical passages, when not connecting a cell put it in a set by itself (since it’s now disconnected from the rest of the Maze). Creation starts with each cell in its own set before connecting cells within the first row, and creation ends after connecting cells within the last row, with a special final rule that every cell must be in the same set by the time we’re done to prevent isolations. (The last row is done by connecting each pair of adjacent cells if not already in the same set.) One issue with this algorithm is that it’s not balanced with respect to how it treats the different edges of the Maze, where connecting vs. not connecting cells need to be done in the right proportions to prevent texture blemishes.
- Recursive division: This algorithm is somewhat similar to recursive backtracking, since they’re both stack based, except this focuses on walls instead of passages. Start by making a random horizontal or vertical wall crossing the available area in a random row or column, with an opening randomly placed along it. Then recursively repeat the process on the two subareas generated by the dividing wall. For best results, give bias to choosing horizontal or vertical based on the proportions of the area, e.g. an area twice as wide as it is high should be divided by a vertical wall more often. This is the fastest algorithm without directional biases, although it has the obvious blemish of long walls crossing the interior. This algorithm is a form of nested fractal Mazes, except instead of always making fixed cell size Mazes with Mazes of the same size within each cell, it divides the given area randomly into a random sized 1×2 or 2×1 Maze. Recursive division doesn’t work as a passage carver, because doing so results in an obvious solution path that either follows the outside edge or else directly crosses the interior.
- Binary tree Mazes: This is basically the simplest and fastest algorithm possible, however Mazes produced by it have a very biased texture. For each cell carve a passage either leading up or leading left, but not both. In the wall added version, for each vertex add a wall segment leading down or right, but not both. Each cell is independent of every other cell, where you don’t have to refer to the state of any other cells when creating it. Hence this is a true memoryless Maze generation algorithm, with no limit to the size of Maze you can create. This is basically a computer science binary tree, if you consider the upper left corner the root, where each node or cell has one unique parent which is the cell above or to the left of it. Binary tree Mazes are different than standard perfect Mazes, since about half the cell types can never exist in them. For example there will never be a crossroads, and all dead ends have passages pointing up or left, and never down or right. The Maze tends to have passages leading diagonally from upper left to lower right, where the Maze is much easier to navigate from lower right to upper left. You will always be able to travel up or left, but never both, so you can always deterministically travel diagonally up and to the left without hitting any barriers. Traveling down and to the right is when you’ll encounter choices and dead ends. Note if you flip a binary tree Maze upside down and treat passages as walls and vice versa, the result is basically another binary tree.
- Sidewinder Mazes: This simple algorithm is very similar to the binary tree algorithm, and only slightly more complicated. The Maze is generated one row at a time: For each cell randomly decide whether to carve a passage leading right. If a passage is not carved, then consider the horizontal passage just completed, formed by the current cell and any cells to the left that carved passages leading to it. Randomly pick one cell along this passage, and carve a passage leading up from it (which must be the current cell if the adjacent cell didn’t carve). While a binary tree Maze always goes up from the leftmost cell of a horizontal passage, a sidewinder Maze goes up from a random cell. While binary tree has the top and left edges of the Maze one long passage, a sidewinder Maze has just the top edge one long passage. Like binary tree, a sidewinder Maze can be solved deterministically without error from bottom to top, because at each row, there will always be exactly one passage leading up. A solution to a sidewinder Maze will never double back on itself or visit a row more than once, although it will “wind from side to side”. The only cell type that can’t exist in a sidewinder Maze is a dead end with the passage facing down, because that would contradict the fact that every passage going up leads back to the start. A sidewinder Maze tends to have an elitist solution, where the right path is very direct, but there are many long false paths leading down from the top next to it.
|Algorithm||Dead End %||Type||Focus||Bias Free?||Memory||Time||Solution %|
|Hunt and Kill||11 (21)||Tree||Passage||no||0||55 (105)||9.5 (3.9)|
|Eller’s Algorithm||28||Set||Either||no||N*||10||4.2 (3.2)|
|Wilson’s Algorithm||29||Tree||Either||Yes||N^2||51 (26)||4.5|
|Aldous-Broder Algorithm||29||Tree||Either||Yes||0||222 (160)||4.5|
|Prim’s Algorithm||36 (31)||Tree||Either||Yes||N^2||21||2.3|
|Growing Tree||49 (39)||Tree||Either||Yes||N^2||43||11.0|
This table summarizes the characteristics of the perfect Maze creation algorithms above. The Unicursal Maze algorithm (unicursal Mazes are technically perfect) is included for comparison. Descriptions of the columns follow:
- Dead End: This is the approximate percentage of cells that are dead ends in a Maze created with this algorithm, when applied to an orthogonal 2D Maze. The algorithms in the table are sorted by this field. Usually creating by adding walls is the same as carving passages, however if significantly different the wall adding percentage is in parentheses. The Growing Tree value can actually range from 10% (always pick newest cell) to 49% (always swap with oldest cell). With a high enough run factor the Recursive Backtracker can get lower than 1%. The highest possible dead end percentage in an 2D orthogonal perfect Maze is 66%, which would be a unicursal passage with a bunch of one unit long dead ends off either side of it.
- Type: There are two types of perfect Maze creation algorithms: A tree based algorithm grows the Maze like a tree, always adding onto what is already present, having a valid perfect Maze at every step. A set based algorithm builds where it pleases, keeping track of which parts of the Maze are connected with each other, to ensure it’s able to link everything up to form a valid Maze by the time it’s done.
- Focus: Most algorithms can be implemented by either carving passages or adding walls. A few can only be done as one or the other. Unicursal Mazes are always wall added since they involve bisecting passages with walls, although the base Maze can be created either way. Recursive Backtracker can’t be done as a wall adder because doing so tends to result in a solution path that follows the outside edge, where the entire interior of the Maze is attached to the boundary by a single stem. Similarly Recursive Division can only be done as a wall adder due to its bisection behavior. Hunt and Kill is technically only passage carved for a similar reason, although it can be wall added if effort is made to grow inward from all boundary walls equally.
- Bias Free: This is whether the algorithm treats all directions and sides of the Maze equally, where analysis of the Maze afterward can’t reveal any bias. Binary Tree is extremely biased, where it’s easy traveling toward one corner and hard to its opposite. Sidewinder is also biased, where it’s easy traveling toward one edge and hard to its opposite. Eller’s algorithm tends to have a passage roughly paralleling the starting or finishing edges. Hunt and Kill is nearly bias free, although the back and forth systematic searching will give a slight bias along that axis.
- Memory: This is how much extra memory or stack is required to implement the algorithm. Efficient algorithms only require and look at the Maze bitmap itself, while others require storage proportional to a single row (N), or proportional to the number of cells (N^2). Some algorithms don’t even need to have the entire Maze in memory (these are marked with a asterisk). Eller’s algorithm requires storage for a row, but more than makes up for that since it only needs to store the current row of the Maze in memory. Sidewinder also only needs to store one row of the Maze, while Binary Tree only needs to keep track of the current cell. Recursive Division requires stack up to the size of a row, but other than that doesn’t need to look at the Maze bitmap any.
- Time: This gives an idea of how long it takes to create a Maze using this algorithm, lower numbers being faster. The numbers are only relative to each other (with the fastest standard algorithm being assigned speed 10) as opposed to in some units, because the time is dependent on the size of the Maze and speed of the computer. These numbers are from creating 100×100 passage Mazes in the latest version of Daedalus. Usually creating by adding walls is the same speed as carving passages, however if significantly different the wall adding time is in parentheses.
- Solution: This is the percentage of cells in the Maze that the solution path passes through, for a typical Maze created by the algorithm. This assumes the Maze is 100×100 passages with the start and end in opposite corners. This is a measure of the “windiness” of the solution path. Unicursal Mazes have maximum windiness, since the solution goes throughout the entire Maze. Binary Tree has the minimum possible windiness, where the solution path simply crosses the Maze and never deviates away from or ceases to make progress toward the end. Usually creating by adding walls has the same properties as carving passages, however if significantly different the wall adding percentage is in parentheses.
Maze Solving Algorithms
There are a number of ways of solving Mazes, each with its own characteristics. Here’s a list of specific algorithms:
- Dead end filler: This is a simple Maze solving algorithm. It focuses on the Maze, is always very fast, and uses no extra memory. Just scan the Maze, and fill in each dead end, filling in the passage backwards from the block until you reach a junction. This includes filling in passages that become parts of dead ends once other dead ends are removed. At the end only the solution will remain, or solutions if there are more than one. This will always find the one unique solution for perfect Mazes, but won’t do much in heavily braid Mazes, and in fact won’t do anything useful at all for those Mazes without dead ends.
- Wall follower: This is another simple Maze solving algorithm. It focuses on you, is always very fast, and uses no extra memory. Start following passages, and whenever you reach a junction always turn right (or left). Equivalent to a human solving a Maze by putting their hand on the right (or left) wall and leaving it there as they walk through. If you like you can mark what cells you’ve visited, and what cells you’ve visited twice, where at the end you can retrace the solution by following those cells visited once. This method won’t necessarily find the shortest solution, and it doesn’t work at all when the goal is in the center of the Maze and there’s a closed circuit surrounding it, as you’ll go around the center and eventually find yourself back at the beginning. Wall following can be done in a deterministic way in a 3D Maze by projecting the 3D passages onto the 2D plane, e.g. by pretending up passages actually lead northwest and down lead southeast, and then applying normal wall following rules.
- Cul-de-sac filler: This method finds and fills in cul-de-sacs or nooses, i.e. constructs in a Maze consisting of a blind alley stem that has a single loop at the end. Like the dead end filler, it focuses on the Maze, is always fast, and uses no extra memory. Scan the Maze, and for each noose junction (a noose junction being one where two of the passages leading from it connect with each other with no other junctions along the way) add a wall to convert the entire noose to a long dead end. Afterwards run the dead end filler. Mazes can have nooses hanging off other constructs that will become nooses once the first one is removed, so the whole process can be repeated until nothing happens during a scan. This doesn’t do much in complicated heavily braid Mazes, but will be able to invalidate more than just the dead end filler.
- Blind alley filler: This method finds all possible solutions, regardless of how long or short they may be. It does so by filling in all blind alleys, where a blind alley is a passage where if you walk down it in one direction, you will have to backtrack through that passage in the other direction in order to reach the goal. All dead ends are blind alleys, and all nooses as described in the cul-de-sac filler are as well, along with any sized section of passages connected to the rest of the Maze by only a single stem. This algorithm focuses on the Maze, uses no extra memory, but unfortunately is rather slow. For each junction, send a wall following robot down each passage from it, and see if the robot sent down a path comes back from the same path (as opposed to returning from a different direction, or it exiting the Maze). If it does, then that passage and everything down it can’t be on any solution path, so seal that passage off and fill in everything behind it. This algorithm will fill in everything the cul-de-sac filler will and then some, however the collision solver will fill in everything this algorithm will and then some.
- Blind alley sealer: This is like the blind alley filler, in that it also finds all possible solutions by removing blind alleys from the Maze. However this just fills in the stem passage of each blind alley, and doesn’t touch any collection of passages at the end of it. As a result this will create inaccessible passage sections for cul-de-sacs or any blind alley more complicated than a dead end. This algorithm focuses on the Maze, runs much faster than the blind alley filler, although it requires extra memory. Assign each connected section of walls to a unique set. To do this, for each wall section not already in a set, flood across the top of the walls at that point, and assign all reachable walls to a new set. After all walls are in sets, then for each passage section, if the walls on either side of it are in the same set, then seal off that passage. Such a passage must be a blind alley, since the walls on either side of it link up with each other, forming a pen. Note a similar technique can be used to help solve hypermazes, by sealing off space between branches that connect with each other.
- Pledge algorithm: This is a modified version of wall following that’s able to jump between islands, to solve Mazes wall following can’t. It’s a guaranteed way to reach an exit on the outer edge of any 2D Maze from any point in the middle, however it’s not able to do the reverse, i.e. find a solution within the Maze. It’s great for implementation by a Maze escaping robot, since it can get out of any Maze without having to mark or remember the path in any way. Start by picking a direction, and always move in that direction when possible. When a wall is hit, start wall following until your chosen direction is available again. Note you should start wall following upon the far wall that’s hit, where if the passage turns a corner there, it can cause you to turn around in the middle of a passage and go back the way you came. When wall following, count the number of turns you make, e.g. a left turn is -1 and a right turn is 1. Only stop wall following and take your chosen direction when the total number of turns you’ve made is 0, i.e. if you’ve turned around 360 degrees or more, keep wall following until you untwist yourself. The counting ensures you’re eventually able to reach the far side of the island you’re currently on, and jump to the next island in your chosen direction, where you’ll keep on island hopping in that direction until you hit the boundary wall, at which point wall following takes you to the exit. Note Pledge algorithm may make you visit a passage or the start more than once, although subsequent times will always be with different turn totals. Without marking your path, the only way to know whether the Maze is unsolvable is if your turn total keeps increasing, although the turn total can get to large numbers in solvable Mazes in a spiral passage.
- Chain algorithm: The Chain algorithm solves the Maze by effectively treating it as a number of smaller Mazes, like links in a chain, and solving them in sequence. You have to specify the start and desired end locations, and the algorithm will always find a path from start to end if one exists, where the solution tends to be a reasonably short if not the shortest solution. That means this can’t solve Mazes where you don’t know exactly where the end is. This is most similar to Pledge algorithm since it’s also essentially a wall follower with a way to jump between islands. Start by drawing a straight line (or at least a line that doesn’t double back on itself) from start to end, letting it cross walls if needed. Then just follow the line from start to end. If you bump into a wall, you can’t go through it, so you have to go around. Send two wall following “robots” in both directions along the wall you hit. If a robot runs into the guiding line again, and at a point which is closer to the exit, then stop, and follow that wall yourself until you get there too. Keep following the line and repeating the process until the end is reached. If both robots return to their original locations and directions, then farther points along the line are inaccessible, and the Maze is unsolvable.
- Recursive backtracker: This will find a solution, but it won’t necessarily find the shortest solution. It focuses on you, is fast for all types of Mazes, and uses stack space up to the size of the Maze. Very simple: If you’re at a wall (or an area you’ve already plotted), return failure, else if you’re at the finish, return success, else recursively try moving in the four directions. Plot a line when you try a new direction, and erase a line when you return failure, and a single solution will be marked out when you hit success. When backtracking, it’s best to mark the space with a special visited value, so you don’t visit it again from a different direction. In Computer Science terms this is basically a depth first search. This method will always find a solution if one exists, but it won’t necessarily be the shortest solution.
- Trémaux’s algorithm: This Maze solving method is designed to be able to be used by a human inside of the Maze. It’s similar to the recursive backtracker and will find a solution for all Mazes: As you walk down a passage, draw a line behind you to mark your path. When you hit a dead end turn around and go back the way you came. When you encounter a junction you haven’t visited before, pick a new passage at random. If you’re walking down a new passage and encounter a junction you have visited before, treat it like a dead end and go back the way you came. (That last step is the key which prevents you from going around in circles or missing passages in braid Mazes.) If walking down a passage you have visited before (i.e. marked once) and you encounter a junction, take any new passage if one is available, otherwise take an old passage (i.e. one you’ve marked once). All passages will either be empty, meaning you haven’t visited it yet, marked once, meaning you’ve gone down it exactly once, or marked twice, meaning you’ve gone down it and were forced to backtrack in the opposite direction. When you finally reach the solution, paths marked exactly once will indicate a direct way back to the start. If the Maze has no solution, you’ll find yourself back at the start with all passages marked twice.
- Collision solver: Also called the “amoeba” solver, this method will find all shortest solutions. It focuses on you multiple times, is fast for all types of Mazes, and requires at least one copy of the Maze in memory in addition to using memory up to the size of the Maze. It basically floods the Maze with “water”, such that all distances from the start are filled in at the same time (a breadth first search in Computer Science terms) and whenever two “columns of water” approach a passage from both ends (indicating a loop) add a wall to the original Maze where they collide. Once all parts of the Maze have been “flooded”, fill in all the new dead ends, which can’t be on the shortest path, and repeat the process until no more collisions happen. (Picture amoebas surfing at the crest of each “wave” as it flows down the passages, where when waves collide, the amoebas head-butt and get knocked out, and form there a new wall of unconscious amoebas, hence the name.)
- Shortest path finder: As the name indicates, this algorithm finds the shortest solution, picking one if there are multiple shortest solutions. It focuses on you multiple times, is fast for all types of Mazes, and requires quite a bit of extra memory proportional to the size of the Maze. Like the collision solver, this basically floods the Maze with “water”, such that all distances from the start are filled in at the same time (a breadth first search in Computer Science terms) however each “drop” or pixel remembers which pixel it was filled in by. Once the solution is hit by a “drop”, trace backwards from it to the beginning and that’s a shortest path. This algorithm works well given any input, because unlike most of the others, this doesn’t require the Maze to have any one pixel wide passages that can be followed. Note this is basically the A* path finding algorithm without a heuristic so all movement is given equal weight.
- Shortest paths finder: This is very similar to the shortest path finder above, except this finds all shortest solutions. Like the shortest path finder, this focuses on you multiple times, is fast for all types of Mazes, requires extra memory proportional to the size of the Maze, and works well given any input since it doesn’t require the Maze to have any one pixel wide passages that can be followed. Also like the shortest path finder, this does a breadth first search flooding the Maze with “water” such that all distances from the start are filled in at the same time, except here each pixel remembers how far it is from the beginning. Once the end is reached, do another breadth first search starting from the end, however only allow pixels to be included which are one distance unit less than the current pixel. The included pixels precisely mark all the shortest solutions, as blind alleys and non-shortest paths will jump in pixel distances or have them increase.
- Random mouse: For contrast, here’s an inefficient Maze solving method, which is basically to move randomly, i.e. move in one direction and follow that passage through any turnings until you reach the next junction. Don’t do any 180 degree turns unless you have to. This simulates a human randomly roaming the Maze without any memory of where they’ve been. It’s slow and isn’t guaranteed to ever terminate or solve the Maze, and once the end is reached it will be just as hard to retrace your steps, but it’s definitely simple and doesn’t require any extra memory to implement.
|Algorithm||Solutions||Guarantee?||Focus||Human Doable?||Passage Free?||Memory Free?||Fast?|
|Random Mouse||1||no||You||Inside / Above||no||Yes||no|
|Wall Follower||1||no||You||Inside / Above||Yes||Yes||Yes|
|Pledge Algorithm||1||no||You||Inside / Above||Yes||Yes||Yes|
|Chain Algorithm||1||Yes||You +||no||Yes||no||Yes|
|Trémaux’s Algorithm||1||Yes||You||Inside / Above||no||no||Yes|
|Dead End Filler||All +||no||Maze||Above||no||Yes||Yes|
|Cul-de-sac Filler||All +||no||Maze||Above||no||Yes||Yes|
|Blind Alley Sealer||All +||Yes||Maze||no||no||no||Yes|
|Blind Alley Filler||All||Yes||Maze||Above||no||Yes||no|
|Collision Solver||All Shortest||Yes||You +||no||no||no||Yes|
|Shortest Paths Finder||All Shortest||Yes||You +||no||Yes||no||Yes|
|Shortest Path Finder||1 Shortest||Yes||You +||no||Yes||no||Yes|
This table summarizes the characteristics of the Maze solving algorithms above. Maze solving algorithms can be classified and judged by these criteria. Descriptions of the columns follow:
- Solutions: This describes the solutions the algorithm finds, and what the algorithm does when there’s more than one. An algorithm can pick one solution, or leave multiple solutions. Also the solution(s) can be any path, or they can be the shortest path. The dead end and cul-de-sac fillers (and the blind alley sealer when considering its inaccessible sections) leave all solutions, however they may also leave passages that aren’t on any solution path, so are marked “All +” above.
- Guarantee: This is whether the algorithm is guaranteed to find at least one solution. Random mouse is “no” because it isn’t guaranteed to terminate, and wall follower and Pledge algorithm are “no” because they will fail to find a solution if the goal is within an island. The dead end and cul-de-sac fillers are “no” because they may not do anything to the Maze at all in purely braid Mazes.
- Focus: There are two general types of algorithms to solve a Maze: Focus on “you”, or focus on the Maze. In a you-focuser, you have a single point (“You” above) or a set of points (“You +” above) and try to move them through the Maze from start to finish. In a Maze-focuser, you look at the Maze as a whole and invalidate useless passages.
- Human Doable: This refers to whether a person could readily use the algorithm to solve the Maze, either while inside a life sized version, or while looking at a map from above. Some you-focuser algorithms can be implemented by a person inside (or above) the Maze, while some Maze-focusers can be implemented by a person, but only from above. Other algorithms are complicated or intricate enough they can only reliably be done by a computer.
- Passage Free: This is whether the algorithm can be done anywhere. Some algorithms require the Maze to have obvious passages, or distinct edges between distinct vertices in graph terms, or one pixel wide passages when implemented on a computer. The wall follower, Pledge algorithm, and chain algorithm only require a wall on one side of you. The recursive backtracker and the shortest path(s) finders make their own paths through open spaces.
- Memory Free: This is whether no extra memory or stack is required to implement the algorithm. Efficient algorithms only require and look at the Maze bitmap itself, and don’t need to add markers to the Maze during the solving process.
- Fast: This is whether the solving process is considered fast. The most efficient algorithms only need to look at each cell in the Maze once, or can skip sections altogether. Running time should be proportional to the size of the Maze, or in Computer Science terms O(n^2) where n is the number of cells along one side. Random mouse is slow because it isn’t guaranteed to terminate, while the blind alley filler potentially solves the Maze from each junction.