快毕业了,工作还没找到,刚好GOOGLE举办了igoogle创意大赛,正好有时间试一下,前几天做了一个豆瓣的热评获取工具,第二个是随机迷宫。在网上查了好多资料,发现国内的太少,最后终于在国外找到了一个全面介绍迷宫的页面http://www.astrolog.org/labyrnth/algrithm.htm,还有一个是迷宫生成器http://www.xefer.com/2007/07/maze,通过两天的研究,自己也弄出来了,迷宫的生成用dfs,其它算法准备也试一下好比较。
有兴趣的朋友一起研究,我把我的代码贴出来,希望大家多多指教。
Code
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title></title>
<style type="text/css">
table
{
border-collapse: collapse;
}
.cell
{
float: left;
border-right: 1px solid transparent;
border-bottom: 1px solid transparent;
margin-right: -1px;
margin-bottom: -1px;
}
.left
{
border-left: 1px solid #000000;
}
.right
{
border-right: 1px solid #000000;
}
.top
{
border-top: 1px solid #000000;
}
.bottom
{
border-bottom: 1px solid #000000;
}
.noleft
{
border-left: 1px solid transparent;
}
.noright
{
border-right: 1px solid transparent;
}
.notop
{
border-top: 1px solid transparent;
}
.nobottom
{
border-bottom: 1px solid transparent;
}
.cell
{
height: 8px;
}
.cell
{
width: 8px;
}
</style>
</head>
<body>
<div id="box">
</div>
<input type="text" id="width" />*<input type="text" id="height" />
<input type="button" onclick="createMaze()" value="生成" /> <input type="button"
onclick="findPath()" value="寻路" />
</body>
</html>
<script type="text/javascript">
var rows;
var columns;
//方向
var top = 0;
var bottom = 1;
var left = 2;
var right = 3;
//方向数组
var dirs = [0, 1, 2, 3];
var undirs = [1, 0, 3, 2];
var delta = { x: [0, 0, -1, 1], y: [-1, 1, 0, 0] };
var isShowPath = false;
//生成迷宫
function createMaze() {
rows = parseInt(document.getElementById("height").value);
columns = parseInt(document.getElementById("width").value);
//初始化迷宫数组
var maze = new Maze();
maze.init();
//dfs生成迷宫
dfsCreateMaze(maze);
//显示迷宫
showMaze(maze);
//return false;
}
//深度遍历生成迷宫
function dfsCreateMaze(maze) {
//单元格栈
var stack = new Array();
//访问起点
maze.cells[maze.start.y][maze.start.x].visited = true;
maze.visitedCount++;
//起点入栈
stack.push({ x: maze.start.x,
y: maze.start.y,
neighbors: randomArray()
});
//定义方向变量
var dir, x, y, dx, dy;
//选取邻接单元格
dir = stack[stack.length - 1].neighbors.pop();
x = stack[stack.length - 1].x;
y = stack[stack.length - 1].y;
dx = x + delta.x[dir];
dy = y + delta.y[dir];
//利用栈循环访问
while (stack.length > 0) {
if (x == maze.end.x && y == maze.end.y) {
setPath(maze, stack);
}
//如果当前方向的单元格可访问
if (dx >= 0 && dy >= 0 && dx <= (columns - 1) && dy <= (rows - 1)) {
if (maze.cells[dy][dx].visited) {
dir = stack[stack.length - 1].neighbors.pop();
x = stack[stack.length - 1].x;
y = stack[stack.length - 1].y;
dx = x + delta.x[dir];
dy = y + delta.y[dir];
}
else {
maze.cells[dy][dx].visited = true;
maze.visitedCount++;
stack.push({ x: dx,
y: dy,
neighbors: randomArray()
});
//拆除邻接单元格之间的墙
maze.cells[y][x].wall[dir] = false;
maze.cells[dy][dx].wall[undirs[dir]] = false;
//访问下一个单元格
dir = stack[stack.length - 1].neighbors.pop();
x = stack[stack.length - 1].x;
y = stack[stack.length - 1].y;
dx = x + delta.x[dir];
dy = y + delta.y[dir];
}
}
//否则选取下一个方向的单元格
else {
dir = stack[stack.length - 1].neighbors.pop();
x = stack[stack.length - 1].x;
y = stack[stack.length - 1].y;
dx = x + delta.x[dir];
dy = y + delta.y[dir];
}
//邻接单元格访问完,退栈
if (stack[stack.length - 1].neighbors.length == 0) {
stack.pop();
}
}
}
//显示迷宫
function showMaze(maze) {
//如果已显示路径则删除
var styles = document.getElementsByTagName("style");
if (styles.length >= 2) {
for (var i = 1; i < styles.length; i++) {
styles[i].parentNode.removeChild(styles[i]);
}
}
//设置出入口
maze.cells[maze.start.y][maze.start.x].wall[top] = false;
maze.cells[maze.end.y][maze.end.x].wall[bottom] = false;
//用table显示
var html = "<table cellpadding='0' cellspace='0' id='mazeBox'>";
for (var i = 0; i < rows; i++) {
html += "<tr>";
for (var j = 0; j < columns; j++) {
var classes = "";
classes += maze.cells[i][j].wall[top] ? "top " : "notop ";
classes += maze.cells[i][j].wall[bottom] ? "bottom " : "nobottom ";
classes += maze.cells[i][j].wall[left] ? "left " : "noleft ";
classes += maze.cells[i][j].wall[right] ? "right " : "noright ";
if (maze.cells[i][j].token) html += "<td class='cell token " + classes + "'>" + "</td>";
else html += "<td class='cell " + classes + "'>" + "</td>";
}
html += "</tr>";
}
var box = document.getElementById("box");
box.innerHTML = html;
}
//迷宫对象
function Maze() {
this.cells = new Array(); //保存所有单元格
this.start = { x: 0, y: 0 }; //起点
this.end = { x: columns - 1, y: rows - 1 }; //终点
this.visitedCount = 0;
//初始化
this.init = function() {
build(this);
}
//初始化单元格
function build(maze) {
for (var i = 0; i < rows; i++) {
maze.cells[i] = new Array(columns);
for (var j = 0; j < columns; j++) {
maze.cells[i][j] = new cell(j, i);
}
}
}
//单元格对象
function cell(x, y) {
this.token = false;
this.x = x; //列坐标
this.y = y; //行坐标
this.visited = false;
this.wall = [true, true, true, true]; //“墙”
}
}
//生成随机分配值的数组
function randomArray() {
var dir = [0, 1, 2, 3];
var tempDir = new Array();
for (var i = 4; i > 0; i--) {
var temp;
var index = Math.floor(Math.random() * i);
temp = dir[i - 1];
tempDir.push(dir[index]);
dir[i - 1] = dir[index];
dir[index] = temp;
}
return tempDir;
}
//设置路径
function setPath(m, s) {
isShowPath = true;
for (var i = 0; i < s.length; i++) {
m.cells[s[i].y][s[i].x].token = true;
}
}
//显示路径
function findPath() {
var sheet = document.createStyleSheet();
sheet.addRule('.token', 'background:url("breadcrumb.png") center no-repeat;');
//sheet.addRule('.token', 'background:red;');
}
</script>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title></title>
<style type="text/css">
table
{
border-collapse: collapse;
}
.cell
{
float: left;
border-right: 1px solid transparent;
border-bottom: 1px solid transparent;
margin-right: -1px;
margin-bottom: -1px;
}
.left
{
border-left: 1px solid #000000;
}
.right
{
border-right: 1px solid #000000;
}
.top
{
border-top: 1px solid #000000;
}
.bottom
{
border-bottom: 1px solid #000000;
}
.noleft
{
border-left: 1px solid transparent;
}
.noright
{
border-right: 1px solid transparent;
}
.notop
{
border-top: 1px solid transparent;
}
.nobottom
{
border-bottom: 1px solid transparent;
}
.cell
{
height: 8px;
}
.cell
{
width: 8px;
}
</style>
</head>
<body>
<div id="box">
</div>
<input type="text" id="width" />*<input type="text" id="height" />
<input type="button" onclick="createMaze()" value="生成" /> <input type="button"
onclick="findPath()" value="寻路" />
</body>
</html>
<script type="text/javascript">
var rows;
var columns;
//方向
var top = 0;
var bottom = 1;
var left = 2;
var right = 3;
//方向数组
var dirs = [0, 1, 2, 3];
var undirs = [1, 0, 3, 2];
var delta = { x: [0, 0, -1, 1], y: [-1, 1, 0, 0] };
var isShowPath = false;
//生成迷宫
function createMaze() {
rows = parseInt(document.getElementById("height").value);
columns = parseInt(document.getElementById("width").value);
//初始化迷宫数组
var maze = new Maze();
maze.init();
//dfs生成迷宫
dfsCreateMaze(maze);
//显示迷宫
showMaze(maze);
//return false;
}
//深度遍历生成迷宫
function dfsCreateMaze(maze) {
//单元格栈
var stack = new Array();
//访问起点
maze.cells[maze.start.y][maze.start.x].visited = true;
maze.visitedCount++;
//起点入栈
stack.push({ x: maze.start.x,
y: maze.start.y,
neighbors: randomArray()
});
//定义方向变量
var dir, x, y, dx, dy;
//选取邻接单元格
dir = stack[stack.length - 1].neighbors.pop();
x = stack[stack.length - 1].x;
y = stack[stack.length - 1].y;
dx = x + delta.x[dir];
dy = y + delta.y[dir];
//利用栈循环访问
while (stack.length > 0) {
if (x == maze.end.x && y == maze.end.y) {
setPath(maze, stack);
}
//如果当前方向的单元格可访问
if (dx >= 0 && dy >= 0 && dx <= (columns - 1) && dy <= (rows - 1)) {
if (maze.cells[dy][dx].visited) {
dir = stack[stack.length - 1].neighbors.pop();
x = stack[stack.length - 1].x;
y = stack[stack.length - 1].y;
dx = x + delta.x[dir];
dy = y + delta.y[dir];
}
else {
maze.cells[dy][dx].visited = true;
maze.visitedCount++;
stack.push({ x: dx,
y: dy,
neighbors: randomArray()
});
//拆除邻接单元格之间的墙
maze.cells[y][x].wall[dir] = false;
maze.cells[dy][dx].wall[undirs[dir]] = false;
//访问下一个单元格
dir = stack[stack.length - 1].neighbors.pop();
x = stack[stack.length - 1].x;
y = stack[stack.length - 1].y;
dx = x + delta.x[dir];
dy = y + delta.y[dir];
}
}
//否则选取下一个方向的单元格
else {
dir = stack[stack.length - 1].neighbors.pop();
x = stack[stack.length - 1].x;
y = stack[stack.length - 1].y;
dx = x + delta.x[dir];
dy = y + delta.y[dir];
}
//邻接单元格访问完,退栈
if (stack[stack.length - 1].neighbors.length == 0) {
stack.pop();
}
}
}
//显示迷宫
function showMaze(maze) {
//如果已显示路径则删除
var styles = document.getElementsByTagName("style");
if (styles.length >= 2) {
for (var i = 1; i < styles.length; i++) {
styles[i].parentNode.removeChild(styles[i]);
}
}
//设置出入口
maze.cells[maze.start.y][maze.start.x].wall[top] = false;
maze.cells[maze.end.y][maze.end.x].wall[bottom] = false;
//用table显示
var html = "<table cellpadding='0' cellspace='0' id='mazeBox'>";
for (var i = 0; i < rows; i++) {
html += "<tr>";
for (var j = 0; j < columns; j++) {
var classes = "";
classes += maze.cells[i][j].wall[top] ? "top " : "notop ";
classes += maze.cells[i][j].wall[bottom] ? "bottom " : "nobottom ";
classes += maze.cells[i][j].wall[left] ? "left " : "noleft ";
classes += maze.cells[i][j].wall[right] ? "right " : "noright ";
if (maze.cells[i][j].token) html += "<td class='cell token " + classes + "'>" + "</td>";
else html += "<td class='cell " + classes + "'>" + "</td>";
}
html += "</tr>";
}
var box = document.getElementById("box");
box.innerHTML = html;
}
//迷宫对象
function Maze() {
this.cells = new Array(); //保存所有单元格
this.start = { x: 0, y: 0 }; //起点
this.end = { x: columns - 1, y: rows - 1 }; //终点
this.visitedCount = 0;
//初始化
this.init = function() {
build(this);
}
//初始化单元格
function build(maze) {
for (var i = 0; i < rows; i++) {
maze.cells[i] = new Array(columns);
for (var j = 0; j < columns; j++) {
maze.cells[i][j] = new cell(j, i);
}
}
}
//单元格对象
function cell(x, y) {
this.token = false;
this.x = x; //列坐标
this.y = y; //行坐标
this.visited = false;
this.wall = [true, true, true, true]; //“墙”
}
}
//生成随机分配值的数组
function randomArray() {
var dir = [0, 1, 2, 3];
var tempDir = new Array();
for (var i = 4; i > 0; i--) {
var temp;
var index = Math.floor(Math.random() * i);
temp = dir[i - 1];
tempDir.push(dir[index]);
dir[i - 1] = dir[index];
dir[index] = temp;
}
return tempDir;
}
//设置路径
function setPath(m, s) {
isShowPath = true;
for (var i = 0; i < s.length; i++) {
m.cells[s[i].y][s[i].x].token = true;
}
}
//显示路径
function findPath() {
var sheet = document.createStyleSheet();
sheet.addRule('.token', 'background:url("breadcrumb.png") center no-repeat;');
//sheet.addRule('.token', 'background:red;');
}
</script>