HTML5实现的迷宫地图随机生成器

很多小朋友喜欢用笔在纸上画线进行走迷宫游戏。
比如下图这种迷宫:从标注了s(start-起点)的位置出发,走到终点e(end)就算成功。
-->
#toolbar {
position: absolute;
padding:2px;
top:0;
right:0;
width:180px;
}
#toolbar button {
padding:10px;
font-size:16px;
margin:5px;
}
迷宫的轮廓模型生成逻辑位于代码maze.js里:
use strict;
var maze = function(options) {
for (var p in options) {
this[p] = options[p];
}
};
maze.prototype = {
constructor: maze,
width: 0,
height: 0,
grid: null,
startnode: null,
endnode: null,
// 是否每走一步, 都尝试回溯.
alwaysbacktrace: false,
init: function() {
this.trace = [];
this.size = this.width * this.height;
this.initgrid();
this.oninit();
},
initgrid: function() {
var grid = this.grid = [];
for (var r = 0; r < this.height; r++) {
var row = [];
grid.push(row);
for (var c = 0; c < this.width; c++) {
var node = {
x: c,
y: r,
value: 0,
};
row.push(node);
}
}
},
oninit: function() {},
random: function(min, max) {
return ((max - min + 1) * math.random() + min) >> 0;
},
getnode: function(c, r) {
return this.grid[r][c];
},
getrandomnode: function() {
var r = this.random(0, this.height - 1);
var c = this.random(0, this.width - 1);
return this.grid[r][c];
},
setmark: function(node, value) {
return node.value |= value;
},
removemark: function(node, value) {
return node.value &= ~value;
},
ismarked: function(node, value) {
return (node.value & value) === value;
},
setstart: function(c, r) {
var node = this.grid[r][c];
this.startnode = node;
},
setend: function(c, r) {
var node = this.grid[r][c];
this.endnode = node;
},
setcurrent: function(node) {
this.current = node;
this.neighbors = this.getvalidneighbors(node);
if (this.neighbors && node.value === 0) {
this.trace.push(node);
this.ontrace(node);
}
},
ontrace: function(node) {
},
moveto: function(node, dir) {
this.beforemove(node);
this.current.value |= dir;
this.setcurrent(node);
node.value |= maze.direction.opposite[dir];
this.aftermove(node);
},
beforemove: function(node) {
},
aftermove: function(node) {
},
start: function() {
this.beforestart();
this.setcurrent(this.startnode);
this.stepcount = 0;
while (this.nextstep()) {
this.stepcount++;
if (this.isover() === true) {
break;
}
// console.log(step);
}
console.log(step count : + this.stepcount);
},
beforestart: function() {},
// 生成迷宫时的提前终止条件
isover: function() {},
nextstep: function() {
if (!this.neighbors) {
return this.backtrace();
}
var n = this.getneighbor();
this.moveto(n[0], n[1]);
this.updatecurrent();
return true;
},
backtrace: function() {
var len = this.trace.length;
while (len > 0) {
var idx = this.gettraceindex();
var node = this.trace[idx];
var n = this.getvalidneighbors(node);
if (n) {
this.current = node;
this.neighbors = n;
return true;
} else {
this.trace.splice(idx, 1);
len--;
}
}
return false;
},
/***************************************
通过重写以下几个方法, 可以实现不同的迷宫效果
**************************************/
getvalidneighbors: function(node) {
var n = [];
var c = node.x;
var r = node.y;
var nearnode, dir;
nearnode = r > 0 this.grid[r - 1][c] : null;
dir = maze.direction.n;
this.isvalid(nearnode, node, dir) && n.push([nearnode, dir]);
nearnode = this.grid[r][c + 1];
dir = maze.direction.e;
this.isvalid(nearnode, node, dir) && n.push([nearnode, dir]);
nearnode = r < this.height - 1 this.grid[r + 1][c] : null;
dir = maze.direction.s;
this.isvalid(nearnode, node, dir) && n.push([nearnode, dir]);
nearnode = this.grid[r][c - 1];
dir = maze.direction.w;
this.isvalid(nearnode, node, dir) && n.push([nearnode, dir]);
n = this.updateneighbors(node, n);
return n.length > 0 n : null;
},
updateneighbors: function(node, neighbors) {
return neighbors;
},
isvalid: function(nearnode, node, dir) {
return nearnode && nearnode.value === 0;
},
updatecurrent: function() {
if (this.alwaysbacktrace) {
this.backtrace();
}
},
getneighbor: function() {
var n = this.neighbors[this.neighbors.length * math.random() >> 0];
return n;
},
gettraceindex: function() {
var idx = this.trace.length - 1;
return idx;
},
};
maze.direction = {
n: 1,
s: 2,
e: 4,
w: 8,
opposite: {
1: 2,
2: 1,
4: 8,
8: 4
},
stepx: {
1: 0,
2: 0,
4: 1,
8: -1
},
stepy: {
1: -1,
2: 1,
4: 0,
8: 0
},
};
迷宫的渲染位于脚本文件main.js里:
var maze = new maze({
width: 60,
height: 40,
perfect: true,
oninit: function() {
this.checkcount = {};
this.foundendnode = false;
},
isvalid: function(nearnode, node, dir) {
if (!nearnode) {
return false;
}
if (nearnode && nearnode.value === 0) {
return true;
}
if (this.perfect) {
return false;
}
var c = nearnode.x,
r = nearnode.y;
// 用于生成一种非perfect迷宫
this.checkcount[c + - + r] = this.checkcount[c + - + r] || 0;
var count = ++this.checkcount[c + - + r];
return math.random() < 0.3 && count < 3;
},
updatecurrent: function() {
// 每步有 10% 的概率 进行回溯
if (math.random() <= 0.10) {
this.backtrace();
}
},
gettraceindex: function() {
// 按一定的概率随机选择回溯策略
var r = math.random();
var len = this.trace.length;
var idx = 0;
if (r < 0.5) {
idx = len - 1;
} else if (r < 0.7) {
idx = len >> 1;
} else if (r < 0.8) {
idx = len * math.random() >> 0;
}
return idx;
},
isover: function() {
if (this.current == this.endnode) {
this.foundendnode = true;
}
// 当探索到迷宫终点, 且探索了至少一半的区域时,终止迷宫的生成
if (this.foundendnode && this.stepcount >= this.size / 2) {
return true;
}
return false;
}
});
window.onload = function() {
start();
}
function createperfectmaze() {
createmaze(true);
}
function createmaze(perfect) {
maze.perfect = perfect || false;
maze.init();
// maze.setstart(0, 0);
// maze.setend(4, 4);
maze.startnode = maze.getrandomnode();
do {
maze.endnode = maze.getrandomnode();
} while (maze.startnode == maze.endnode);
maze.start();
rendermaze(context, maze);
}
function $id(id) {
return document.getelementbyid(id);
}
var canvas, context;
function start() {
canvas = $id(canvas);
context = canvas.getcontext(2d);
createmaze(true);
}
function rendermaze(context, maze) {
// var grid = json.parse(json.stringify(maze.grid));
var grid = maze.grid;
var wallwidth = 2;
var cellsize = 15;
var width = cellsize * maze.width;
var height = cellsize * maze.height;
var x = 10,
y = 10;
canvas.width = width + wallwidth + x * 2;
canvas.height = height + wallwidth + y * 2;
context.fillstyle = #eeeeee;
context.fillrect(0, 0, canvas.width, canvas.height);
context.fillstyle = #334466;
context.strokestyle = #334466;
context.font = 12px arial;
context.linewidth = wallwidth;
for (var r = 0; r < grid.length; r++) {
var row = grid[r];
for (var c = 0; c < row.length; c++) {
var node = row[c];
var cx = c * cellsize + x;
var cy = r * cellsize + y;
if (!node.value) {
context.fillrect(cx, cy, cellsize, cellsize);
continue;
}
if (node == maze.startnode) {
context.filltext(s, cx + cellsize * 1 / 3, cy + cellsize - 2);
} else if (node == maze.endnode) {
context.filltext(e, cx + cellsize * 1 / 3, cy + cellsize - 2);
} else {
}
var left = (node.value & maze.direction.w) !== maze.direction.w;
var top = (node.value & maze.direction.n) !== maze.direction.n;
if (left && top) {
context.fillrect(cx, cy, wallwidth, cellsize);
context.fillrect(cx, cy, cellsize, wallwidth);
} else if (left) {
context.fillrect(cx, cy, wallwidth, cellsize);
} else if (top) {
context.fillrect(cx, cy, cellsize, wallwidth);
} else {
var w = false;
if (r > 0) {
w = (grid[r - 1][c].value & maze.direction.w) !== maze.direction.w;
}
if (w && c > 0) {
w = (grid[r][c - 1].value & maze.direction.n) !== maze.direction.n;
}
var ltc = w 1 : 0;
if (ltc) {
context.fillrect(cx, cy, wallwidth, wallwidth);
}
}
}
}
context.fillrect(x, cellsize * maze.height + y, cellsize * maze.width, wallwidth);
context.fillrect(cellsize * maze.width + x, y, wallwidth, cellsize * maze.height + wallwidth);
}


海旭 微商热销祖传黑膏药贴牌加工 冷敷贴OEM贴牌
江西橡胶棒价格 屠宰场用脱毛棒直销 鸽子鹌鹑天然橡胶拔毛棒
邗江区黄金回收之黄金回收多少钱一克
超能量 环保 5号 7号碳性电池 电子钟碳性电池
中频点焊机_中频点焊机厂家_东光县振东焊接设备制造有限公司
HTML5实现的迷宫地图随机生成器
200款图纸选2款,农村建房就是要百里挑一,让你与众不同!
智能家居加盟多少钱 选择荣事达智能家居怎么样
曲江附近幼儿英语、小升初英语听力、青少儿英语早教培训机构排名
Mo钼靶 耐高温钼靶 钼板 钼丝 钼棒 钼坩埚 钼舟
河南玻璃清洗机厂家-精湛技术-业内精英
中南艺考美术培训暑假班哪里有培训的
鸡血石的鉴别方法
北京PE给水管材管件一般多少钱,宏信
泡沫箱 鑫源泡沫箱厂 泡沫箱的使用条件
山东明美电动车铝框架数控加工设备厂家 山东明美.品质保证
模特培训真的很辛苦吗
厂家直销 螺旋毛刷 尼龙刷滚 毛刷辊 工业毛刷 可加工定制
金刚捨利子该去哪里鉴定
seo网站排名优化-众赢天下(图)-专业seo网站排名优化