initial commit
This commit is contained in:
commit
bcafd62c26
9
index.html
Normal file
9
index.html
Normal file
|
@ -0,0 +1,9 @@
|
|||
<html>
|
||||
<head>
|
||||
</head>
|
||||
<body onload="startup()">
|
||||
<script type="text/javascript" src="js/maze_generation.js"></script>
|
||||
<script type="text/javascript" src="js/maze_solving.js"></script>
|
||||
<script type="text/javascript" src="js/canvas.js"></script>
|
||||
</body>
|
||||
</html>
|
222
js/canvas.js
Normal file
222
js/canvas.js
Normal file
|
@ -0,0 +1,222 @@
|
|||
var canv, ctx, columns, rows, rectWidth, rectHeight, maze;
|
||||
|
||||
function display() {
|
||||
ctx.fillStyle = "black";
|
||||
ctx.fillRect(0,0,canv.width,canv.height);
|
||||
maze = generate_maze(columns, rows);
|
||||
startingCell = maze[0];
|
||||
endingCell = maze[maze.length-1];
|
||||
|
||||
// Draw Grid in Grey (to see individual Cells)
|
||||
ctx.strokeStyle = "rgb(60, 60, 60)";
|
||||
for (var i = 0; i < columns; i++) {
|
||||
var x = i*rectWidth;
|
||||
for (var j = 0; j < rows; j++) {
|
||||
var y = j*rectHeight;
|
||||
ctx.beginPath();
|
||||
ctx.rect(x,y,rectWidth,rectHeight);
|
||||
ctx.closePath();
|
||||
ctx.stroke();
|
||||
}
|
||||
}
|
||||
|
||||
// Display the Maze ontop of the indivudial Cells
|
||||
ctx.strokeStyle = "white";
|
||||
for (var i = 0; i < columns; i++) {
|
||||
var sx = i*rectWidth;
|
||||
var rx = (i+1)*rectWidth;
|
||||
for (var j = 0; j < rows; j++) {
|
||||
var sy = j*rectHeight;
|
||||
var by = (j+1)*rectHeight;
|
||||
var cell = maze[getIndex(i, j, columns)];
|
||||
|
||||
if (cell.walls[0]) {
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(sx, sy);
|
||||
ctx.lineTo(rx, sy);
|
||||
ctx.closePath();
|
||||
ctx.stroke();
|
||||
}
|
||||
if (cell.walls[1]) {
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(rx, sy);
|
||||
ctx.lineTo(rx, by);
|
||||
ctx.closePath();
|
||||
ctx.stroke();
|
||||
}
|
||||
if (cell.walls[2]) {
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(sx, by);
|
||||
ctx.lineTo(rx, by);
|
||||
ctx.closePath();
|
||||
ctx.stroke();
|
||||
}
|
||||
if (cell.walls[3]) {
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(sx, sy);
|
||||
ctx.lineTo(sx, by);
|
||||
ctx.closePath();
|
||||
ctx.stroke();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function startup() {
|
||||
columns = 10;
|
||||
rows = 5;
|
||||
|
||||
var div = document.createElement("div");
|
||||
div.style.position = "absolute";
|
||||
div.style.bottom = "0px";
|
||||
div.style.color = "white";
|
||||
div.style.fontFamily = "arial";
|
||||
|
||||
var wp = document.createElement("a");
|
||||
wp.innerText = "Cells in column:"
|
||||
div.appendChild(wp);
|
||||
var wi = document.createElement("input");
|
||||
wi.type="range";
|
||||
wi.min = 10;
|
||||
wi.max = 100;
|
||||
wi.value = columns;
|
||||
wi.oninput=function() {
|
||||
columns = parseInt(this.value);
|
||||
rectWidth = window.innerWidth/columns;
|
||||
display();
|
||||
}
|
||||
div.appendChild(wi);
|
||||
|
||||
var hp = document.createElement("a");
|
||||
hp.innerText = "Cells in row:"
|
||||
div.appendChild(hp);
|
||||
var hi = document.createElement("input");
|
||||
hi.type="range";
|
||||
hi.min = 5;
|
||||
hi.max = 50;
|
||||
hi.value = rows;
|
||||
hi.oninput=function() {
|
||||
rows = parseInt(this.value);
|
||||
rectHeight = window.innerHeight/rows;
|
||||
display();
|
||||
}
|
||||
div.appendChild(hi);
|
||||
|
||||
var pb = document.createElement("button");
|
||||
pb.innerHTML = "Solve Maze";
|
||||
pb.onclick = function() {
|
||||
var startingCell = maze[0];
|
||||
var endingCell = maze[maze.length-1];
|
||||
var path = solve_maze(maze, columns, rows, startingCell, endingCell);
|
||||
|
||||
ctx.strokeStyle = "rgb(0,200,255)";
|
||||
ctx.beginPath();
|
||||
var first_x = path[0].i*rectWidth;
|
||||
var first_y = path[0].j*rectHeight;;
|
||||
ctx.moveTo(first_x+rectWidth/2, first_y+rectHeight/2);
|
||||
for (var i = 1; i < path.length; i++) {
|
||||
var cell = path[i];
|
||||
var x = cell.i*rectWidth;
|
||||
var y = cell.j*rectHeight;
|
||||
ctx.lineTo(x+rectWidth/2, y+rectHeight/2);
|
||||
}
|
||||
ctx.stroke();
|
||||
ctx.closePath();
|
||||
}
|
||||
div.appendChild(pb);
|
||||
|
||||
rectWidth = window.innerWidth/columns;
|
||||
rectHeight = window.innerHeight/rows;
|
||||
|
||||
canv = document.createElement("canvas");
|
||||
canv.width = window.innerWidth;
|
||||
canv.height = window.innerHeight;
|
||||
canv.style.position = "absolute";
|
||||
canv.style.top = "0px";
|
||||
canv.style.left = "0px";
|
||||
ctx = canv.getContext("2d");
|
||||
document.body.appendChild(canv);
|
||||
document.body.appendChild(div);
|
||||
|
||||
display();}/*
|
||||
mazeToGrid();
|
||||
}
|
||||
|
||||
function mazeToGrid() {
|
||||
var newColumns = columns*2-1;
|
||||
var cellWidth = canv.width/newColumns;
|
||||
var newRows = rows*2-1;
|
||||
var cellHeight = canv.height/newRows;
|
||||
|
||||
var grid = Array(newColumns);
|
||||
for (var i = 0; i < grid.length; i++) {
|
||||
var row = Array(newRows);
|
||||
for (var j = 0; j < rows.length; j++) {
|
||||
row[j] = false;
|
||||
}
|
||||
grid.push(row);
|
||||
}
|
||||
|
||||
var stack = Array();
|
||||
var o = gridSet(grid, 0, 0, stack);
|
||||
grid = o.g;
|
||||
stack = o.s;
|
||||
|
||||
for (var i = 0; i < grid.length; i++) {
|
||||
var x = i * cellWidth;
|
||||
for (var j = 0; j < grid[i].length; j++) {
|
||||
var y = j * cellHeight;
|
||||
ctx.fillStyle = (grid[i][j]) ? "white" : "black";
|
||||
ctx.fillRect(x,y,cellWidth,cellHeight);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function gridSet(g, x, y, s) {
|
||||
var isInStack = false;
|
||||
for (var i = 0; i < s; i++) {
|
||||
if (s[i].x == x && s[i].y == y) {
|
||||
isInStack = true;
|
||||
}
|
||||
}
|
||||
if (!isInStack) {
|
||||
|
||||
var neighbors = Array();
|
||||
for (var i = -1; i < -2; i++) {
|
||||
var nx = x + i;
|
||||
if (nx >= 0 && nx < columns) {
|
||||
for (var j = -1; j < -2; j++) {
|
||||
var ny = y + j;
|
||||
if (ny >= 0 && ny < rows && !(nx == x && ny == y)) {
|
||||
neighbors.push({x: nx, y: ny});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
s.push({x, y});
|
||||
|
||||
// ALWAYS DO RIGHT AND BOTTOM
|
||||
if (maze[x+y*columns].walls[1]) {
|
||||
if (x*2+1 < newColumns) {
|
||||
grid[x*2+1][y*2] = true;
|
||||
}
|
||||
}
|
||||
if (maze[x+y*columns].walls[2]) {
|
||||
if (y*2+1 < newRows) {
|
||||
grid[x*2][y*2+1] = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (neighbors.length > 0) {
|
||||
for (var i = 0; i < neighbors.length; i++) {
|
||||
var n = neighbors[i];
|
||||
var o = gridSet(g, n.x, n.y, s);
|
||||
g = o.g;
|
||||
s = o.s;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {g, s};
|
||||
}*/
|
113
js/maze_generation.js
Normal file
113
js/maze_generation.js
Normal file
|
@ -0,0 +1,113 @@
|
|||
function generate_maze(cols, rows) {
|
||||
var maze = Array(cols*rows);
|
||||
|
||||
for (var j = 0; j < rows; j++) {
|
||||
for (var i = 0; i < cols; i++) {
|
||||
var index = getIndex(i, j, cols);
|
||||
maze[index] = new Cell(i, j);
|
||||
}
|
||||
}
|
||||
|
||||
var stack = Array();
|
||||
var current = maze[0];
|
||||
current.visited = true;
|
||||
|
||||
while (true) {
|
||||
var next = current.choose_neighbor(maze, cols, rows);
|
||||
if (next) {
|
||||
stack.push(current);
|
||||
current = current.remove_walls(next);
|
||||
current.visited = true;
|
||||
} else if (stack.length > 0) {
|
||||
current = stack.pop();
|
||||
}
|
||||
|
||||
var visitedAll = true;
|
||||
for (var i = 0; i < maze.length; i++) {
|
||||
if (!maze[i].visited) {
|
||||
visitedAll = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (visitedAll && current == maze[0]) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return maze;
|
||||
}
|
||||
|
||||
class Cell {
|
||||
constructor(x, y) {
|
||||
this.i = x;
|
||||
this.j = y;
|
||||
this.visited = false;
|
||||
this.walls = [true, true, true, true];
|
||||
this.previous = undefined;
|
||||
}
|
||||
|
||||
choose_neighbor(maze, cols, rows) {
|
||||
var neighbors = Array();
|
||||
|
||||
for (var i = -1; i < 2; i++) {
|
||||
if (i != 0) {
|
||||
var x_n_x = this.i+i;
|
||||
var x_n_y = this.j;
|
||||
var x_n_isInCols = x_n_x >= 0 && x_n_x < cols;
|
||||
var x_n_isInRows = x_n_y >= 0 && x_n_y < rows;
|
||||
if (x_n_isInCols && x_n_isInRows) {
|
||||
var x_n_index = x_n_x+x_n_y*cols;
|
||||
var x_neighbor = maze[x_n_index];
|
||||
if (!x_neighbor.visited) {
|
||||
neighbors.push(x_neighbor);
|
||||
}
|
||||
}
|
||||
|
||||
var y_n_x = this.i;
|
||||
var y_n_y = this.j+i;
|
||||
var y_n_isInCols = y_n_x >= 0 && y_n_x < cols;
|
||||
var y_n_isInRows = y_n_y >= 0 && y_n_y < rows;
|
||||
if (y_n_isInCols && y_n_isInRows) {
|
||||
var y_n_index = y_n_x+y_n_y*cols;
|
||||
var y_neighbor = maze[y_n_index];
|
||||
if (!y_neighbor.visited) {
|
||||
neighbors.push(y_neighbor);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (neighbors.length > 0) {
|
||||
var random_neighbor_index = Math.floor(Math.random()*neighbors.length);
|
||||
var random_neighbor = neighbors[random_neighbor_index];
|
||||
|
||||
return random_neighbor;
|
||||
}
|
||||
}
|
||||
|
||||
remove_walls(other) {
|
||||
var x_w = other.i - this.i;
|
||||
if (x_w == 1) {
|
||||
this.walls[1] = false;
|
||||
other.walls[3] = false;
|
||||
} else if (x_w == -1) {
|
||||
this.walls[3] = false;
|
||||
other.walls[1] = false;
|
||||
}
|
||||
|
||||
var y_w = other.j - this.j;
|
||||
if (y_w == 1) {
|
||||
this.walls[2] = false;
|
||||
other.walls[0] = false;
|
||||
} else if (y_w == -1) {
|
||||
this.walls[0] = false;
|
||||
other.walls[2] = false;
|
||||
}
|
||||
|
||||
return other;
|
||||
}
|
||||
}
|
||||
|
||||
function getIndex(x, y, w) {
|
||||
return x + y * w;
|
||||
}
|
72
js/maze_solving.js
Normal file
72
js/maze_solving.js
Normal file
|
@ -0,0 +1,72 @@
|
|||
function solve_maze(maze, cols, rows, start, end) {
|
||||
var path = Array();
|
||||
var openSet = Array(start);
|
||||
var closedSet = Array();
|
||||
|
||||
var solved = false;
|
||||
while (!solved) {
|
||||
for (var i = openSet.length-1; i >= 0; i--) {
|
||||
var current = openSet[i];
|
||||
if (current == end) {
|
||||
if (path.length == 0) {
|
||||
path.push(current);
|
||||
var temp = current.previous;
|
||||
while (true) {
|
||||
if (temp != start) {
|
||||
path.push(temp);
|
||||
temp = temp.previous;
|
||||
} else {
|
||||
path.push(start);
|
||||
solved = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
} else {
|
||||
for (var j = 0; j < current.walls.length; j++) {
|
||||
if (!current.walls[j]) {
|
||||
var neighbor_index = indexFromWall(current, j, cols);
|
||||
if (neighbor_index > -1) {
|
||||
var neighbor = maze[neighbor_index];
|
||||
var isInSet = false;
|
||||
for (var k = 0; k < closedSet.length; k++) {
|
||||
if (neighbor == closedSet[k]) {
|
||||
isInSet = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!isInSet) {
|
||||
neighbor.previous = current;
|
||||
openSet.push(neighbor);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
closedSet.push(current);
|
||||
openSet.splice(openSet.indexOf(current),1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
function indexFromWall(cell, wall_index, cols) {
|
||||
var index = -1;
|
||||
switch (wall_index) {
|
||||
case 0:
|
||||
index = getIndex(cell.i, cell.j-1, cols);
|
||||
break;
|
||||
case 1:
|
||||
index = getIndex(cell.i+1, cell.j, cols);
|
||||
break;
|
||||
case 2:
|
||||
index = getIndex(cell.i, cell.j+1, cols);
|
||||
break;
|
||||
case 3:
|
||||
index = getIndex(cell.i-1, cell.j, cols);
|
||||
break;
|
||||
}
|
||||
return index;
|
||||
}
|
Loading…
Reference in New Issue
Block a user