递归除法迷宫生成算法

Posted

技术标签:

【中文标题】递归除法迷宫生成算法【英文标题】:Recursive Division Maze Generation Algorithm 【发布时间】:2014-02-13 08:23:49 【问题描述】:

我目前正在处理,我想我快到了。我目前有一个二维数组,20 个单元格宽,15 个单元格高。该数组包含单元格对象,其中包含行、列和一个布尔变量以指示它是否是一堵墙。

每当我取消评论时

generateMaze(height, maxWidth-randomColumn, 1, randomColumn+1);

我得到一个堆栈溢出。没有它,它只会向左和向上遍历,我需要让它也向右和向下遍历。我已经盯着这个看了很长时间,想弄清楚为什么,但就是看不出来。

编辑:我现在可以生成一些东西,但是迷宫经常被阻塞,即有路径被阻塞。所以如果我设置一个随机的起始位置,它可能会被墙包围。

    private void generateMaze(int minColumn, int maxColumn, int minRow, int maxRow)

        int width  = maxColumn - minColumn;
        int height = maxRow-minRow;

        if (width > 2 && height > 2)
            if ("VERTICAL".equals(getOrientation(height, width)))
                splitVertical(minColumn, maxColumn, minRow, maxRow);
            
            else
                splitHorizontal(minColumn, maxColumn, minRow, maxRow);
            
        
    

    private void splitVertical (int minColumn, int maxColumn, int minRow, int maxRow)
        int randomColumn = getRandomNumber(minColumn, maxColumn);
        for (int i= minRow; i < maxRow; i++)
            maze[i][randomColumn] = new Cell (i+1, randomColumn+1, true);
        
        maze[(getRandomNumber(minRow, maxRow))][randomColumn].setWall(false);

        generateMaze(minColumn, randomColumn, minRow, maxRow);
        generateMaze(randomColumn, maxColumn, minRow, maxRow);
    

     private void splitHorizontal (int minColumn, int maxColumn, int minRow, int maxRow)
        int randomRow = getRandomNumber(minRow, maxRow);
        for (int i = minColumn; i < maxColumn; i++)
            maze[randomRow][i] = new Cell (randomRow+1, i+1, true);
        
        generateMaze(minColumn, maxColumn, minRow, randomRow);
        generateMaze(minColumn, maxColumn, randomRow, maxRow);
    



    private String getOrientation(int height, int width) 
        Random rand = new Random();
        if (height > width)
            return "HORIZONTAL";
         else if (width > height)
            return "VERTICAL";
         else 
            int randomNumber = rand.nextInt(2);
            if (randomNumber == 0)
                return "HORIZONTAL";
             else
                return "VERTICAL";
            
        
    

    private int getRandomNumber(int x, int y)
        int minimum = x;
        int maximum = y;
        int randomNumber = 0;
        Random rand = new Random();
        randomNumber = rand.nextInt((maximum-minimum)+1)+ minimum;
        return randomNumber;
    

【问题讨论】:

【参考方案1】:

编辑:我注意到你在开始时有停止条件。我的错。

如果代码无限运行,请添加一些调试打印,以查看递归的进度。似乎宽度和高度没有正确更新。也许您计算的尺寸不正确?

我没有全面检查算法,但一般问题是没有停止条件。

在递归函数中你总是递归的。错了,你必须检查你是否需要再深入一步。

如果遇到问题,在递归函数中,您必须检查剩下的板是否仍然可整除。如果函数中还剩下 1x1 网格,那就死路一条了。

【讨论】:

当我做 width >= 10 时,它在没有 *** 的情况下运行,但从 9 开始它会开始生成 ***,依此类推。男人.. :(【参考方案2】:

在您取消注释的以下行中:

generateMaze(height, maxWidth-randomColumn, 1, randomColumn+1);

您正在使用允许值内的随机值调用递归函数,因此它将无限递归,因为大小不会减小,因此您永远不会满足您的停止条件:

if (height >= 2 && width >= 2)

你为什么用随机值调用它?也许正如 jnovacho 建议的那样,您应该添加另一个条件,例如,最大递归级别或类似的东西......

作为建议,尝试在 Eclipse 中调试您的代码,如果可能,添加一些 UnitTests 来检查您测试过的配置是否仍然有效...

【讨论】:

代码已编辑,没有更多的***,只是不准确。【参考方案3】:

编辑

你的新代码好多了,但还是有问题:

您没有在splitHorizontal 中创建墙缝。 您的意思可能是循环到i &lt;= maxRowi &lt;= maxColumn,而不是严格比创建墙时少。 正如我在之前的编辑中提到的,您仍在用新墙(无论是平行还是垂直)堵住现有墙壁中的缝隙。

正如其他人所建议的,您的递归不正确。您要拆分的尺寸未正确收缩。您有时也会忽略您传递的信息。

不正确的递归

最小高度和宽度被丢弃并替换为1,宽度被丢弃并替换为maxWidth

generateMaze(height, randomColumn-1, 1, 1);
//generateMaze(height, maxWidth-randomColumn, 1, randomColumn+1);

当第二次调用被注释时,宽度或高度最终会随机下降到2以下,结束递归。然而,当取消注释时,这两个调用之一肯定会有width &gt;= 2(因为maxWidth == 18 &gt; 3)。递归提前结束的可能性很小,但这只是因为您尚未以与 "VERTICAL" 案例相同(不正确)的方式在 "HORIZONTAL" 案例中实现第二个递归调用。

您的代码中对于参数heightwidthmHeightmWidth 的确切含义似乎有些混淆。一组替代的函数参数可以帮助你推理它:

private void generateMaze(int startRow, int startCol, int endRow, int endCol)
    //...

忽略传递的信息

专注于"VERTICAL" 案例。您为墙选择的列不尊重分区:

int randomColumn = getRandomNumber(mWidth, maxWidth);

mWidth 始终 1,maxWidth 始终 18,即使您已经分区。同样,您可能会将间隙放置在墙外:

for (int i = minHeight; i <= height; i++)
    maze[i][randomColumn] = new Cell (i+1, randomColumn+1, true);

//Make random passage in the column
maze[rand.nextInt(height)+1][randomColumn].setWall(false);

rand.nextInt(height)+1 可能小于minHeight

小问题

还有其他一些潜在的问题:

从风格上讲,enumstring 更有意义,因为 getOrientation 的返回值。 墙可以与现有墙相邻(并与之平行)放置。 即使是直角,一堵墙也可能挡住现有墙的间隙或通道。 当任一 heightwidth 高于其阈值时,递归应该继续,而不仅仅是两者

【讨论】:

@user2472706 我已经用 cmets 更新了关于新代码的信息,不过对我来说这似乎是一个不同的问题了。

以上是关于递归除法迷宫生成算法的主要内容,如果未能解决你的问题,请参考以下文章

谁能解释这个除法算法是如何工作的?

辗转相除法

求两个数的最大公约数,辗转相除法与更相减损法(递归迭代)

生成随机迷宫--深度优先(递归回溯)算法

欧几里得算法(辗转相除法)计算最大公约数

四种迷宫生成算法