Java递归迷宫求解器问题

时间:2014-03-07 01:45:20

标签: java recursion

我正在尝试使用递归编写迷宫求解器,似乎它尝试每个方向一次,然后停止,我无法弄清楚为什么。如果您发现问题,请告诉我。 键 0是一个开放空间 1是墙 2是路径的一部分 3是迷宫的终点

public class Maze{
  public static void main(String[] args){
    int[][] maze = 
     {{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
      {0,0,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,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1},
      {1,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,0,1,0,1},
      {1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,1,0,1,0,0,0,1,0,1,0,0,0,1,0,0,0,1,0,1,0,1},
      {1,0,1,0,1,1,1,0,1,0,1,1,1,1,1,1,1,1,1,0,1,0,1,1,1,0,1,0,1,1,1,1,1,0,1,1,1,0,1,0,1,0,1,1,1,0,1,1,1,0,1},
      {1,0,1,0,1,0,1,0,1,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,1,0,1,0,1,0,0,0,0,0,1,0,0,0,1,0,1,0,0,0,0,0,1,0,0,0,1},
      {1,0,1,1,1,0,1,0,1,1,1,0,1,0,1,0,1,0,1,1,1,1,1,0,1,0,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,0,1,0,1},
      {1,0,0,0,0,0,1,0,0,0,0,0,1,0,1,0,1,0,1,0,0,0,0,0,1,0,1,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,1,0,1},
      {1,1,1,0,1,1,1,1,1,1,1,1,1,0,1,0,1,0,1,0,1,0,1,1,1,0,1,1,1,1,1,1,1,0,1,0,1,0,1,1,1,0,1,1,1,1,1,1,1,0,1},
      {1,0,1,0,1,0,0,0,0,0,0,0,1,0,1,0,1,0,1,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,1,0,1,0,0,0,1,0,0,0,1},
      {1,0,1,0,1,0,1,1,1,1,1,0,1,0,1,0,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,0,1,1,1,0,1,0,1,1,1},
      {1,0,1,0,1,0,0,0,1,0,1,0,1,0,1,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,1},
      {1,0,1,0,1,1,1,0,1,0,1,0,1,0,1,1,1,1,1,1,1,0,1,0,1,0,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1},
      {1,0,1,0,1,0,1,0,1,0,0,0,1,0,1,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1},
      {1,0,1,0,1,0,1,0,1,0,1,1,1,0,1,0,1,1,1,1,1,1,1,1,1,0,1,0,1,1,1,0,1,1,1,0,1,1,1,1,1,0,1,0,1,1,1,1,1,0,1},
      {1,0,0,0,1,0,1,0,1,0,0,0,0,0,1,0,1,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,1,0,0,0,1,0,1,0,0,0,1,0,1,0,0,0,0,0,1},
      {1,0,1,1,1,0,1,0,1,1,1,1,1,1,1,0,1,0,1,1,1,1,1,0,1,1,1,1,1,0,1,0,1,0,1,1,1,0,1,0,1,1,1,1,1,0,1,1,1,0,1},
      {1,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,1,0,0,0,1,0,1,0,0,0,0,0,1,0,1,0,1},
      {1,1,1,1,1,0,1,1,1,0,1,1,1,0,1,0,1,0,1,0,1,1,1,1,1,1,1,0,1,0,1,1,1,1,1,0,1,0,1,0,1,0,1,1,1,1,1,0,1,0,1},
      {1,0,0,0,1,0,0,0,1,0,0,0,1,0,1,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,0,0,1,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,1},
      {1,0,1,1,1,1,1,0,1,1,1,0,1,1,1,0,1,0,1,1,1,0,1,0,1,1,1,0,1,1,1,1,1,0,1,0,1,1,1,1,1,1,1,0,1,0,1,0,1,0,1},
      {1,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,1,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,1,0,1,0,0,0,1,0,0,0,1,0,1,0,1,0,1,0,1},
      {1,1,1,0,1,0,1,1,1,0,1,1,1,0,1,0,1,1,1,1,1,0,1,1,1,0,1,1,1,0,1,0,1,0,1,1,1,0,1,0,1,0,1,0,1,0,1,1,1,0,1},
      {1,0,0,0,1,0,1,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,1,0,1,0,1,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,1},
      {1,0,1,1,1,0,1,0,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,0,1,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,0,1,0,1},
      {1,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,1,0,0,0,1,0,1,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,1},
      {1,0,1,1,1,1,1,1,1,0,1,1,1,0,1,1,1,0,1,0,1,0,1,0,1,0,1,1,1,0,1,0,1,0,1,1,1,1,1,0,1,0,1,1,1,0,1,0,1,0,1},
      {1,0,0,0,0,0,0,0,1,0,1,0,1,0,1,0,0,0,1,0,1,0,1,0,1,0,0,0,0,0,1,0,1,0,0,0,0,0,1,0,1,0,1,0,0,0,1,0,1,0,1},
      {1,0,1,1,1,1,1,0,1,0,1,0,1,0,1,0,1,1,1,0,1,0,1,0,1,0,1,1,1,1,1,0,1,0,1,0,1,1,1,0,1,0,1,0,1,1,1,1,1,0,1},
      {1,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,1,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,1,0,1,0,0,0,1,0,1,0,0,0,0,0,1,0,1},
      {1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,0,1,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,1,1,0,1,0,1},
      {1,0,0,0,1,0,1,0,0,0,1,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,1,0,1},
      {1,0,1,1,1,0,1,1,1,0,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,0,1,0,1,0,1,0,1},
      {1,0,0,0,0,0,0,0,0,0,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,1,0,1,0,0,0,1},
      {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1}};
    boolean[][] posCheck = new boolean[maze.length][maze[0].length];
    int r = 0;
    int c = 0;
    for(int row = 0; row < maze.length; row++){
      for(int col = 0; col < maze[row].length; col++){
        if(maze[row][col]==0){
          r = row;
          c = col;
        }
      }
    }
    maze[r][c] = 3;
    mazeSolver(1, 0, 0, maze, posCheck);
  }

  public static boolean mazeSolver(int r, int c, int d, int[][]maze, boolean[][] posCheck){
    maze[r][c] = 2;

    if(maze[r][c] == 3){
      print(maze);
      return true;
    }

    if((c+1 < maze.length) && maze[r][c+1]==0 && d != 1 && !posCheck[r][c+1]){
      if(d != 3)
        posCheck[r][c+1] = true;
      if(mazeSolver(r, c + 1, 3, maze, posCheck)){
        maze[r][c] = 2;
        return true;
      }
    }

    if((r-1 >= 0) && maze[r-1][c]==0 && !posCheck[r-1][c] && d != 2){
      if(d != 4)
        posCheck[r-1][c] = true;
      if(mazeSolver(r - 1, c, 4, maze, posCheck)){
        maze[r][c] = 2;
        return true;
      }
    }

    if((c-1 >= 0) && maze[r][c-1]==0 && !posCheck[r][c-1] && d != 3){
      if(d != 1)
        posCheck[r][c-1] = true;
      if(mazeSolver(r, c - 1, 1, maze, posCheck)){
        maze[r][c] = 2;
        return true;
      }
    }

    if((r+1 < maze.length) && maze[r+1][c]==0 && !posCheck[r+1][c] && d != 4){
      if(d != 2)
        posCheck[r+1][c] = true;
      if(mazeSolver(r + 1, c, 4, maze, posCheck)){
        maze[r][c] = 2;
        return true;
      }
    }

    print(maze);
    return false;
  }

  public static void print(int[][] maze){
    for(int row = 0; row<maze.length; row++){
      for(int col = 0; col<maze[row].length; col++)
        System.out.print(maze[row][col]);
      System.out.println();
    }
  }
}

2 个答案:

答案 0 :(得分:5)

看到你已经接受了答案,但无论如何我都会加上这个......

递归可以是解决某些问题的一种非常优雅的方式,但它可能需要一些时间才能解决问题。所以这不是一个确切的答案,为什么你的代码不起作用,而是更多的更高级别的如何在这样的问题中使用递归。

递归问题通常包含数据的两个部分:一些整体拼图状态,以及与当前尝试相关的一些状态。整个递归的工作原理是因为每次调用递归函数时都会将一些新状态推送到调用堆栈,当函数退出时,它会被移除,让您准备好尝试下一个选项。您还可以在递归函数中操纵整体拼图状态,但通常在您开始时我建议您在函数中对拼图状态所做的任何更改都应在退出时恢复。

所以在你的情况下,迷宫本身就是拼图状态,当前路径是整个拼图状态的临时变化,当前位置是与当前调用堆栈相关的瞬态。

所以整体解决方案开始采用以下形式:

  // global state
  private static int[][] maze;

  private static boolean solve(int r, int c) {
    // return true if I'm at the exit, false otherwise
  }

主要功能只是提供起始坐标:

  public static void main(String[] args) {
    if (solve(1, 0)) {
      print();
    } else {
      System.out.println("no solution found");
    }
  }

所以下一步是“解决”功能的主体(我在迷宫数据中将退出位置设置为3 - 请参见最后的完整解决方案),这将成为:

  private static boolean solve(int r, int c) {

    if (maze[r][c] == 3) {
      // we've found the exit
      return true;
    }

    // push the current position onto the path
    maze[r][c] == 2;

    // try up / down / left / right - if any of these return true then we're done
    if (available(r - 1, c) && solve(r - 1, c)) {
      return true;
    }
    if (available(r + 1, c) && solve(r + 1, c)) {
      return true;
    }
    if (available(r, c - 1) && solve(r, c - 1)) {
      return true;
    }
    if (available(r, c + 1) && solve(r, c + 1)) {
      return true;
    }

    // no result found from the current position so return false
    // ... but have to revert the temporary state before doing so
    maze[r][c] = 0;

    return false;
  }

这首先检查我们是否在退出的简单情况,如果是这种情况则返回true。如果没有,我们将当前单元格推送到路径,并查找可用的邻居。如果我们找到一个,我们依次尝试每个,这是递归的核心...如果没有可用的邻居工作,那么我们失败了,并且必须回溯。

最后,如果我们回溯,我们必须从路径中删除当前单元格。

就是这样。 'available'函数只是检查潜在的单元是否在边界而不是墙或已经在当前路径上:

  private static boolean available(int r, int c) {
    return r >= 0 && r < maze.length
        && c >= 0 && c < maze[r].length
        && (maze[r][c] == 0 || maze[r][c] == 3);
  }

完整代码:

public class Maze2 {

  private static int[][] maze = 
     {{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
      {0,0,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,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1},
      {1,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,0,1,0,1},
      {1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,1,0,1,0,0,0,1,0,1,0,0,0,1,0,0,0,1,0,1,0,1},
      {1,0,1,0,1,1,1,0,1,0,1,1,1,1,1,1,1,1,1,0,1,0,1,1,1,0,1,0,1,1,1,1,1,0,1,1,1,0,1,0,1,0,1,1,1,0,1,1,1,0,1},
      {1,0,1,0,1,0,1,0,1,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,1,0,1,0,1,0,0,0,0,0,1,0,0,0,1,0,1,0,0,0,0,0,1,0,0,0,1},
      {1,0,1,1,1,0,1,0,1,1,1,0,1,0,1,0,1,0,1,1,1,1,1,0,1,0,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,0,1,0,1},
      {1,0,0,0,0,0,1,0,0,0,0,0,1,0,1,0,1,0,1,0,0,0,0,0,1,0,1,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,1,0,1},
      {1,1,1,0,1,1,1,1,1,1,1,1,1,0,1,0,1,0,1,0,1,0,1,1,1,0,1,1,1,1,1,1,1,0,1,0,1,0,1,1,1,0,1,1,1,1,1,1,1,0,1},
      {1,0,1,0,1,0,0,0,0,0,0,0,1,0,1,0,1,0,1,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,1,0,1,0,0,0,1,0,0,0,1},
      {1,0,1,0,1,0,1,1,1,1,1,0,1,0,1,0,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,0,1,1,1,0,1,0,1,1,1},
      {1,0,1,0,1,0,0,0,1,0,1,0,1,0,1,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,1},
      {1,0,1,0,1,1,1,0,1,0,1,0,1,0,1,1,1,1,1,1,1,0,1,0,1,0,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1},
      {1,0,1,0,1,0,1,0,1,0,0,0,1,0,1,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1},
      {1,0,1,0,1,0,1,0,1,0,1,1,1,0,1,0,1,1,1,1,1,1,1,1,1,0,1,0,1,1,1,0,1,1,1,0,1,1,1,1,1,0,1,0,1,1,1,1,1,0,1},
      {1,0,0,0,1,0,1,0,1,0,0,0,0,0,1,0,1,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,1,0,0,0,1,0,1,0,0,0,1,0,1,0,0,0,0,0,1},
      {1,0,1,1,1,0,1,0,1,1,1,1,1,1,1,0,1,0,1,1,1,1,1,0,1,1,1,1,1,0,1,0,1,0,1,1,1,0,1,0,1,1,1,1,1,0,1,1,1,0,1},
      {1,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,1,0,0,0,1,0,1,0,0,0,0,0,1,0,1,0,1},
      {1,1,1,1,1,0,1,1,1,0,1,1,1,0,1,0,1,0,1,0,1,1,1,1,1,1,1,0,1,0,1,1,1,1,1,0,1,0,1,0,1,0,1,1,1,1,1,0,1,0,1},
      {1,0,0,0,1,0,0,0,1,0,0,0,1,0,1,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,0,0,1,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,1},
      {1,0,1,1,1,1,1,0,1,1,1,0,1,1,1,0,1,0,1,1,1,0,1,0,1,1,1,0,1,1,1,1,1,0,1,0,1,1,1,1,1,1,1,0,1,0,1,0,1,0,1},
      {1,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,1,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,1,0,1,0,0,0,1,0,0,0,1,0,1,0,1,0,1,0,1},
      {1,1,1,0,1,0,1,1,1,0,1,1,1,0,1,0,1,1,1,1,1,0,1,1,1,0,1,1,1,0,1,0,1,0,1,1,1,0,1,0,1,0,1,0,1,0,1,1,1,0,1},
      {1,0,0,0,1,0,1,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,1,0,1,0,1,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,1},
      {1,0,1,1,1,0,1,0,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,0,1,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,0,1,0,1},
      {1,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,1,0,0,0,1,0,1,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,1},
      {1,0,1,1,1,1,1,1,1,0,1,1,1,0,1,1,1,0,1,0,1,0,1,0,1,0,1,1,1,0,1,0,1,0,1,1,1,1,1,0,1,0,1,1,1,0,1,0,1,0,1},
      {1,0,0,0,0,0,0,0,1,0,1,0,1,0,1,0,0,0,1,0,1,0,1,0,1,0,0,0,0,0,1,0,1,0,0,0,0,0,1,0,1,0,1,0,0,0,1,0,1,0,1},
      {1,0,1,1,1,1,1,0,1,0,1,0,1,0,1,0,1,1,1,0,1,0,1,0,1,0,1,1,1,1,1,0,1,0,1,0,1,1,1,0,1,0,1,0,1,1,1,1,1,0,1},
      {1,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,1,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,1,0,1,0,0,0,1,0,1,0,0,0,0,0,1,0,1},
      {1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,0,1,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,1,1,0,1,0,1},
      {1,0,0,0,1,0,1,0,0,0,1,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,1,0,1},
      {1,0,1,1,1,0,1,1,1,0,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,0,1,0,1,0,1,0,1},
      {1,0,0,0,0,0,0,0,0,0,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,1,0,1,0,0,0,1},
      {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,1}};

  public static void main(String[] args) {
    if (solve(1, 0)) {
      print();
    } else {
      System.out.println("no solution found");
    }
  }

  private static boolean solve(int r, int c) {

    // if we're at the goal then we've solved it
    if (maze[r][c] == 3) {
      return true;
    }

    // mark the current cell as on the path
    maze[r][c] = 2;

    // try all available neighbours - if any of these return true then we're solved
    if (available(r - 1, c) && solve(r - 1, c)) {
      return true;
    }
    if (available(r + 1, c) && solve(r + 1, c)) {
      return true;
    }
    if (available(r, c - 1) && solve(r, c - 1)) {
      return true;
    }
    if (available(r, c + 1) && solve(r, c + 1)) {
      return true;
    }

    // nothing found so remove the current cell from the path and backtrack
    maze[r][c] = 0;

    return false;
  }

  // cell is available if it is in the maze and either a clear space or the
  // goal - it is not available if it is a wall or already on the current path
  private static boolean available(int r, int c) {
    return r >= 0 && r < maze.length
        && c >= 0 && c < maze[r].length
        && (maze[r][c] == 0 || maze[r][c] == 3);
  }

  // use symbols to make reading the output easier...
  private static final char[] SYMBOLS = {' ', '#', '.', '*' };

  private static void print(){
    for(int row = 0; row < maze.length; ++row) {
      for(int col = 0; col < maze[row].length; ++col) {
        System.out.print(SYMBOLS[maze[row][col]]);
      }
      System.out.println();
    }
  }
}

最后,如果您想要打印出所有可能的解决方案,而不仅仅是找到的第一个解决方案,那么只需将已解决的函数的顶部更改为:

// if we're at the goal then print it but return false to continue searching
if (maze[r][c] == 3) {
  print();
  return false;
}

快乐的递归!!!

答案 1 :(得分:3)

在过去的五个小时里,您已经提出了四个关于这个迷宫递归谜题的问题,这证明了它有多复杂。整个概念1/0迷宫网格引起了我的兴趣,我想出了一个类,它应该让它更简单。整个更简单。如果你需要进行递归,那么它对你没用,但是如果你可以使用它,它就会消除它的大部分复杂性。

有两个类,一个枚举。

首先,枚举,定义您想要在网格中移动的方向,并根据其移动一次一个地确定新索引。

enum Direction {
   UP(-1, 0),
   DOWN(1, 0),
   LEFT(0, -1),
   RIGHT(0, 1);

   private final int rowSteps;
   private final int colSteps;
   private Direction(int rowSteps, int colSteps)  {
      this.rowSteps = rowSteps;
      this.colSteps = colSteps;
   }
   public int getNewRowIdx(int currentRowIdx)  {
      return  (currentRowIdx + getRowSteps());
   }
   public int getNewColIdx(int currentColIdx)  {
      return  (currentColIdx + getColSteps());
   }
   public int getRowSteps()  {
      return  rowSteps;
   }
   public int getColSteps()  {
      return  colSteps;
   }
};

主要类名为MazePosition(下方)。首先,通过其int[][]构造函数将迷宫网格双数组设置到其中,并静态存储该实例:

private static final MazePosition MAZE_HOLDER = new MazePosition(MAZE_GRID);

(这个步骤可以更好地设计,但它有效。)

设置迷宫网格(这是一次性的,每次执行)后,x / y构造函数用于声明初始位置:

MazePosition pos = new MazePosition(0, 0);

然后,根据需要移动:

pos = pos.getNeighbor(Direction.RIGHT);
pos = pos.getNeighbor(Direction.RIGHT);
pos = pos.getNeighbor(Direction.DOWN);
...

每个职位的价值由pos.getValue()pos.isPath()检索 - 我认为1是“墙”,0是“路径”。 (顺便说一句:巨大的2d数组应该包含一位booleans,而不是4字节ints,但在数组代码中查找对{ {1}} s,而不是布尔值...请注意,它至少应更改为int s。)

关于移动,如果你试图在没有邻居的情况下找到邻居,例如在左边缘向左移动,则抛出byte。使用IllegalStateException功能可以避免这种情况。

MazePosition类还有一个方便的调试函数is*Edge(),它返回数组值的9x9网格(作为字符串),其中中间项是当前位置。

getNineByNine()

这没有,是“碰撞检测”或任何实际为你找出迷宫路径的东西。它只是在整个网格中移动,无论它是否穿过墙壁。可以轻松添加一些 import java.util.Arrays; import java.util.Objects; class MazePosition { //state private static int[][] MAZE_GRID; private final int rowIdx; private final int colIdx; //internal private final int rowIdxMinus1; private final int colIdxMinus1; public MazePosition(int[][] MAZE_GRID) { if(this.MAZE_GRID != null) { throw new IllegalStateException("Maze double-array already set. Use x/y constructor."); } MazePosition.MAZE_GRID = MAZE_GRID; //TODO: Crash if null or empty, or sub-arrays null or empty, or unequal lengths, or contain anything but 0 or -1. rowIdx = -1; colIdx = -1; rowIdxMinus1 = -1; colIdxMinus1 = -1; } public MazePosition(int rowIdx, int colIdx) { if(MazePosition.MAZE_GRID == null) { throw new IllegalStateException("Must set maze double-array with: new MazePosition(int[][])."); } if(rowIdx < 0 || rowIdx >= MazePosition.getRowCount()) { throw new IllegalArgumentException("rowIdx (" + rowIdx + ") is invalid."); } if(colIdx < 0 || colIdx >= MazePosition.getColumnCount()) { throw new IllegalArgumentException("colIdx (" + colIdx + ") is invalid."); } this.rowIdx = rowIdx; this.colIdx = colIdx; rowIdxMinus1 = (rowIdx - 1); colIdxMinus1 = (colIdx - 1); } public boolean isPath() { return (getValue() == 0); //1??? } public int getValue() { return MazePosition.MAZE_GRID[getRowIdx()][getColumnIdx()]; } public int getRowIdx() { return rowIdx; } public int getColumnIdx() { return colIdx; } public MazePosition getNeighbor(Direction dir) { Objects.requireNonNull(dir, "dir"); return (new MazePosition( dir.getNewRowIdx(getRowIdx()), dir.getNewColIdx(getColumnIdx()))); } public MazePosition getNeighborNullIfEdge(Direction dir) { if(isEdgeForDirection(dir)) { return null; } return getNeighbor(dir); } public int getNeighborValueNeg1IfEdge(Direction dir) { MazePosition pos = getNeighborNullIfEdge(dir); return ((pos == null) ? -1 : pos.getValue()); } public static final int getRowCount() { return MAZE_GRID.length; } public static final int getColumnCount() { return MAZE_GRID[0].length; } public boolean isEdgeForDirection(Direction dir) { Objects.requireNonNull(dir); switch(dir) { case UP: return isTopEdge(); case DOWN: return isBottomEdge(); case LEFT: return isLeftEdge(); case RIGHT: return isRightEdge(); } throw new IllegalStateException(toString() + ", dir=" + dir); } public boolean isLeftEdge() { return (getColumnIdx() == 0); } public boolean isTopEdge() { return (getRowIdx() == 0); } public boolean isBottomEdge() { return (getRowIdx() == rowIdxMinus1); } public boolean isRightEdge() { return (getColumnIdx() == colIdxMinus1); } public String toString() { return "[" + getRowIdx() + "," + getColumnIdx() + "]=" + getValue(); } public String getNineByNine() { int[][] nineByNine = new int[3][3]; //Middle row nineByNine[1][1] = getValue(); nineByNine[1][0] = getNeighborValueNeg1IfEdge(Direction.LEFT); nineByNine[1][2] = getNeighborValueNeg1IfEdge(Direction.RIGHT); //Top MazePosition posUp = getNeighborNullIfEdge(Direction.UP); if(posUp != null) { nineByNine[0][0] = posUp.getNeighborValueNeg1IfEdge(Direction.LEFT); nineByNine[0][1] = posUp.getValue(); nineByNine[0][2] = posUp.getNeighborValueNeg1IfEdge(Direction.RIGHT); } //Bottom MazePosition posDown = getNeighborNullIfEdge(Direction.DOWN); if(posDown != null) { nineByNine[2][0] = posDown.getNeighborValueNeg1IfEdge(Direction.LEFT); nineByNine[2][1] = posDown.getValue(); nineByNine[2][2] = posDown.getNeighborValueNeg1IfEdge(Direction.RIGHT); } String sLS = System.getProperty("line.separator", "\r\n"); return "Middle position in 9x9 grid is *this*: " + toString() + sLS + Arrays.toString(nineByNine[0]) + sLS + Arrays.toString(nineByNine[1]) + sLS + Arrays.toString(nineByNine[2]); } } getNeighborIfNotWall(Direction)个功能,但我会留给您。 ;)

(实际上,这些类没有太多变化,可以用来遍历任何2D数组,虽然我可能会添加对角线方向,例如isWallToLeft(),以及移动多个步骤的能力,例如UP_LEFT)。

以下是演示用法:

getNeighbor(3, Direction.DOWN)

输出

public class MazePosDemo  {
   private static final int[][] MAZE_GRID = new int[][] {

   //mega maze grid goes here...

   };

   private static final MazePosition MAZE_HOLDER = new MazePosition(MAZE_GRID);

   public static final void main(String[] ignored)  {
      MazePosition pos = new MazePosition(0, 0);
      System.out.println("start: " + pos);

      pos = pos.getNeighbor(Direction.RIGHT);
      System.out.println("right: " + pos);

      pos = pos.getNeighbor(Direction.RIGHT);
      System.out.println("right: " + pos);

      pos = pos.getNeighbor(Direction.DOWN);
      System.out.println("down:  " + pos);

      pos = pos.getNeighbor(Direction.DOWN);
      System.out.println("down:  " + pos);

      pos = pos.getNeighbor(Direction.RIGHT);
      System.out.println("right: " + pos);

      pos = pos.getNeighbor(Direction.DOWN);
      System.out.println("down:  " + pos);

      pos = pos.getNeighbor(Direction.LEFT);
      System.out.println("left:  " + pos);

      pos = pos.getNeighbor(Direction.UP);
      System.out.println("up:    " + pos);

      pos = pos.getNeighbor(Direction.UP);
      System.out.println("up:    " + pos);

      System.out.println(pos.getNineByNine());
   }

}

这是整个源代码文件,包含以上所有内容(包括mega-maze-array):

[C:\java_code\]java MazePosDemo
start: [0,0]=1
right: [0,1]=1
right: [0,2]=1
down:  [1,2]=1
down:  [2,2]=1
right: [2,3]=1
down:  [3,3]=0
left:  [3,2]=1
up:    [2,2]=1
up:    [1,2]=1
Middle position in 9x9 grid is *this*: [1,2]=1
[1, 1, 1]
[0, 1, 0]
[0, 1, 1]