Skip to content

Commit 1debc37

Browse files
author
Kevin Nadro
committed
Added Maze creation example
I saw that there isn’t anything on disjoint sets or mazes under the examples so I implemented the process of making a maze. I have visualized a maze creation before (https://github.com/nadr0/Maze). I have always been a fan of visualizing data structures or algorithms and I though this was the perfect chance! My code is rather large but it gets the job done. I
1 parent fe7d899 commit 1debc37

File tree

5 files changed

+318
-1
lines changed

5 files changed

+318
-1
lines changed

algorithm/category.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,8 @@
102102
"etc": {
103103
"list": {
104104
"flood_fill": "Flood Fill",
105-
"cellular_automata": "Cellular Automata"
105+
"cellular_automata": "Cellular Automata",
106+
"create_maze": "Create Maze"
106107
},
107108
"name": "Uncategorized"
108109
}
Lines changed: 247 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,247 @@
1+
function buildMaze(){
2+
var mySet = new disjoint_set();
3+
var width = m;
4+
var height = n;
5+
var setSize = 0;
6+
var graph = [];
7+
var visitedMap = {};
8+
var walls = {};
9+
var rightWalls = [];
10+
var downWalls = [];
11+
var location = 0;
12+
13+
mySet.addElements(width*height);
14+
15+
// init 'graph'
16+
for (var i = 0; i < width; i++) {
17+
graph[i] = new Array(height);
18+
for(var j = 0; j < height; j++){
19+
graph[i][j] = location;
20+
21+
walls[location] = {down: true, right: true};
22+
visitedMap[location] = false;
23+
24+
rightWalls.push({x:i, y:j});
25+
downWalls.push({x:i, y:j});
26+
location++;
27+
}
28+
};
29+
30+
var rightWalls = shuffle(rightWalls);
31+
var downWalls = shuffle(downWalls);
32+
while(setSize != mySet.elements - 1){
33+
var randomWall = Math.floor((Math.random() * 2) + 1);
34+
if(randomWall === 1 && downWalls.length > 0){
35+
// Down wall
36+
var currNode = downWalls.pop();
37+
var i_x = currNode.x;
38+
var i_y = currNode.y;
39+
var i_y_down = i_y + 1;
40+
if(i_y_down < height){
41+
var u = graph[i_x][i_y];
42+
var v = graph[i_x][i_y_down];
43+
if(mySet.find(u) != mySet.find(v)){
44+
mySet.setUnion(u,v);
45+
setSize++;
46+
// delete wall
47+
walls[u].down = false;
48+
}
49+
}
50+
}else if(randomWall === 2 && rightWalls.length > 0){
51+
// Right Wall
52+
var currNode = rightWalls.pop();
53+
var i_x = currNode.x;
54+
var i_y = currNode.y;
55+
var i_x_right = i_x + 1;
56+
if(i_x_right < width){
57+
var u = graph[i_x][i_y];
58+
var v = graph[i_x_right][i_y];
59+
if(mySet.find(u) != mySet.find(v)){
60+
mySet.setUnion(u,v);
61+
setSize++;
62+
// delete wall
63+
walls[u].right = false;
64+
}
65+
}
66+
}
67+
}
68+
69+
//update deleted walls
70+
for (var i = 0; i < width; i++) {
71+
for(var j = 0; j < height; j++){
72+
var current_wall = walls[graph[i][j]];
73+
74+
if(current_wall.down === false){
75+
G[j*2 + 2][i*3 + 1] = ' ';
76+
G[j*2 + 2][i*3 + 2] = ' ';
77+
tracer._select(j*2 + 2, i*3 + 1)._wait();
78+
tracer._select(j*2 + 2, i*3 + 2)._wait();
79+
}
80+
// tracer._notify(i, j, G[i][j])._wait();
81+
if(current_wall.right === false){
82+
G[j*2 + 1][i*3 + 3] = ' ';
83+
tracer._select(j*2 +1 , i*3 + 3)._wait();
84+
}
85+
tracer._setData(G);
86+
}
87+
}
88+
89+
// Start location
90+
G[0][0] = '│';
91+
G[0][1] = ' ';
92+
G[0][2] = ' ';
93+
// End location
94+
G[v_end-1][h_end-1] = '│';
95+
G[v_end-1][h_end-2] = ' ';
96+
G[v_end-1][h_end-3] = ' ';
97+
98+
// clean up grid for looks
99+
for (var i = 0; i < v_end; i++) {
100+
for(var j = 0; j < h_end; j++){
101+
if(G[i][j] === '├'){
102+
if(G[i][j+1] === ' '){
103+
G[i][j] = '│';
104+
}
105+
}
106+
107+
if(G[i][j] === '┤'){
108+
if(G[i][j-1] === ' '){
109+
G[i][j] = '│';
110+
}
111+
}
112+
113+
if(G[i][j] === '┬'){
114+
if(G[i+1][j] === ' '){
115+
G[i][j] = '─';
116+
}
117+
}
118+
119+
if(G[i][j] === '┴'){
120+
if(G[i-1][j] === ' '){
121+
G[i][j] = '─';
122+
}
123+
}
124+
125+
if(G[i][j] === '┼'){
126+
if(G[i][j+1] === ' '&& G[i-1][j] === ' ' && G[i][j-1] !== ' ' && G[i+1][j] !== ' '){
127+
G[i][j] = '┐';
128+
}
129+
else if(G[i][j-1] === ' '&& G[i-1][j] === ' ' && G[i+1][j] !== ' ' && G[i][j+1] !== ' '){
130+
G[i][j] = '┌';
131+
}
132+
else if(G[i][j-1] === ' '&& G[i+1][j] === ' ' && G[i-1][j] !== ' ' && G[i][j+1] !== ' '){
133+
G[i][j] = '└';
134+
}
135+
else if(G[i][j+1] === ' '&& G[i+1][j] === ' ' && G[i-1][j] !== ' ' && G[i][j-1] !== ' '){
136+
G[i][j] = '┘';
137+
}
138+
139+
else if(G[i][j+1] === ' '&& G[i][j-1] === ' ' && (G[i+1][j] === ' ' || G[i-1][j] === ' ')){
140+
G[i][j] = '│';
141+
}
142+
else if(G[i+1][j] === ' '&& G[i-1][j] === ' ' && (G[i][j-1] === ' ' || G[i][j+1] === ' ')){
143+
G[i][j] = '─';
144+
}
145+
146+
else if(G[i][j+1] === ' '&& G[i][j-1] === ' ' ){
147+
G[i][j] = '│';
148+
}
149+
else if(G[i+1][j] === ' '&& G[i-1][j] === ' '){
150+
G[i][j] = '─';
151+
}
152+
else if(G[i+1][j] === ' ' && G[i-1][j] !== ' ' && G[i][j-1] !== ' ' && G[i][j+1] !== ' '){
153+
G[i][j] = '┴';
154+
}
155+
156+
else if(G[i-1][j] === ' ' && G[i+1][j] !== ' ' && G[i][j+1] !== ' ' && G[i][j-1] !== ' '){
157+
G[i][j] = '┬';
158+
}
159+
160+
else if(G[i][j+1] === ' ' && G[i-1][j] !== ' ' && G[i+1][j] !== ' ' && G[i][j-1] !== ' '){
161+
G[i][j] = '┤';
162+
}
163+
164+
else if(G[i][j-1] === ' ' && G[i-1][j] !== ' ' && G[i+1][j] !== ' ' && G[i][j+1] !== ' '){
165+
G[i][j] = '├';
166+
}
167+
168+
169+
}
170+
171+
}
172+
}
173+
174+
G[1][1] = 'S';
175+
G[v_end-1][h_end-2] = 'E';
176+
// last wall clean up for start & end locations
177+
if(G[0][3] === '┬'){
178+
G[0][3] = '┌';
179+
}
180+
if(G[v_end-1][h_end-4] === '┴'){
181+
G[v_end-1][h_end-4] = '┘';
182+
}
183+
184+
// set the data
185+
tracer._setData(G);
186+
}
187+
188+
class disjoint_set {
189+
constructor(){
190+
this.set = [];
191+
this.elements = 0;
192+
}
193+
addElements(numberOfElements){
194+
for(var i = 0; i < numberOfElements; i++){
195+
this.elements++;
196+
this.set.push(-1);
197+
}
198+
}
199+
find(element){
200+
if(this.set[element] < 0){
201+
return element;
202+
}else {
203+
return this.set[element] = this.find(this.set[element]);
204+
}
205+
}
206+
setUnion(_a,_b){
207+
var a = this.find(_a);
208+
var b = this.find(_b);
209+
210+
if(a != b){
211+
var newSize = (this.set[a] + this.set[b]);
212+
if(this.compareSize(a,b)){
213+
this.set[b] = a;
214+
this.set[a] = newSize;
215+
}else{
216+
this.set[a] = b;
217+
this.set[b] = newSize;
218+
}
219+
}
220+
}
221+
compareSize(a,b){
222+
if(this.set[a] === this.set[b]){
223+
return true;
224+
}else if(this.set[a] < this.set[b]){
225+
return true;
226+
}else{
227+
return false;
228+
}
229+
}
230+
}
231+
232+
// http://bost.ocks.org/mike/shuffle/
233+
function shuffle(array) {
234+
var m = array.length, t, i;
235+
// While there remain elements to shuffle…
236+
while (m) {
237+
// Pick a remaining element…
238+
i = Math.floor(Math.random() * m--);
239+
// And swap it with the current element.
240+
t = array[m];
241+
array[m] = array[i];
242+
array[i] = t;
243+
}
244+
return array;
245+
}
246+
247+
buildMaze();
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
var tracer = new Array2DTracer ();
2+
var n = 6; // rows (change these!)
3+
var m = 6; // columns (change these!)
4+
5+
var h_end = m * 4 - (m-1);
6+
var v_end = n * 3 - (n-1);
7+
8+
var G = [];
9+
10+
for (var i = 0; i < v_end; i++) {
11+
G[i] = new Array(h_end);
12+
for(var j = 0; j < h_end; j++){
13+
14+
G[i][j] = ' ';
15+
16+
if(i === 0 && j === 0){ // top-left corner
17+
G[i][j] = '┌';
18+
}else if( i === 0 && j === h_end-1){ // top-right corner
19+
G[i][j] = '┐';
20+
}else if(i === v_end - 1 && j === 0){ // bottom-left corner
21+
G[i][j] = '└';
22+
}else if(i === v_end - 1 && j === h_end - 1){ // bottom-right corner
23+
G[i][j] = '┘';
24+
}
25+
else if( (j % 3 === 0) && (i % v_end !== 0 && i !== v_end-1 && i % 2 == 1)){
26+
G[i][j] = '│';
27+
}else if (i % 2 === 0){
28+
G[i][j] = '─';
29+
}
30+
31+
if(m > 1){
32+
if( j % 3 === 0 && j !== 0 && j !== h_end - 1 && i === 0){
33+
G[i][j] = '┬';
34+
}
35+
if( j % 3 === 0 && j !== 0 && j !== h_end - 1 && i === v_end-1){
36+
G[i][j] = '┴';
37+
}
38+
}
39+
40+
if(n > 1){
41+
if(i % 2 === 0 && i !== 0 && i !==v_end-1 && j === 0){
42+
G[i][j] = '├';
43+
}
44+
if(i % 2 === 0 && i !== 0 && i !==v_end-1 && j === h_end-1){
45+
G[i][j] = '┤';
46+
}
47+
}
48+
49+
if(n > 1 && m > 1){
50+
if(i % 2 === 0 && j % 3 === 0 && i !== 0 && j !== 0 && i !== v_end-1 && j !== h_end-1){
51+
G[i][j] = '┼';
52+
}
53+
}
54+
55+
}
56+
}
57+
58+
tracer._setData(G);

algorithm/etc/create_maze/desc.json

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"Create Maze": "Building a maze can be done with using disjoint sets.",
3+
"References": [
4+
"<a href='https://en.wikipedia.org/wiki/Disjoint-set_data_structure'>Disjoint Sets Wikipedia</a>"
5+
],
6+
"files": {
7+
"create_maze": ""
8+
}
9+
}

gulpfile.babel.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
'use strict';
22

3+
var Promise = require('es6-promise').Promise;
4+
35
import path from 'path';
46
import gulp from 'gulp';
57
import uglify from 'gulp-uglify';

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy