迷宫 动画 java_HTML5 迷宫生成算法动画

本文介绍了一个使用JavaScript编写的迷宫生成器,该生成器利用HTML和CSS在网页上绘制迷宫,并通过JavaScript控制迷宫的生成过程。文章详细解释了如何创建迷宫的基本结构,包括墙壁和通道,并演示了如何通过随机选择邻居来逐步生成完整的迷宫。

JavaScript

语言:

JaveScriptBabelCoffeeScript

确定

var maze = document.querySelector("#maze"),

playButton = document.querySelector("#play-maze"),

stepButton = document.querySelector("#step-maze"),

resetButton = document.querySelector("#reset-maze"),

numCols = 5,

numRows = numCols,

width = maze.clientWidth, // width of padding-box

height = maze.clientHeight, // height of padding-box

workingWidth = width / numCols,

workingHeight = height / numRows,

boxWidth = workingWidth * .9,

boxHeight = workingHeight * .9,

// recall that there are numRows - 1 borders per col

smallDimension = (width - boxWidth * numRows) / (numRows - 1),

// true indicates unexplored

row = Array.apply(null, {length : numCols}).map(function(){return { unexplored: true, node: null}; }),

// call slice to create deep copy

grid = Array.apply(null, {length: numRows}).map(function(dontcare, j){

// deep copy the value of each row

return Array.prototype.slice.call(row).map(function(el, i){

return {unexplored: el.unexplored, node: el.unexplored, y: j, x: i};

});

}),

/**

* @function shuffle

*

* uses Fisher-Yates_shuffle

* To shuffle an array a of n elements (indices 0..n-1):

* for i from n − 1 downto 1 do

* j ← random integer with 0 ≤ j ≤ i

* exchange a[j] and a[i]

*

* @param Array

* @return arr // Note that we are modifiying in place, so you don't have to use return value

*/

shuffle = function(arr) {

var j , temp;

for (var i = arr.length - 1; i > 0; i-- ) {

j = Math.floor( Math.random() * i + 1) - 1;

temp = arr[j];

arr[j] = arr[i];

arr[i] = temp;

}

return arr;

},

NORTH = 1,

SOUTH = 2,

EAST = 3,

WEST = 4,

// stack implementation variables

stack = [],

layoutGrid = function() {

var i = 0,

j = 0,

hBoundary = numCols - 1,

vBoundary = numRows - 1,

rightX = boxWidth,

rightY = 0,

bottomX = 0,

bottomY = boxHeight,

div;

// go vertically

for (j = 0; j < numRows; j++) {

// traverse horizontally

for (i = 0; i < numCols; i++) {

// drawBox;

div = document.createElement("div");

div.style.position = "absolute";

div.style.width = boxWidth + "px";

div.style.height = boxHeight + "px";

div.style.left = bottomX + "px";

div.style.top = rightY + "px";

div.style.backgroundColor = "#222";

maze.appendChild(div);

grid[j][i].node = div;

// haven't hit horizontal boundary

if (i < hBoundary) {

div = document.createElement("div");

div.style.backgroundColor = "black";

div.style.position = "absolute";

div.style.width = smallDimension + "px";

// TODO: optimize

// right now we are using overflow: hidden to hide extra fluff

// if we are not rendering top row

// adjust positioning to account for corners

if (j > 0) {

div.style.height = boxHeight + (2 * smallDimension) + "px";

div.style.top = rightY - smallDimension + "px";

} else {

div.style.height = boxHeight + smallDimension + "px";

div.style.top = rightY + "px";

}

div.style.left = rightX + "px";

maze.appendChild(div);

grid[j][i].rightBorderNode = div;

rightX += boxWidth + smallDimension;

}

// haven't hit vertical boundary

if (j < vBoundary) {

div = document.createElement("div");

div.style.backgroundColor = "black";

div.style.position = "absolute";

// TODO: optimize

// right now we are using overflow: hidden to hide extra fluff

// if we are not rendering leftmost column

// adjust positioning to account for corners

if (i > 0) {

div.style.left = bottomX - smallDimension + "px";

div.style.width = boxWidth + (2 * smallDimension) + "px";

} else {

div.style.left = bottomX + "px";

div.style.width = boxWidth + smallDimension + "px";

}

div.style.height = smallDimension + "px";

div.style.top = bottomY + "px";

maze.appendChild(div);

grid[j][i].bottomBorderNode = div;

}

// move out of if statement because we need to layout out boxes

bottomX += boxWidth + smallDimension;

}

bottomX = 0;

bottomY += boxHeight + smallDimension;

rightY += boxHeight + smallDimension;

rightX = boxWidth;

}

},

getNeighbors = function(y, x) {

var neighbors = [];

if (y - 1 > 0) {

neighbors.push({

cell: grid[y - 1][x],

name: NORTH

});

}

if (y + 1 < numRows) {

neighbors.push({

cell: grid[y + 1][x],

name: SOUTH

});

}

if (x + 1 < numCols) {

neighbors.push({

cell: grid[y][x + 1],

name: EAST

})

}

if (x - 1 > 0) {

neighbors.push({

cell: grid[y][x - 1],

name: WEST

});

}

return neighbors;

};

reset = function() {

grid.forEach(function(row) {

row.forEach(function(el){

el.unexplored = true;

el.node = null;

el.bottomBorderNode = null;

el.rightBorderNode = null;

});

});

maze.innerHTML = "";

layoutGrid();

stack.push({cell: grid[0][0], neighbors: shuffle(getNeighbors(0,0))});

},

step = function() {

var curCellData,

curCell,

y,

x,

neighbors,

nbr,

style,

styleAdjustProp,

wall;

if (stack.length) {

curCellData = stack.pop();

curCell = curCellData.cell;

y = curCell.y;

x = curCell.x;

// indicate as explored

curCell.node.style.backgroundColor = "lime";

curCell.unexplored = false;

neighbors = curCellData.neighbors;

// find unexplored neighbor

while ((nbr = neighbors.pop()) && nbr.cell && !nbr.cell.unexplored) {};

if (nbr) {

// remove wall

if (nbr.name === NORTH ) {

wall = nbr.cell.bottomBorderNode;

nbr.cell.bottomBorderNode = null;

styleAdjustProp = "height"

style = nbr.cell.node.style;

} else if (nbr.name === SOUTH) {

wall = curCell.bottomBorderNode;

styleAdjustProp = "height";

curCell.bottomBorderNode = null;

style = curCell.node.style;

} else if (nbr.name === EAST) {

wall = curCell.rightBorderNode;

curCell.rightBorderNode = null;

styleAdjustProp = "width";

style = curCell.node.style;

} else {

wall = nbr.cell.rightBorderNode;

nbr.cell.rightBorderNode = null;

styleAdjustProp = "width";

style = nbr.cell.node.style;

}

if (wall) {

wall.parentNode.removeChild(wall);

style[styleAdjustProp] = parseFloat(style[styleAdjustProp]) + smallDimension + "px";

}

// push cell back even if there are no neighbors left

// so that we can indicate backtracking

stack.push(curCellData);

// push cell of neighbors

nbr.cell.unexplored = false;

stack.push({cell: nbr.cell, neighbors: shuffle(getNeighbors(nbr.cell.y, nbr.cell.x))});

} else {

// indicate backtracking

curCell.node.style.backgroundColor = "white";

}

return true;

} else {

return false;

}

},

setButtonsInactive = function() {

playButton.classList.remove("active");

stepButton.classList.remove("active");

},

resetButtons = function() {

playButton.classList.add("active");

stepButton.classList.add("active");

},

loop = function() {

if (step()) {

setTimeout(loop, 50);

} else {

setButtonsInactive();

}

};

stack.push({cell: grid[0][0], neighbors: shuffle(getNeighbors(0, 0))});

layoutGrid();

playButton.addEventListener("click", function(e){

e.preventDefault();

e.stopPropagation();

loop();

});

stepButton.addEventListener("click", function(e){

e.preventDefault();

e.stopPropagation();

if (!step()) {

setButtonsInactive();

}

});

resetButton.addEventListener("click", function(e){

e.preventDefault();

e.stopPropagation();

reset();

resetButtons();

});

loop();

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值