【问题标题】: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;
    }
}

【问题讨论】:

    标签: java recursion tail-recursion maze


    【解决方案1】:

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

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

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

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

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

    【讨论】:

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

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

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

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

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

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

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

    【讨论】:

    • 代码已编辑,没有更多的stackoverflow,只是不准确。
    【解决方案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 更新了关于新代码的信息,不过对我来说这似乎是一个不同的问题了。
    猜你喜欢
    • 2020-12-14
    • 1970-01-01
    • 1970-01-01
    • 2014-06-25
    • 2020-05-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多