【问题标题】:Error when using backtracking recursive algorithm to generate maze使用回溯递归算法生成迷宫时出错
【发布时间】:2013-03-29 18:08:38
【问题描述】:

我正在使用递归回溯算法创建一个迷宫生成器。但是,我的问题是每次运行程序时都会给出以下结果:

1 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 1 1
0 0 0 0 0 0 0 1 1 1
0 0 0 0 0 0 1 1 1 1
0 0 0 0 0 1 1 1 1 1
0 0 0 0 1 1 1 1 1 1
0 0 0 1 1 1 1 1 1 1
0 0 1 1 1 1 1 1 1 1
0 1 1 1 1 1 1 1 1 1
0 1 1 1 1 1 1 1 1 1

我的代码的一些背景知识: 构造函数用0填充迷宫int数组,在结束位置(0, 0)放一个1,然后调用backtrackGenerateMaze()方法随机生成一个迷宫。我认为问题可能是我没有墙,这可能会导致奇怪的事情发生。此外,对于方向:0 = 上,1 = 右,2 = 下,& 3 = 左。希望对您有所帮助。

这是我的代码(抱歉这么久,我一直在尝试使用 cmets 来调试它):

public class Maze {

    private int width, length;
    private int[][] maze;

    public Maze(int rows, int columns) {
        width = columns;
        length = rows;

        maze = new int[rows][columns];
        for (int i = 0; i < rows; i++) {
            for (int j = 0; j < columns; j++) {
                maze[i][j] = 0;
            }
        }
        maze[0][0] = 1;

        backtrackGenerateMaze(rows - 1, columns - 1, 1);
    }

    /*
    * THE PROBLEM MUST BE HERE IN THE backtrackGenerateMaze() METHOD
    */
    private void backtrackGenerateMaze(int rows, int columns, int moveLength) {
        if (rows == 0 && columns == 0) {
            System.out.println("rows = " + rows);
            System.out.println("length = " + length);
            System.out.println("columns = " + columns);
            System.out.println("width = " + width);
            return;
        }

        int[] randDirs = generateRandomDirections();

        for (int dir : randDirs) {
            System.out.println("dir == " + dir);
            System.out.println("rows == " + rows);
            System.out.println("columns == " + columns + "\n");
            if (dir == 0) {
                System.out.println("rows - moveLength == " + (rows - moveLength));
                 System.out.println("valid(rows - moveLength, columns) == " + (valid(rows - moveLength, columns)));
                 System.out.println("isInRange(0, length, rows - moveLength, false) == " + (isInRange(0, length, rows - moveLength, false)));

                if (valid(rows - moveLength, columns)
                    && isInRange(0, length, rows - moveLength, false)
                    && maze[rows - moveLength][columns] != 1) {
                    System.out.println("IF 0 is TRUE");
                    for (int i = 1; i <= moveLength; i++) {
                        maze[rows - moveLength][columns] = 1;
                    }
                    maze[rows][columns] = 1;
                    System.out.println("HERE 0");
                    backtrackGenerateMaze(rows - moveLength, columns, moveLength);
                }

                // System.out.println("RETURN DIR 0");
                // return;
            } else if (dir == 1) {
                System.out.println("columns + moveLength = " + (columns + moveLength));
                System.out.println("valid(rows, columns + moveLength) = " + (valid(rows, columns + moveLength)));
                System.out.println();

                if (valid(rows, columns + moveLength)) {
                    System.out.println("VALID 1 is TRUE");
                    if (isInRange(0, width, columns + moveLength, false)) {
                        System.out.println("isInRange() 1 is TRUE");
                        if (maze[rows][columns + moveLength] != 1) {
                            System.out.println("square != 1 is TRUE");
                            System.out.println("IF 1 is TRUE");
                            for (int i = 1; i <= moveLength; i++) {
                                maze[rows][columns + moveLength] = 1;
                            }
                            maze[rows][columns] = 1;
                            System.out.println("HERE 1");
                            backtrackGenerateMaze(rows, columns + moveLength, moveLength);
                        }
                    }
                }

                System.out.println("RETURN DIR 1");
                return;
            } else if (dir == 2) {
                if (valid(rows + moveLength, columns)
                    && isInRange(0, length, rows + moveLength, false)
                    && maze[rows + moveLength][columns] != 1) {
                    System.out.println("IF 2 is TRUE");
                    for (int i = 1; i <= moveLength; i++) {
                        maze[rows + moveLength][columns] = 1;
                    }
                    maze[rows][columns] = 1;
                    System.out.println("HERE 2");
                    backtrackGenerateMaze(rows + moveLength, columns, moveLength);
                }

                System.out.println("RETURN DIR 2");
                return;
            } else if (dir == 3) {
                if (valid(rows, columns - moveLength)
                    && isInRange(0, width, columns - moveLength, false)
                    && maze[rows][columns - moveLength] != 1) {
                    System.out.println("IF 3 is TRUE");
                    for (int i = 1; i <= moveLength; i++) {
                        maze[rows][columns - moveLength] = 1;
                    }
                    maze[rows][columns] = 1;
                    System.out.println("HERE 3");
                    backtrackGenerateMaze(rows + moveLength, columns - moveLength, moveLength);
                }

                System.out.println("RETURN DIR 3");
                return;
            }
        }
        System.out.println("--------------------");
    }

    public int[] generateRandomDirections() {
        ArrayList<Integer> rands = new ArrayList<>();
        for (int i = 0; i < 4; i++) {
            rands.add(i);
        }
        Collections.shuffle(rands);

        int[] ret = new int[4];
        for (int i = 0; i < rands.size(); i++) {
            ret[i] = rands.get(i);
        }
        return ret;
    }

    private boolean valid(int row, int column) {
        return isInRange(0, maze.length - 1, row, true)
                && isInRange(0, maze[0].length - 1, column, true);
    }

    private boolean isInRange(int start, int end, int toCheck,
            boolean inclusive) {
        if (inclusive) {
            return (toCheck >= start && toCheck <= end);
        }
        return (toCheck > start && toCheck < end);
    }

    @Override
    public String toString() {
        String ret = "";
        for (int i = 0; i < maze.length; i++) {
            for (int j = 0; j < maze[0].length; j++) {
                ret += maze[i][j] + " ";
            }
            ret += "\n";
        }
        return ret;
    }
}

...这是我用来运行它的 Main 方法:

public class MazeGame {

    private static ArrayList<Maze> mazes = new ArrayList<>();
    private static final int MAZE_SIZE = 10, NUM_MAZES = 1;

    public static void main(String[] args) {
        Maze temp;
        for (int i = 0; i < NUM_MAZES; i++) {
            temp = new Maze(MAZE_SIZE, MAZE_SIZE);
            System.out.println(temp);
            mazes.add(temp);
        }
    }
}

非常感谢任何帮助。

【问题讨论】:

  • 如果我知道问题出在哪里我会的...但是代码太多很难追踪(尤其是随机部分)。
  • 当然,但这对我们来说更难!您已经在 IDE 中进行了所有设置,准备就绪。恐怕你得先用调试器来解决这个问题。
  • 那你建议我怎么做?如果你愿意,我可以把零件拿出来……
  • 确实如此。删除与问题不直接相关的每一行代码。如果您知道某些代码路径未用于您的示例输入,那么也将它们删除(首先检查断言语句以进行仔细检查)。然后找到可能失败的最小/最简单的测试用例,看看是否可以逐步跟踪以找到导致不同行为的迭代。您现在还应该使用固定种子来生成随机数,以便在多次运行之间获得相同的行为。

标签: java recursion generator backtracking maze


【解决方案1】:

这段代码,在这里运行,输出:

dir == 2
rows == 9
columns == 9

RETURN DIR 2
1 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 0 

绝对不是你说的……

【讨论】:

  • 对不起,我很困惑...您是否运行了我发布的代码,因为它应该为您提供我发布的输出...我即将删除很多代码应该有帮助...感谢您的回答:)