简体   繁体   English

Java迷宫解算器

[英]Java Maze Solver

I'm having difficulty trying to turn a algorithm that was hinted to us into usable code. 我在尝试将一个暗示给我们的算法变成可用代码时遇到了困难。 We are given a Direction enum that has the 8 coordinates (N, NE, NW, S, SE. SW. E, W) along with the exit HERE. 我们给出一个方向枚举,其具有8个坐标(N,NE,NW,S,SE,SW.E,W)以及出口HERE。

This is the hinted algorithm: 这是暗示的算法:

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

This is the code I have been working on for a while: 这是我一直在研究的代码:

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

This is the enum class: 这是枚举类:

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

}

Thanks in advance. 提前致谢。

There are two issues in the code: 代码中有两个问题:

(1) In the main for loop: (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);
}

You need to check if the recursive call: getPathToExit() returned a not null list. 您需要检查递归调用: getPathToExit()返回了非空列表。 If it had, you should break the loop and push the relevant direction to its start. 如果有,你应该break循环并将相关方向推到它的开始。 You already found a path - not point to keep on checking the rest! 你已经找到了一条路 - 不是要继续检查其余部分!


(2) In order for your algorithm to be complete (find a solution if one exists), you need to maintain a visited set, and avoid revisiting already visited nodes. (2)为了使您的算法完整(找到解决方案,如果存在),您需要维护一个visited集,并避免重新访问已访问过的节点。
Have a look at the following example: 看看下面的例子:

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

where all are valid squares (no obstacles), S is the start and E is the end. 所有都是有效的正方形(没有障碍物),S是开始,E是结束。

Now, assume the order of directions is right,left, ... . 现在,假设方向的顺序是right,left, ...

The code (without visited set) will do the following: 代码(没有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)
....

You are in an infinite loop! 你处在一个无限循环中! (one known draw back of DFS) (一个已知的DFS退款)
The StackOverflowError is usually an indication that this is the issue, the call stack is full from all the recursive calls - and an error is thrown. StackOverflowError通常表明这是问题,调用堆栈从所有递归调用中已满 - 并且抛出错误。

To fix it, you need to maintain a visited set, and avoid revisitting already visited nodes. 要修复它,您需要维护一个visited集,并避免重新访问已访问过的节点。 With this set, and the above maze (order of directions is right, left, down, ... ) what will happen is: 有了这个设置,以及上面的迷宫(方向顺序是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.

A more advanced alternative is using Iterative Deepening DFS - which basically mean, you are limitting the length of the path to l , and iteratively increase this l . 更高级的替代方案是使用Iterative Deepening DFS - 这基本上意味着,您将路径的长度限制为l ,并迭代地增加此l I'd ignore this alternative for this time, it is a bit more advanced. 我这次忽略了这个替代方案,它有点先进了。


As a side note, your algorithm is an implementation of DFS , which is complete with a visited set and in finite graphs (always finds a solution if one exists), but not optimal (does not guarantee to find the shortest path). 作为旁注,您的算法是DFS的实现,它具有访问集和有限图(如果存在,则总是找到解决方案),但不是最优的(不保证找到最短路径)。 To find the shortest path, you might want to use BFS instead. 要找到最短路径,您可能希望使用BFS

Also : I assume the recursive call in the third line of the method is a leftover that is there for debugging. 另外 :我假设在方法的第三行中的递归调用是用于调试的剩余调用。 It shouldn't be there. 它应该不存在。

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

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