【问题标题】:Why is my random maze generation algorithm creating a pattern of columns at the bottom of my maze?为什么我的随机迷宫生成算法会在迷宫底部创建列模式?
【发布时间】:2015-12-02 05:29:38
【问题描述】:

所以我正在使用深度优先搜索制作迷宫生成算法。我在一个二维字符数组中执行此操作。墙用“#”表示,路径用“.”表示每次调用“迷宫”类时,我都会创建一个新迷宫。

我使用三种方法来做到这一点:

1 - hasUnvisited: 检查一个单元格周围是否有算法之前未访问过的单元格。仅检查向上或向下或向左或向右 +2 个单位的单元格。 (UDLR)

2 - pather:在仅由墙壁组成的网格中雕刻出一条路径。检查路径是否不在网格边缘。然后将该单元格变成一条路径。然后检查单元格是否hasUnvisited。如果是,它会选择一个随机方向(UDLR)。如果该方向+2(例如:左+2,右+2..等)单元格清晰,则它将方向的+1更改为墙壁,然后为方向+2调用pather。 (这将依次清除随机选择的方向上的 +2 并递归重复,直到路径没有未访问。

3 - mazer:此方法仅用于美学目的,因此我已将其注释掉很多以关注潜在问题。它基本上是一个网格,用所有的'#'初始化它。然后使用起始行 (sr) 和起始列 (sc) 1,1 调用 pather。然后返回那个字符网格。

但是,由于某种原因,我的代码每次运行时都会在迷宫底部生成一条奇怪的“列”路径。我 99% 确定它在 'pather' 方法中代码的“剪辑”部分,但我不知道如何结束该方法并阻止它在那个时候越界。

如您所见,这是 Java,但我尝试了 C++ 中的代码,它做同样的事情,所以我很确定这是与语言无关的。

代码如下:

import java.util.Random;

public class Maze {

private char[][] grid;
private final int WIDTH;
private final int HEIGHT;
Random randomGen = new Random();

//Checks to see if any of the surrounding cells are un
private boolean hasUnvisited (char[][] grid, int sr, int sc) {
    if (sc+2 > HEIGHT-1) {
    } else if (grid[sr][sc+2]=='#') {
        return true;
    }
    if (sc-2 < 0) {
    } else if (grid[sr][sc-2]=='#') {
        return true;
    }
    if (sr+2 > WIDTH-1) {
    } else if (grid[sr+2][sc]=='#') {
        return true;
    }
    if (sr-2 < 0) {
    } else if (grid[sr-2][sc]=='#') {
        return true;
    }
    return false;
}

//Visits each cell, turns it to '.'
private void pather (char[][] grid, int sr, int sc) {
    //Sets current cell to '.' to mark as visited
    grid[sr][sc] = '.';

    //"Clipping": if it is at edge of grid, don't carve any more, just return.
    if (sr>WIDTH-2||sr<1||sc>HEIGHT-2||sc<1) {
        return;
    }

    //Gets a number between 0-3
    switch (randomGen.nextInt(4)) {
    case 0:
        if(hasUnvisited(grid,sr,sc)) {
            if(sc+2>HEIGHT-1) {
            }else if(grid[sr][sc+2]!='.'){
                grid[sr][sc+1]='.';
                pather(grid,sr,sc+2);
            }
            pather(grid,sr,sc);
        }
        break;
    case 1:
        if(hasUnvisited(grid,sr,sc)) {
            if(sc-2<0) {
            } else if(grid[sr][sc-2]!='.'){
                grid[sr][sc-1]='.';
                pather(grid,sr,sc-2);
            }
            pather(grid,sr,sc);
        }
        break;
    case 2:
        if(hasUnvisited(grid,sr,sc)) {
            if(sr+2>WIDTH-1) {
            }else if(grid[sr+2][sc]!='.'){
                grid[sr+1][sc]='.';
                pather(grid,sr+2,sc);
            }
            pather(grid,sr,sc);
        }
        break;

    case 3:
        if(hasUnvisited(grid,sr,sc)) {
            if(sr-2<0) {
            } else if(grid[sr-2][sc]!='.') {
                grid[sr-1][sc]='.';
                pather(grid,sr-2,sc);
            }
            pather(grid,sr,sc);
        }
        break;
    }
}

//Returns a complete maze, gets the carved out paths from the pather function,
//then 'cleans it up' to return a useable maze format for the game.

private char[][] mazer() {
    grid = new char[WIDTH][HEIGHT];
    //Initialize Grid with all walls
    for (int i=0;i<WIDTH;i++)
    {
        for (int j=0;j<HEIGHT;j++)
        {
            grid[i][j]= '#';
        }
    }
    //Starting from row and column 1 and 1, respectively.
    int sr=1,sc=1;
    //Carve Out the Grid
    pather(grid,sr,sc);

/*
    //Draw Vertical Surrounding Walls
    for (int j=0;j<HEIGHT;j++)
    {
        grid [0][j]= '#';
        grid [WIDTH-1][j]= '#';
    }
    //Draw Horizontal Surrounding Walls
    for (int j=0;j<WIDTH;j++)
    {
        grid [j][0]= '#';
        grid [j][HEIGHT-1]= '#';
    }
*/

    //JUST FOR DEBUGGING:
    for (int i=0;i<HEIGHT;i++)
    {
        for (int j=0;j<WIDTH;j++)
        {
            System.out.print(grid[j][i]);
        }
        System.out.println("");
    }
    //JUST FOR DEBUGGING ERASE IMMEDIATELY AFTER DONE WITH
    return grid;
}

public Maze (int wIn, int hIn) {
    WIDTH = wIn;
    HEIGHT = hIn;
    grid = mazer();

}

//After Debugging the maze: 
public static void main(String[] args) {
    Maze maze = new Maze(15,10);
   }
}

【问题讨论】:

  • 为什么你移动+2而不是+1

标签: java algorithm recursion maze


【解决方案1】:

我修复了你的解决方案,问题是检查极端情况。

主要变化:

sc+2 > HEIGHT-1 => sc+2 > HEIGHT-2
sr+2 > WIDTH-1 => sr+2 > WIDTH-2

更新后的代码:

import java.util.Random;

public class Maze {

    private char[][] grid;
    private final int WIDTH;
    private final int HEIGHT;
    Random randomGen = new Random();

    //Checks to see if any of the surrounding cells are un
    private boolean hasUnvisited (char[][] grid, int sr, int sc) {
        if (sc+2 > HEIGHT-2) {
        } else if (grid[sr][sc+2]=='#') {
            return true;
        }
        if (sc-2 < 0) {
        } else if (grid[sr][sc-2]=='#') {
            return true;
        }
        if (sr+2 > WIDTH-2) {
        } else if (grid[sr+2][sc]=='#') {
            return true;
        }
        if (sr-2 < 0) {
        } else if (grid[sr-2][sc]=='#') {
            return true;
        }
        return false;
    }

    //Visits each cell, turns it to '.'
    private void pather (char[][] grid, int sr, int sc) {
        //Sets current cell to '.' to mark as visited
        grid[sr][sc] = '.';

        //"Clipping": if it is at edge of grid, don't carve any more, just return.
        if (sr>WIDTH-2||sr<1||sc>HEIGHT-2||sc<1) {
            return;
        }

        //Gets a number between 0-3
        switch (randomGen.nextInt(4)) {
            case 0:
                if(hasUnvisited(grid,sr,sc)) {
                    if(sc+2>HEIGHT-2) {
                    }else if(grid[sr][sc+2]!='.'){
                        grid[sr][sc+1]='.';
                        pather(grid,sr,sc+2);
                    }
                    pather(grid,sr,sc);
                }
                break;
            case 1:
                if(hasUnvisited(grid,sr,sc)) {
                    if(sc-2<0) {
                    } else if(grid[sr][sc-2]!='.'){
                        grid[sr][sc-1]='.';
                        pather(grid,sr,sc-2);
                    }
                    pather(grid,sr,sc);
                }
                break;
            case 2:
                if(hasUnvisited(grid,sr,sc)) {
                    if(sr+2>WIDTH-2) {
                    }else if(grid[sr+2][sc]!='.'){
                        grid[sr+1][sc]='.';
                        pather(grid,sr+2,sc);
                    }
                    pather(grid,sr,sc);
                }
                break;

            case 3:
                if(hasUnvisited(grid,sr,sc)) {
                    if(sr-2<0) {
                    } else if(grid[sr-2][sc]!='.') {
                        grid[sr-1][sc]='.';
                        pather(grid,sr-2,sc);
                    }
                    pather(grid,sr,sc);
                }
                break;
        }
    }

//Returns a complete maze, gets the carved out paths from the pather function,
//then 'cleans it up' to return a useable maze format for the game.

    private char[][] mazer() {
        grid = new char[WIDTH][HEIGHT];
        //Initialize Grid with all walls
        for (int i=0;i<WIDTH;i++)
        {
            for (int j=0;j<HEIGHT;j++)
            {
                grid[i][j]= '#';
            }
        }
        //Starting from row and column 1 and 1, respectively.
        int sr=1,sc=1;
        //Carve Out the Grid
        pather(grid,sr,sc);

/*
    //Draw Vertical Surrounding Walls
    for (int j=0;j<HEIGHT;j++)
    {
        grid [0][j]= '#';
        grid [WIDTH-1][j]= '#';
    }
    //Draw Horizontal Surrounding Walls
    for (int j=0;j<WIDTH;j++)
    {
        grid [j][0]= '#';
        grid [j][HEIGHT-1]= '#';
    }
*/

        //JUST FOR DEBUGGING:
        for (int i=0;i<HEIGHT;i++)
        {
            for (int j=0;j<WIDTH;j++)
            {
                System.out.print(grid[j][i]);
            }
            System.out.println("");
        }
        //JUST FOR DEBUGGING ERASE IMMEDIATELY AFTER DONE WITH
        return grid;
    }

    public Maze (int wIn, int hIn) {
        WIDTH = wIn;
        HEIGHT = hIn;
        grid = mazer();

    }

    //After Debugging the maze:
    public static void main(String[] args) {
        Maze maze = new Maze(17,17);
    }
}

输出(17*17):

#################
#.#.............#
#.#######.#####.#
#.......#...#...#
#######.#.#.#####
#.#.....#.#.#...#
#.#.#####.#.#.#.#
#...#.....#...#.#
#.#######.#####.#
#.......#.....#.#
#######.#######.#
#.......#.....#.#
#.#######.###.#.#
#.#.......#.#.#.#
#.#######.#.#.#.#
#.........#.....#
#################

但是当涉及到均匀的宽度和高度时,它的输出有点奇怪(但无论如何都是正确的),因为移动是+2

输出(18*18):

################
#.......#.....##
#######.###.#.##
#.#.....#...#.##
#.#.#####.###.##
#.#.#.......#.##
#.#.#######.#.##
#...#.....#.#.##
#.###.###.#.#.##
#...#.#.#.#.#.##
###.#.#.#.#.#.##
#.#.#.#...#.#.##
#.#.#.#.###.#.##
#.....#.....#.##
################
################

我的建议是尝试重构您的解决方案以通过 1 步移动生成路径。您的代码永远不会生成类似

的路径
#####
#.#.#
#...#
#####

因为它在地图上走两步。

【讨论】:

  • 它实际上确实完成了你最后写的那张地图......如果你只做两步,它就会在迷宫中开辟出一条单单元宽度的路径。否则,它会雕刻出带有两个“。”的路径的东西。彼此相邻。我希望它排成一行。另外,我不明白你在 hasUnvisited 中做了什么。我没有检查哪些极端情况?
  • 对不起,我的英语不好,所以我听不懂你的想法(虽然仔细阅读了你的评论)......但是你知道,谈话很便宜,我的代码生成一个比你的代码更正确的迷宫......所以你可以调试并找到为什么我改变if-statement来达到这个结果......
  • 我想我会用奇数来使用它,更容易......不过谢谢!
  • @user73664 欢迎您。如果没有其他问题,您能否将我的答案设置为已接受?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-06-25
  • 2010-09-07
相关资源
最近更新 更多