繁体   English   中英

Java迷宫解算器

[英]Java Maze Solver

我在尝试将一个暗示给我们的算法变成可用代码时遇到了困难。 我们给出一个方向枚举,其具有8个坐标(N,NE,NW,S,SE,SW.E,W)以及出口HERE。

这是暗示的算法:

getPathToExit(row, col):
  if (row, col) is outside of the map:
    return an empty list
  else if (row, col) is an obstacle:
    return an empty list
  else if (row, col) is marked as visited or as deadend:
   return an emtpy list
  else if (row, col) is the exit:
    //optional: mark exit as visited
   return a list containing Direction.HERE
  else:
   //try to find a path from current square to exit:
    mark current square as visited (that is, part of path)
      for each neighbor of current square:
        path = path from neighbor to exit
          if path is not empty:
             add (direction to neighbor) to start of path
               return path
   //after for loop: no path exists from this square to exit
   mark current square as deadend
     return empty list

这是我一直在研究的代码:

public java.util.ArrayList<Direction> getPathToExit(){

for (int x=0; x<map.length; x++){
    for (int y=0; y<map[x].length; y++){
        if (map[x][y]=='S'){
            this.startRow=x;
            this.startCol=y;
        }
    }
}
System.out.println("start "+startRow+", "+startCol);
return getPathToExit(this.startRow, this.startCol);
}

private java.util.ArrayList<Direction> getPathToExit(int row, int col){

  Direction [] dirs = Direction.values();
  ArrayList<Direction> path = new ArrayList<Direction>();

getPathToExit(row, col);

    if (row < 0 || col < 0 || row > map.length || col > map[row].length){
        return null;
    }
    else if (map[row][col] != ' '){
        return null;
    }
    else if (map[row][col] == 'E'){
        path.add(Direction.HERE);
        return path;
    }
    else {
        for (int x=0; x<dirs.length-1; x++){
            int nextRow = row + dirs[x].getRowModifier();
            int nextCol = col + dirs[x].getColModifier();
            path = getPathToExit(nextRow, nextCol);
        }
    }
return path;
}

这是枚举类:

public enum Direction {
   N, NE, E, SE, S, SW, W, NW, HERE;

 /**
 * Returns the X/column change on the screen that is associated with
 * this direction: -1 for W, 0 for N/S, and +1 for E.
 */
  public int getColModifier() {
    int mod;
    switch (this) {
     case NW:
     case W:
     case SW:
     mod = -1;
    break;
  case NE:
  case E:
  case SE:
    mod = +1;
    break;
  default:
    mod = 0;
    break;
  }
return mod;
}

/**
 * Returns the Y/row change on the screen that is associated with
 * this direction: -1 for N, 0 for E/W, and +1 for south.
 */
public int getRowModifier() {
 int mod;
 switch (this) {
   case N:
   case NE:
   case NW:
    mod = -1;
    break;
  case S:
  case SE:
  case SW:
    mod = +1;
    break;
  default:
    mod = 0;
    break;
  }
return mod;
}

/** As {@link #getColModifier()} */
public int getXModifier() {
 return this.getColModifier();
}

 /** As {@link #getRowModifier()} */
public int getYModifier() {
  return this.getRowModifier();
}

/**
 * Returns the direction that is the opposite of this one.
 * For example, <code>Direction.NE.reverse() == Direction.SW</code>.
 * (The opposite of HERE is still HERE though.)
 */
public Direction reverse() {
  if (this == HERE) {
    return this;
  }else {
    int reversed = (this.ordinal() + 4) % 8;
   Direction[] dirs = Direction.values();
    return dirs[reversed];
  }
}

}

提前致谢。

代码中有两个问题:

(1)在主循环中:

for (int x=0; x<dirs.length-1; x++){
      int nextRow = row + dirs[x].getRowModifier();
      int nextCol = col + dirs[x].getColModifier();
      path = getPathToExit(nextRow, nextCol);
}

您需要检查递归调用: getPathToExit()返回了非空列表。 如果有,你应该break循环并将相关方向推到它的开始。 你已经找到了一条路 - 不是要继续检查其余部分!


(2)为了使您的算法完整(找到解决方案,如果存在),您需要维护一个visited集,并避免重新访问已访问过的节点。
看看下面的例子:

-------
|S |x1|
-------
|x2|E |
-------

所有都是有效的正方形(没有障碍物),S是开始,E是结束。

现在,假设方向的顺序是right,left, ...

代码(没有visited集)将执行以下操作:

go right (to x1).
go right - out of maze, go back.
go left (to S).
go right (to x1).
go right - out of maze, go back.
go left (to S)
....

你处在一个无限循环中! (一个已知的DFS退款)
StackOverflowError通常表明这是问题,调用堆栈从所有递归调用中已满 - 并且抛出错误。

要修复它,您需要维护一个visited集,并避免重新访问已访问过的节点。 有了这个设置,以及上面的迷宫(方向顺序是right, left, down, ... )将会发生的事情是:

go right (to x1)
go right - out of maze, go back.
go left (to S) - already visitted, go back.
go down (to E) - found target, return it.

更高级的替代方案是使用Iterative Deepening DFS - 这基本上意味着,您将路径的长度限制为l ,并迭代地增加此l 我这次忽略了这个替代方案,它有点先进了。


作为旁注,您的算法是DFS的实现,它具有访问集和有限图(如果存在,则总是找到解决方案),但不是最优的(不保证找到最短路径)。 要找到最短路径,您可能希望使用BFS

另外 :我假设在方法的第三行中的递归调用是用于调试的剩余调用。 它应该不存在。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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