递归除法迷宫生成返回错误

问题描述

我正在使用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]