递归分割迷宫生成算法

时间:2014-02-13 08:23:50

标签: java recursion tail-recursion maze

我目前在处理制作递归分割迷宫生成算法,我想我差不多了。我目前有一个二维阵列,20个细胞宽,15个细胞高。该数组包含单元格对象,它包含行,列和布尔变量,以指示它是否为墙。

什么时候取消注释

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

我得到一个stackoverflow。没有它,它只会向左和向上移动,我需要让它正向和向下移动。我已经长时间盯着这个找出原因,但却看不到这样做。

编辑:我现在可以生成一些内容,但迷宫经常被阻止,也就是说,有些路径被阻止了。因此,如果我设置一个随机起始位置,它可能会被墙包围。

    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;
    }
}

3 个答案:

答案 0 :(得分:0)

编辑:我注意到你在开始时有停止状态。我的坏。

如果代码无限添加一些调试打印,则可以看到回顾的进度。似乎宽度和高度没有正确更新。也许你错误地计算了尺寸?

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

在递归函数中,你总是递归。那是错的,你必须检查你是否还需要再做一步。

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

答案 1 :(得分:0)

在以下行中取消注释:

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

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

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

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

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

答案 2 :(得分:0)

修改

您的新代码要好得多,但仍存在问题:

  • 您没有在splitHorizontal
  • 中创建墙隙
  • 您可能想要循环到i <= maxRowi <= maxColumn,而不是严格小于创建墙壁时。
  • 正如我在之前的编辑中提到的那样,你仍然用新的墙壁(无论是平行还是垂直)阻挡现有墙壁的间隙。

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

递归错误

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

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

当第二个调用被注释时,宽度或高度最终会随机下降到2以下,从而结束递归。但是,当取消注释时,这两个调用中的一个肯定会有width >= 2(从maxWidth == 18 > 3开始)。递归很有可能在早期结束,但仅仅是因为你还没有在"HORIZONTAL"情况下以"VERTICAL"案例的相同(不正确)方式实现第二次递归调用

您的代码中似乎有一些关于参数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更有意义。
  • 墙可以放置在现有墙附近(并与之平行)。
  • 即使是直角,墙壁也可能阻挡现有墙壁的间隙或通道。
  • <{em> heightwidth高于其阈值时,递归应该继续,不仅