问题描述
我正在使用JavaScript构建应用程序,并尝试使用递归除法方法生成迷宫。在n x m矩阵中生成迷宫,其中m> n,n是高度,m是宽度。在矩阵中,墙占据矩阵[y] [x]的位置(它们不是矩阵中各点之间的薄屏障)。我以此为指导:http://weblog.jamisbuck.org/2011/1/12/maze-generation-recursive-division-algorithm。
我的代码如下:
const HORIZONTAL = "HORIZONTAL";
const VERTICAL = "VERTICAL";
// this function gets called first
function GenerateRecursiveDivisionMaze(grid) {
let height = grid.length;
let width = grid[0].length;
// all the positions of the walls in the matrix
let wallNodes = [];
divide(wallNodes,width,height,HORIZONTAL);
return wallNodes;
}
function divide(wallNodes,row,col,direction) {
if (width < 3 || height < 3) return;
let horizontal = direction === HORIZONTAL;
// start position of the wall,change col and row?
let wallPositionX = x + (horizontal ? 0 : generaterandomNumber(0,width - 2));
let wallPositionY =
y + (horizontal ? generaterandomNumber(0,height - 2) : 0);
// passage in the wall
let passageX =
wallPositionX + (horizontal ? generaterandomNumber(0,width) : 0);
let passageY =
wallPositionY + (horizontal ? 0 : generaterandomNumber(0,height));
// direction of wall
let directionX = horizontal ? 1 : 0;
let directionY = horizontal ? 0 : 1;
// how long will the wall be
let length = horizontal ? width : height;
// build the wall
for (let i = 0; i < length; i++) {
wallPositionY += directionY;
wallPositionX += directionX;
let y = wallPositionY;
let x = wallPositionX;
// make everything a wall except the designated passage
if (passageX !== x || passageY !== y) {
let node = {
row: y,col: x,};
wallNodes.push(node);
}
}
let nextHeight = horizontal ? wallPositionY - y + 1 : height;
let nextWidth = horizontal ? width : wallPositionX - x + 1;
let nextDirectionToSlice = getDirectionToSlice(nextWidth,nextHeight);
let nextX = x;
let nextY = y;
// recurse for the left and top side of the wall:
divide(wallNodes,nextX,nextY,nextWidth,nextHeight,nextDirectionToSlice);
// recurse right or bottom
let nextX2 = horizontal ? x : wallPositionX + 1;
let nextY2 = horizontal ? wallPositionY + 1 : y;
let nextHeight2 = horizontal ? y + height - wallPositionY - 1 : height;
let nextWidth2 = horizontal ? width : x + width - wallPositionX - 1;
let nextDirectionToSlice2 = getDirectionToSlice(nextWidth2,nextHeight2);
// recurse for the right and bottom side of the wall:
divide(
wallNodes,nextX2,nextY2,nextWidth2,nextHeight2,nextDirectionToSlice2
);
}
function getDirectionToSlice(width,height) {
if (width > height) {
return VERTICAL;
} else if (height > width) {
return HORIZONTAL;
} else {
return generaterandomNumber(0,1) == 0 ? HORIZONTAL : VERTICAL;
}
}
// Generate a random number between lowNum and highNum
function generaterandomNumber(lowNum,highNum) {
return Math.floor(Math.random() * (highNum - lowNum + 1)) + lowNum;
}
我已经多次仔细检查过我的代码,这对我来说似乎是正确的。但是,无论何时运行它,我都会收到一条错误消息:“超出了最大调用堆栈大小”。我不知道无限递归在哪里发生。
任何帮助将不胜感激!
有关迷宫的更多信息:如果我试图生成一个吸引眼球的迷宫,该迷宫的墙壁均匀分布,迷宫看起来something like this。递归除法是最好的方法吗?递归分割方法中将壁放置在哪里有一个随机性,恐怕它输出的迷宫不会吸引人。
更新:编辑了除法功能。超过最大堆栈数的问题现在消失了。但是,迷宫中的墙壁会聚在一起,因此有时垂直方向上会有不止一个墙壁彼此相邻,从而使墙壁厚了两个节点。我现在正在尝试解决这个问题。
解决方法
在javascript中,递归与async and await函数一起使用,以便我们可以等到递归完成并返回结果。
请检查小提琴: https://jsfiddle.net/cvpwLrtn/
const HORIZONTAL = "HORIZONTAL";
const VERTICAL = "VERTICAL";
GenerateRecursiveDivisionMaze([5000,5000]).then(result => {
console.log(result);
});
// this function gets called first
async function GenerateRecursiveDivisionMaze(grid) {
let height = grid[0];
let width = grid[1];
// all the positions of the walls in the matrix
let wallNodes = [];
await divide(wallNodes,width,height,HORIZONTAL);
return wallNodes;
}
async function divide(wallNodes,row,col,direction) {
if (width <= 2 || height <= 2) return;
let vertical = direction === VERTICAL;
// start position of the wall
let wallPositionCol = vertical ? generateRandomNumber(row + 2,width - 2) : row;
let wallPositionRow = vertical ? col : generateRandomNumber(col + 2,height - 2);
// passage in the wall
let passageRow = vertical
? generateRandomNumber(col + 1,height - 1)
: wallPositionRow;
let passageCol = vertical
? wallPositionCol
: generateRandomNumber(row + 1,width - 1);
// direction of wall
let directionCol = vertical ? 0 : 1;
let directionRow = vertical ? 1 : 0;
// how long will the wall be
let length = vertical ? height : width;
// build the wall
for (let i = 0; i < length; i++) {
let row = wallPositionRow + directionRow * i;
let col = wallPositionCol + directionCol * i;
// make everything a wall except the designated passage
if (passageRow !== row || passageCol !== col) {
let node = {
row: row,col: col,};
wallNodes.push(node);
}
}
let nextHeight = vertical ? height : wallPositionRow;
let nextWidth = vertical ? wallPositionCol : width;
let nextDirectionToSlice = getDirectionToSlice(nextWidth,nextHeight);
let nextRow = row;
let nextCol = col;
// recurse for the left or top side of the wall:
setTimeout( function () {
divide(
wallNodes,nextRow,nextCol,nextWidth,nextHeight,nextDirectionToSlice,);
},1000);
// recurse right or bottom
let nextHeight2 = vertical ? height : Math.abs(height - wallPositionRow);
let nextWidth2 = vertical ? Math.abs(width - wallPositionCol) : width;
let nextDirectionToSlice2 = getDirectionToSlice(nextWidth2,nextHeight2);
let nextCol2 = vertical ? wallPositionCol : col;
let nextRow2 = vertical ? row : wallPositionRow;
setTimeout(function () {
divide(
wallNodes,nextRow2,nextCol2,nextWidth2,nextHeight2,nextDirectionToSlice2,2000)
}
function getDirectionToSlice(width,height) {
if (width > height) {
return VERTICAL;
} else if (height > width) {
return HORIZONTAL;
} else {
return generateRandomNumber(0,1) === 0 ? HORIZONTAL : VERTICAL;
}
}
// Generate a random number between lowNum and highNum
function generateRandomNumber(lowNum,highNum) {
return Math.floor(Math.random() * (highNum - lowNum + 1)) + lowNum;
}
编辑:
在这里,我在异步除法函数中添加了setTimeout
,以便两次递归都有时间清除堆栈,1000意味着1秒钟,您可以根据网格大小对其进行递减或递增,我使用[200000,200000]