[英]Recursive division maze generation is returning error
我正在使用 JavaScript 構建應用程序,並嘗試使用遞歸除法方法生成迷宮。 迷宮是在 anxm 矩陣中生成的,其中 m > n 和 n 是高度,m 是寬度。 在矩陣中,牆占據了矩陣[y][x] position(它們不是矩陣中點之間的薄壁壘)。 我以此為指導: 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, 0, 0, width, height, HORIZONTAL);
return wallNodes;
}
function divide(wallNodes, row, col, width, height, 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;
}
我已經多次仔細檢查了我的代碼,這對我來說似乎是正確的。 但是,每當我運行它時,我都會收到一條錯誤消息:“超出最大調用堆棧大小”。 我不知道無限遞歸發生在哪里。
任何幫助將不勝感激!
更多關於迷宮的話題:如果我想創建一個吸引眼球的迷宮,牆壁均勻分布,迷宮看起來像這樣。 遞歸除法是最好的方法嗎? 遞歸划分方法中牆壁的放置位置存在隨機性,恐怕它輸出的迷宮不會吸引人。
更新:編輯除法 function。 超過最大堆棧的問題現在消失了。 然而,迷宮中的牆壁是組合在一起的,因此有時會有不止一堵牆垂直相鄰,從而形成一堵有兩個節點厚的牆。 我現在正在嘗試解決這個問題。
在 javascript 中,遞歸與async 和 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, 0, 0, width, height, HORIZONTAL); return wallNodes; } async function divide(wallNodes, row, col, width, height, 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; }
編輯:這里我在異步除法 function 中添加了setTimeout
以便兩個遞歸有時間清除堆棧,1000 意味着 1 秒您可以根據網格大小減少或增加它,我用[200000,200000]
的網格大小測試了這個
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.