簡體   English   中英

遞歸除法迷宮生成返回錯誤

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM