Skip to content

Commit 2fb376d

Browse files
authored
Create maze-generator.html
1 parent 72cb0cb commit 2fb376d

File tree

1 file changed

+211
-0
lines changed

1 file changed

+211
-0
lines changed

maze-generator.html

+211
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,211 @@
1+
<html>
2+
<head><title>Maze generator</title>
3+
<style>
4+
section {
5+
display: grid;
6+
grid-template-columns: repeat(41, 12px);
7+
grid-template-rows: repeat(41, 12px);
8+
cursor: pointer;
9+
}
10+
div {
11+
width: 10px;
12+
height: 10px;
13+
background: lightgrey;
14+
}
15+
16+
div.black { background: black; }
17+
</style>
18+
</head>
19+
<body>
20+
21+
<span id="msg">Random Maze</span>
22+
<section>
23+
<!-- 41x41 empty div elements will be added here. -->
24+
</section>
25+
26+
<p>Click and drag to draw.</p>
27+
<button id="clear">Clear to all white</button>
28+
<button id="fill">Fill with all black</button>
29+
<button id="make_maze_recur">Make maze (recursive)</button>
30+
<button id="make_maze_iter">Make maze (iterative)</button>
31+
32+
<script>
33+
const boardSize = 41;
34+
const mazeSize = 20;
35+
36+
// Create the HTML elmements
37+
let sectionEl = document.querySelector("section");
38+
for (let r=0; r<boardSize; r++)
39+
for (let c=0; c<boardSize; c++) {
40+
let newDiv = document.createElement('div');
41+
newDiv.dataset.r = r;
42+
newDiv.dataset.c = c; sectionEl.appendChild(newDiv);
43+
}
44+
let pixels = document.querySelectorAll('section div');
45+
let running = false;
46+
47+
// Board is matrix of pixels that start with desired color
48+
let board = [];
49+
function initializeBoard(color) {
50+
board = [];
51+
for (let r=0; r<boardSize; r++) {
52+
let row = [];
53+
board.push(row);
54+
for (let c=0; c<boardSize; c++) {
55+
row.push(color);
56+
}
57+
}
58+
}
59+
60+
function render() {
61+
let i = 0;
62+
for (pixel of pixels) {
63+
let r = Math.floor(i / boardSize);
64+
let c = i % boardSize
65+
pixel.className = board[r][c];
66+
i++;
67+
}
68+
}
69+
70+
function fillBoard(color) {
71+
initializeBoard(color);
72+
render();
73+
}
74+
75+
fillBoard('white');
76+
77+
const NORTH = {dx: 0, dy: -2};
78+
const SOUTH = {dx: 0, dy: 2};
79+
const EAST = {dx: -2, dy: 0};
80+
const WEST = {dx: 2, dy: 0};
81+
82+
function findAllNeighbors(cellXY) {
83+
let result = [];
84+
for (let direction of [NORTH, SOUTH, EAST, WEST]) {
85+
let neighborX = cellXY.x + direction.dx;
86+
let neighborY = cellXY.y + direction.dy;
87+
result.push({x: neighborX, y: neighborY});
88+
}
89+
return result;
90+
}
91+
92+
function pickRandomItem(list) {
93+
let index = Math.floor(Math.random() * list.length);
94+
// Cut out a sublist starting at index with length 1.
95+
let itemInAList = list.splice(index, 1);
96+
return itemInAList[0]; // just return the single item
97+
}
98+
99+
function visitRecursive(cellXY) {
100+
// The maze cell that we are visiting is now part of the maze.
101+
board[cellXY.x][cellXY.y] = 'white';
102+
103+
let neighborCells = findAllNeighbors(cellXY);
104+
while (neighborCells.length) {
105+
let potentialNeighbor = pickRandomItem(neighborCells);
106+
// If the potential neighbor is in the bounds of the board and not already part of the maze, choose it.
107+
if (board[potentialNeighbor.x] &&
108+
board[potentialNeighbor.x][potentialNeighbor.y] == 'black') {
109+
// Remove the wall between this cell and the next cell.
110+
board[(cellXY.x + potentialNeighbor.x) / 2][(cellXY.y + potentialNeighbor.y) / 2] = 'white';
111+
// Make that next cell part of the maze and keep going
112+
visitRecursive(potentialNeighbor);
113+
}
114+
}
115+
render();
116+
}
117+
118+
function makeMazeRecursive() {
119+
initializeBoard('black');
120+
visitRecursive({x: 1, y: 1});
121+
console.log('done');
122+
render();
123+
}
124+
125+
// These are cellXY values that are in the unexplored area, but adjacent to the explored area
126+
let frontier = [];
127+
128+
function visitIterative(cellXY) {
129+
// Add this cell to the maze.
130+
if (board[cellXY.x][cellXY.y] == 'black') {
131+
board[cellXY.x][cellXY.y] = 'white';
132+
// Connect it to the part of the existing maze that spawned it.
133+
if (cellXY.connectionX) {
134+
board[cellXY.connectionX][cellXY.connectionY] = 'white';
135+
}
136+
}
137+
138+
// Any unexplored adjacent cells are now added to the list of frontiers.
139+
for (let direction of [NORTH, SOUTH, EAST, WEST]) {
140+
let neighborX = cellXY.x + direction.dx;
141+
let neighborY = cellXY.y + direction.dy;
142+
if (board[neighborX] && board[neighborX][neighborY] == 'black') {
143+
frontier.push({
144+
x: neighborX,
145+
y: neighborY,
146+
connectionX: (cellXY.x + neighborX) / 2,
147+
connectionY: (cellXY.y + neighborY) / 2,
148+
});
149+
// Prevent us from adding the same cell to the frontier again.
150+
board[neighborX][neighborY] == 'frontier';
151+
}
152+
}
153+
}
154+
155+
function makeMazeIterative() {
156+
initializeBoard('black');
157+
visitIterative({x: 1, y: 1});
158+
while (frontier.length) {
159+
let frontierCell = pickRandomItem(frontier);
160+
visitIterative(frontierCell);
161+
}
162+
console.log('done');
163+
render();
164+
}
165+
166+
167+
168+
document.querySelector('#clear').addEventListener('click', (e) => fillBoard('white'));
169+
document.querySelector('#fill').addEventListener('click', (e) => fillBoard('black'));
170+
document.querySelector('#make_maze_recur').addEventListener('click', makeMazeRecursive);
171+
document.querySelector('#make_maze_iter').addEventListener('click', makeMazeIterative);
172+
173+
//document.querySelector('#play-pause').addEventListener('click', playPause);
174+
175+
function gameLoop() {
176+
//if (!running) return;
177+
//update();
178+
render();
179+
}
180+
181+
window.setInterval(gameLoop, 100);
182+
183+
184+
let drawingMode = 'black';
185+
186+
function draw(pixel) {
187+
let r = Number(pixel.dataset.r);
188+
let c = Number(pixel.dataset.c);
189+
board[r][c] = drawingMode;
190+
render();
191+
}
192+
193+
function startDrawing(pixel) {
194+
drawingMode = (pixel.className == 'black') ? 'white' : 'black';
195+
draw(pixel);
196+
}
197+
198+
pixels.forEach((pixel => {
199+
pixel.addEventListener(
200+
'mousedown', (e) => {
201+
startDrawing(e.target);
202+
});
203+
pixel.addEventListener(
204+
'mouseenter', (e) => {
205+
if (e.buttons) draw(e.target);
206+
});
207+
}));
208+
209+
</script>
210+
</body>
211+
</html>

0 commit comments

Comments
 (0)