orienthong / mazes

Maze generation algorithms (>35), solvers (DFS, BFS, A*, Dijkstra, Best-First, Hill-Climbing) and demo applications.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Maze generation algorithms in Java 8

This project provides Java implementations of more than 35 algorithms for generating so called "perfect mazes" (which are just spanning trees of undirected graphs).

On the web, many maze generation implementations in all possible programming languages can be found. The popularity of these algorithms probably comes from the fact that mazes and their creation processes are visually appealing and not really difficult to implement. The most popular algorithm seems to be "recursive backtracking" which is random depth-first traversal of a graph.

On the other side, there are not so many sites where the whole spectrum of maze creation algorithms is investigated. One exception is this blog where Jamis Buck presents the most popular maze algorithms with Ruby and animated Javascript implementations. Reading his blog led myself to investigate this topic too.

Initially I intended to implement some of these algorithms in Java to learn about the new Java 8 features (streams, lambda expressions). I also wanted to implement the needed data structures (graph, grid graph, union-find, ...) not just in an "ad-hoc" fashion. The maze algorithm implementations should become pure graph algorithms without any UI or animation related parts. The underlying graph algorithms, for example minimum-spanning tree algorithms, should still be clearly recognizable in the maze generator code. Avoiding dependencies to UI frameworks should make the maze generators more reusable. For example, the animated GIF images below have been created using a grid observer which takes snapshots of the maze while being created. The maze generator code is not affected.

In the end, all of the algorithms presented in Jamis Buck's blog and even some new algorithms have been implemented. One new algorithm is a modification of Eller's algorithm that in contrast to the original doesn't generate the maze row-wise but from the center of the grid towards the outer borders. The resulting maze however is heavily biased. Other new algorithms are variations of Wilson's uniform spanning tree algorithm. They result from the different possibilities for selecting the random walk start cells.

As the order in which the random walk start cells are selected is arbitrary, we have a number of interesting choices. For example, you can start the random walks in the order defined by a space-filling curves like Hilbert, Peano or Moore curves. You can also use other interesting patterns of filling a grid. In any case you will get visually appealing maze creation processes.

Also implemented in this project are path finding algorithms for "solving" the generated mazes: "Breadth-First" and "Depth-First" search together with their informed variants "Best-First" search and "Hill Climbing". For completeness, the A* path finder has also been included, but for perfect mazes which are trees with equal edge costs and a unique path between every two vertices, the A* or Dijkstra algorithm do not really provide additional value.

The included demo application demonstrates all implemented maze generators and path finders. Using a control panel you can interactively select the generation algorithm, path finder, grid resolution and rendering style ("walls", "passages").

To achieve the goals mentioned above, there is

  • an API for graph and 2D-grid data structures
  • an implementation of a 2D-grid with cell and edge content
  • a publish-subscribe mechanism for observing graph/grid operations and traversal algorithms

Here is the maze generator based on Kruskal's minimum spanning tree algorithm:

public class KruskalMST implements MazeGenerator<OrthogonalGrid> {

	private OrthogonalGrid grid;

	public KruskalMST(int numCols, int numRows) {
		grid = emptyGrid(numCols, numRows, UNVISITED);
	}

	@Override
	public OrthogonalGrid getGrid() {
		return grid;
	}

	@Override
	public OrthogonalGrid createMaze(int x, int y) {
		Partition<Integer> forest = new Partition<>();
		permute(fullGrid(grid.numCols(), grid.numRows(), UNVISITED).edges()).forEach(edge -> {
			int u = edge.either(), v = edge.other();
			if (forest.find(u) != forest.find(v)) {
				grid.addEdge(u, v);
				grid.set(u, COMPLETED);
				grid.set(v, COMPLETED);
				forest.union(u, v);
			}
		});
		return grid;
	}
}

Anybody familiar with the Kruskal algorithm will immediately recognize it in this code. The difference is that in the maze generator the edges of a (full) grid are selected in random order where the original MST algorithm greedily selects the minimum cost edge in each step.

Implemented maze generation algorithms:

Graph Traversal:

Minimum Spanning Tree:

Uniform Spanning Tree:

Other algorithms:

Path finding algorithms:

The EasyGraph library contains the following path finder implementations:

About

Maze generation algorithms (>35), solvers (DFS, BFS, A*, Dijkstra, Best-First, Hill-Climbing) and demo applications.


Languages

Language:Java 100.0%