简体   繁体   中英

Recursive Division Maze Generation Algorithm

I currently in processing making a recursive division maze generating algorithm and I think I'm almost there. I currently have a 2-dimensional array, 20 cells wide, 15 cells tall. The array contains cell objects, which holds rows, columns and a boolean variable to indicate whether or not it's a wall.

When ever I uncomment

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

I get a stackoverflow. Without it, it will only traverse left and up, I need to make it traverse right and down as well. I've been staring at this for long time to figure out why but just cannot see to do it.

EDIT: I can generate something now, but the maze is often blocked, that is, there are paths that are blocked. So If I set up an random starting location, it might be surrounded by walls.

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

EDIT: I've noticed you have the stopping condition at the beggining. My bad.

If the code goes infinitely add some debug prints, to see progress of the recrusion. It seems that the width and height aren't updating correctly. Maybe you are calculating the dimensions incorrectly?

I didn't check the algorithm in full, but generally the problem is there is no stopping condition.

In the recursive function you always recurse. That's wrong, you have to check if you have to do another step deeper.

In case of your problem, in the recursive function, you have to check if the board you are left with is still divisible. If you have 1x1 grid left in the function, it's dead end.

In the following line that you uncomment:

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

You are calling the recursive function with a random value that is inside the allowed values, so it will recurse infinitely, because the size is not decreasing and thus you will never fullfill your stop condition:

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

Why are you calling this with a random value? Maybe as jnovacho suggested, you should add another condition, for instance, max recursion level or something similar...

As a suggestion, try debugging your code in Eclipse and, if possible, add some UnitTests that will check that the configurations you have tested still work...

EDIT

Your new code is much better, but there are still issues:

  • You are not creating a wall gap in splitHorizontal .
  • You probably mean to loop to i <= maxRow and i <= maxColumn instead of strictly less than when creating the walls.
  • As I mentioned in my previous edit, you are still blocking gaps in existing walls with new ones (whether parallel or perpendicular.

As others have suggested, your recursion is not correct. The dimension you are splitting is not shrinking correctly. You're also sometimes ignoring the information you are passing.

Incorrect recursion

The minimum height and width are discarded and replaced with 1 , and the width is discarded and replaced with maxWidth :

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

When the second call is commented, the width or height will eventually randomly drop below 2 , ending the recursion. However, when uncommented, one of these two calls will definitely have width >= 2 (since maxWidth == 18 > 3 ). There's a small chance that the recursion will end early on, but only because you haven't yet implemented the second recursive call in the "HORIZONTAL" case in the same (incorrect) way you did for the "VERTICAL" case.

There seems to be a little confusion in your code about the exact meaning of the parameters height , width , mHeight , and mWidth . An alternate set of parameters to function may help you reason about it:

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

Ignoring passed information

Concentrate on the "VERTICAL" case. The column you pick for the wall does not respect the partition:

int randomColumn = getRandomNumber(mWidth, maxWidth);

mWidth is always 1 and maxWidth is always 18 even if you've already partitioned. Similarly, you may be placing the gap outside the wall:

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 may be less than minHeight .

Smaller issues

There are some other more potential issues as well:

  • Stylistically, an enum makes more sense than a string for the return value of getOrientation .
  • A wall may be placed adjacent to (and parallel with) an existing wall.
  • A wall may blocks the gap or passage of an existing wall even at a right angle.
  • Recursion should continue while either height or width are above their thresholds, not only if both are

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM