[英]Java solving a maze with recursion problem
我有一个任务,我应该能够显示从入口到出口的迷宫的路径,我已经让它工作到一定程度,但当迷宫变得更加复杂,死胡同,这样的程序进入无限递归。 如果你能给我任何帮助,指出我正确的方向,我将不胜感激。
Mu当前的理论可以在Room类中找到。
这里是Room类,其中存储了连接迷宫的每个房间的引用,有点像链接列表,链接在6个方向,北,南,东,西,上和下。
import java.util.ArrayList;
public class OurRoom
{
private OurRoom exits[];
private String name;
private static ArrayList<OurRoom> list;
public OurRoom()
{
this(null);
}
public OurRoom(String name)
{
this.name = name;
this.list = new ArrayList<OurRoom>();
exits = new OurRoom[Direction.values().length];
for(OurRoom exit : exits)
{
exit = null;
}
}
public void connectTo(OurRoom theOtherRoom, Direction direction)
{
exits[direction.ordinal()] = theOtherRoom;
theOtherRoom.exits[direction.getOpposite().ordinal()] = this;
}
public OurRoom getExit(Direction direction)
{
return exits[direction.ordinal()];
}
public boolean lookExit(Direction direction)
{
return exits[direction.ordinal()] != null;
}
public String getName() {
return name;
}
public OurRoom solveRecursively(OurRoom exit) {
list.add(this);
if(this == exit) {
return this;
}else {
OurRoom temp = null;
if(lookExit(Direction.east)) {
temp = exits[Direction.east.ordinal()].solveRecursively(exit);
}
else if(lookExit(Direction.up)) {
temp = exits[Direction.up.ordinal()].solveRecursively(exit);
}
else if(lookExit(Direction.south)) {
temp = exits[Direction.south.ordinal()].solveRecursively(exit);
}
else if(lookExit(Direction.down)) {
temp = exits[Direction.down.ordinal()].solveRecursively(exit);
}
else if(lookExit(Direction.west)) {
temp = exits[Direction.west.ordinal()].solveRecursively(exit);
}
else if(lookExit(Direction.north)) {
temp = exits[Direction.north.ordinal()].solveRecursively(exit);
}
return temp;
}
}
public ArrayList<OurRoom> getList() {
return list;
}
}
这是方向枚举
public enum Direction
{
north, south, east, west, up, down;
public Direction getOpposite()
{
switch(this)
{
case north:
return south;
case south:
return north;
case east:
return west;
case west:
return east;
case up:
return down;
case down:
return up;
default:
return this;
}
}
}
以下是迷宫如何构建的示例。
import java.util.ArrayList;
import java.util.Iterator;
public class OurMaze
{
private OurRoom entrance, exit;
public OurMaze()
{
this(1);
}
public OurMaze(int mazeNumber)
{
entrance = null;
exit = null;
switch(mazeNumber)
{
case 0:
break;
case 1:
this.buildMaze1();
break;
default:
}
}
public OurRoom getEntrance()
{
return entrance;
}
public OurRoom getExit()
{
return exit;
}
public Iterator<OurRoom> findPathRecursively() {
entrance.solveRecursively(exit);
ArrayList<OurRoom> list = entrance.getList();
return list.iterator();
}
private void buildMaze1()
{
OurRoom room1, room2;
room1 = new OurRoom("Room 1");
room2 = new OurRoom("Room 2");
room1.connectTo(room2, Direction.north);
entrance = room1;
exit = room2;
}
public static void main(String[] args) {
OurMaze maze = new OurMaze(1);
}
}
您只需要保留二维数组,其值指示是否访问过该单元格:您不希望两次通过同一单元格。
除此之外,它只是广度优先搜索(深度优先搜索也很好,如果你不想要最短的路径)。
一些链接
http://en.wikipedia.org/wiki/Flood_fill
http://en.wikipedia.org/wiki/Breadth-first_search
http://en.wikipedia.org/wiki/Depth-first_search
样本搜索例程。
void dfs(int i, int j) {
if cell(i, j) is outside of maze or blocked {
return
}
if visited[i][j] {
return
}
visited[i][j] = true;
dfs(i + 1, j);
dfs(i - 1, j);
dfs(i, j + 1);
dfs(i, j - 1);
}
如果与visited
一样,可以找到路径本身,对于每个单元格,您可以保留单元格。 因此,打印看起来像这样(只是一个伪代码)。
var end = exit_point;
while (end != start_point) {
print end;
end = came_from[end];
}
编辑
上面的代码是针对二维迷宫的,我只是注意到你有三维版本。 但是在上面的例子中引入第三个坐标很容易。
如果有任何困难,请告诉我。
其他人已经描述了解决这个问题的适当方法,但我认为值得指出为什么你的程序不能扩展到更复杂的迷宫。
正如duffymo暗示的那样,问题在于你的算法没有正确地进行任何回溯 - 当它需要一个结果是死路的分支,然后返回到前一个方块时,它根本不记得这个。 并且由于它以固定顺序尝试退出,因此它将始终重试失败的退出。
看看如何定义solveRecursively
函数,你会发现从任何给定的房间,只会尝试一个方向。 如果一个房间有一个东边的出口,那么它是否有任何其他出口甚至无关紧要,因为if-else块永远不会考虑它们。
事实证明,在任何情况下,正确的解决方案不是按照您在那里定义的顺序从每个房间“退出”的情况下,您的解决逻辑将失败(即在两个房间之间进入无限循环)。
(速战速决将存储对每个房间/方向一个简单的布尔标志。你叫递归调用之前,如果你在那个房间里最终回到重新设置它,那么,你知道,方向不工作了,可以让if块会通过尝试其他出口之一。重构这个以使用典型的BFS逻辑,正如Nikita所建议的那样,总体上会更好)
我敢打赌你需要一棵树来跟踪你去过的地方。
当递归失败时,通常意味着编写该方法的人没有正确地表达停止条件。 你的是啥呢?
我认为这是我在电脑上遇到过的第一款游戏。 这是我获得本科学位的学校的IBM大型机。 I / O是纸质电传打字机。 许多盐的眼泪都在玩这个迷宫游戏时被冲走的账户美元。 非常有趣。
在解决迷宫时,将其表示为6-ary图,其中每个节点都是一个房间,每个边代表六个方向之一的行程。 然后,您可以应用一些众所周知的算法来查找最短路径。
此页面描述了通过图形结构查找路径的各种解决方案。 您的图表比描述真实世界地图的图表更容易,因为沿着任何边缘行进的成本等于沿着任何其他边缘行进的成本。
特别要确保看看Dijkstra的算法 。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.