The Disjoint-Set, for those who are not familiar, is a data structure that allows to keep track of groups, letting you join groups and find the group to which a specific component belongs, all in O(Log*(n)).
For more info, read: http://en.wikipedia.org/wiki/Disjoint-set_data_structure.
Now, lets think of a maze as a grid of cells. For cells X and Y, you can reach from X to Y through the winding maze if there is a continuous route without walls between the two. So, lets start with a maze in which each cell has all its 4 walls built. The goal is to get a maze in which there is exactly 1 way to get from any cell X to any cell Y. Now lets add the data structure into the image. We start with a Disjoint-set that has a group for each of the cells. Each turn we destroy a wall between 2 cells that belong to different groups. This way we open exactly 1 passage between each of the cells in one group to each in the other. We know we've finished when there is exactly one group in the set.
For those who like algorithms, this is actually an implementation of the Kruskal algorithm for finding Minimal Spanning Trees in graphs (if you take the grid cells as vertices and the walls as edges).
You can read more here: http://en.wikipedia.org/wiki/Kruskal%27s_algorithm
or you can look at some boos here: Books on Algorithms on Amazon
Lets look at some code.
A simple implementation of the Disjoint-set:
public class DisjointSet {
private int[] set;
private int[] sizes;
private int size;
public DisjointSet(int size) {
this.set = new int[size];
for (int i = 0; i < size; i++) { this.set[i] = i; }
this.sizes = new int[size];
for (int i = 0; i < size; i++) { this.sizes[i] = 1; }
this.size = size;
}
public int find(int item) {
int root = item;
// find the root
while (set[root] != root) {
root = set[root];
}
// now shorten the paths
int curr = item;
while (set[curr] != root) {
set[curr] = root;
}
return root;
}
public int join(int item1, int item2) {
int group1 = find(item1);
int group2 = find(item2);
--size;
if (sizes[group1] > sizes[group2]) {
set[group2] = group1;
sizes[group1] += sizes[group2];
return group1;
} else {
set[group1] = group2;
sizes[group2] += sizes[group1];
return group2;
}
}
}
Now, lets build the maze:
Maze createRandomMaze(int rows, int columns) {
Maze maze = new Maze(rows, columns);
// create all walls
List<Wall> walls = maze.getAllInnerWalls();
// remove all the walls you can
DisjointSet diset = new DisjointSet(rows*columns);
while (diset.size() > 1) {
int wallIndex = random.nextInt(walls.size());
int cell1 = walls.get(wallIndex).cell1;
int cell2 = walls.get(wallIndex).cell2;
if (diset.find(cell1) != diset.find(cell2)) {
// we can remove the wall
maze.removeWall(walls.get(wallIndex));
diset.join(cell1, cell2);
}
walls.remove(wallIndex);
}
return maze;
}
And here is the result:
For the full code and much much more, visit my open-source project at: https://code.google.com/p/ai4u/
The code in this post is located at:
Disjoint-Set: https://code.google.com/p/ai4u/source/browse/com.ai4u.util/trunk/src/com/ai4u/util/disjointSet/ArrayDisjointSet.java
Maze: https://code.google.com/p/ai4u/source/browse/com.ai4u.util/trunk/src/com/ai4u/util/games/maze/Maze.java
Well, this is it for my first post.
Please, send me any ideas, questions or comments to My Email
