关于回溯java的迷宫解析问题
Posted
技术标签:
【中文标题】关于回溯java的迷宫解析问题【英文标题】:Problem about maze resolution with backtracking java 【发布时间】:2019-03-18 14:05:53 【问题描述】:我正在尝试制作一个可以解决迷宫的应用程序,我正在 尝试使用回溯技术来实现。
我已经开发了一段代码,并且适用于一些简单的场景,但至少在更复杂的场景中失败了。
在公开代码和具体问题之前,我想解释一下它是如何工作的。
关于代码
所以我有两个方法 initializeMaze1 和 initializedMaze2,它们只是加载一些预设场景(起点、一些墙壁和终点)。
我对第一个没有问题,但是第二个改变了。
Thouse 方法给了我一个整数矩阵,它代表实体(墙、起点...)。
我也有净化的打印方法。
最后是回溯代码的迷宫方法。参数为:
-
生成的迷宫(通过我之前讲过的方法完成)。
“玩家”在迷宫行中的位置。
“玩家”在迷宫列中的位置。
解决方案。这是另一个矩阵,它将给出玩家的路径,所以我将在其中标记移动,并且我将保持原来的迷宫不变。
现在我要深入讨论回溯代码。
回溯代码
所以这个方法是一个for循环,它尝试一些尝试(尝试是玩家可能的移动)所以我们尝试每个人,直到我们获得一个有效的动作或者因为没有可能的有效动作而返回。
我有一个 isFactible 方法,它可以分析运动并判断运动是否正常(如果撞墙或超出限制)。
如果不符合事实,则尝试其他动作(增加 for 循环的迭代变量)。
如果不是事实并且我们完成循环,则取消实际位置并返回一个错误值(因此其他上下文会知道它)。
如果是事实,我们将标记新的位置,我们需要区分两种可能性:
我们要移动的位置是终点(目标或出口),所以我们成功了。 我们要移动的位置不是终点,所以我们再次递归调用我们已经移动的新位置。现在我要谈谈我发现的问题。
问题
当我加载第二个迷宫时,我们有这样的场景:
S:开始。 E:空的。 W:墙。 F:完成。
|S|E|W|W|
|E|E|E|E| 问题来了
|E|E|W|W|
|W|E|E|F|
所以代码首先尝试向右移动,如果不是,则尝试向下,如果不是,则尝试向左,如果不是,则向上尝试。我们有那个预设动作。
所以向右移动,好的。 然后试图再次向右移动,但有一堵墙。 就这样下去了,好吧。 然后,向右移动直到最后一列。 试图向右移动,他不能因为出去了。 想往下移,他不能,有一堵墙。 试图向左移动,他可以,所以移动到那里。 我有这个无限循环。
我首先想到的是,好吧,只是添加更多的限制,并避免 他可以移动到他已经去过的地方。
但我认为这不是一个好的解决方案。
你知道如何解决这个问题吗?也许,如果我在代码中犯了一些错误,或者我选择的解决问题的策略不好,我会感谢你们的 cmets。
谢谢你。
代码
import java.util.List;
import java.util.ArrayList;
public class maze
private static final int START = 1;
private static final int END = 2;
private static final int WALL = 3;
private static final int EMPTY = 0;
private static final int MOVE_RIGHT = 5;
private static final int MOVE_DOWN = 6;
private static final int MOVE_LEFT = 7;
private static final int MOVE_UP = 8;
public static void main(String[] args)
int[][] solution = 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0;
showInitializationMessage();
print(solution);
if(maze(initializeMaze2(),0, 0, solution))
print(solution);
else
System.out.println("There is no solution");
private static void showInitializationMessage()
System.out.println("MAZE APPLICATION");
System.out.println("_________________");
System.out.println();
System.out.println();
private static void print(int[][] solution)
for(int i=0; i<solution.length;i++)
for(int j=0;j<solution.length;j++)
System.out.print(solution[i][j]);
System.out.println();
System.out.println();
System.out.println("____________________");
System.out.println();
private static int[][] initializeMaze1()
//Create the structure
int[][] maze = new int[4][4];
//Setting column 0
maze[0][0]=START;
maze[1][0]=EMPTY;
maze[2][0]=EMPTY;
maze[3][0]=WALL;
//Setting column 1
maze[0][1]=EMPTY;
maze[1][1]=WALL;
maze[2][1]=EMPTY;
maze[3][1]=WALL;
//Setting column 2
maze[0][2]=EMPTY;
maze[1][2]=WALL;
maze[2][2]=WALL;
maze[3][2]=EMPTY;
//Setting column 3
maze[0][3]=EMPTY;
maze[1][3]=EMPTY;
maze[2][3]=EMPTY;
maze[3][3]=END;
return maze;
private static int[][] initializeMaze2()
//Create the structure
int[][] maze = new int[4][4];
//Setting column 0
maze[0][0]=START;
maze[1][0]=EMPTY;
maze[2][0]=EMPTY;
maze[3][0]=WALL;
//Setting column 1
maze[0][1]=EMPTY;
maze[1][1]=EMPTY;
maze[2][1]=EMPTY;
maze[3][1]=EMPTY;
//Setting column 2
maze[0][2]=WALL;
maze[1][2]=EMPTY;
maze[2][2]=WALL;
maze[3][2]=EMPTY;
//Setting column 3
maze[0][3]=WALL;
maze[1][3]=EMPTY;
maze[2][3]=WALL;
maze[3][3]=END;
return maze;
private static boolean checkNotOutOfBounds(int[][] maze,int stepX, int stepY, int movement )
if(movement==MOVE_RIGHT)
if(stepY+1>maze.length-1)
return false;
else if(movement==MOVE_DOWN)
if(stepX+1>maze[0].length)
return false;
else if(movement==MOVE_LEFT)
if(stepY-1<0)
return false;
else if(movement==MOVE_UP)
if(stepX-1<0)
return false;
return true;
private static boolean checkNotCollideWithObstacle(int[][] maze, int stepX, int stepY , int movement)
if(movement==MOVE_RIGHT)
if(maze[stepX][stepY+1]==WALL)
return false;
else if(movement==MOVE_DOWN)
if(maze[stepX+1][stepY]==WALL)
return false;
else if(movement==MOVE_LEFT)
if(maze[stepX][stepY-1]==WALL)
return false;
else if(movement==MOVE_UP)
if(maze[stepX-1][stepY]==WALL)
return false;
return true;
private static boolean checkValidMovement(int[][] maze, int stepX, int stepY , int movement)
if(checkNotOutOfBounds(maze, stepX, stepY, movement) && checkNotCollideWithObstacle(maze, stepX, stepY, movement))
return true;
return false;
private static boolean isFactible(int[][] maze,int stepX, int stepY, int[][] solution, int attemp)
if(attemp==0)
//MOVE RIGHT
return checkValidMovement(maze, stepX, stepY, MOVE_RIGHT);
else if(attemp==1)
//MOVE DOWN
return checkValidMovement(maze, stepX, stepY, MOVE_DOWN);
else if(attemp==2)
//MOVE LEFT
return checkValidMovement(maze, stepX, stepY, MOVE_LEFT);
else if(attemp==3)
//MOVE UP
return checkValidMovement(maze, stepX, stepY, MOVE_UP);
return false;
private static boolean maze(int[][] maze,int stepX, int stepY, int[][] solution)
boolean success =false;
for(int attempt=0; attempt<4 && !success; attempt++)
//solution[stepX][stepY]=attempt???
if(isFactible(maze,stepX, stepY, solution,attempt))
mark(solution,stepX, stepY,attempt);
print(solution);
int updatedStepX = updateStepX(stepX, stepY, maze, attempt);
int updatedStepY = updateStepY(stepX, stepY, maze, attempt);
if(maze[updatedStepX][updatedStepY]==END)
success=true;
else
success = maze(maze, updatedStepX, updatedStepY, solution);
if(!success)
solution[stepX][stepY]=0;
print(solution);
return success;
private static void mark(int[][] solution, int stepX, int stepY, int attempt)
if(attempt==0)
solution[stepX][stepY+1]=1;
else if(attempt==1)
solution[stepX+1][stepY]=1;
else if(attempt==2)
solution[stepX][stepY-1]=1;
else if(attempt==3)
solution[stepX-1][stepY]=1;
private static int updateStepX(int oldStepX, int oldStepY, int[][] maze, int attemp)
int updatedStepX=0;
if(attemp==1)
updatedStepX=oldStepX+1;
else if(attemp==3)
updatedStepX=oldStepX-1;
else
updatedStepX=oldStepX;
return updatedStepX;
private static int updateStepY(int oldStepX, int oldStepY, int[][] maze, int attempt)
int updatedStepY=0;
if(attempt==0)
updatedStepY=oldStepY+1;
else if(attempt==2)
updatedStepY=oldStepY-1;
else
updatedStepY=oldStepY;
return updatedStepY;
【问题讨论】:
en.wikipedia.org/wiki/Maze_solving_algorithm 【参考方案1】:就像你想(想你)解决一个真正的迷宫一样。
对于每个位置,记录您从哪个方向到达以及您离开的(有效)方向(我认为是在您离开之前)。
当您返回某个位置(应允许重新访问)时,将已经尝试过的方向视为与墙壁相同的方向 - 即它是无效的。
当您没有更多有效路线时,请返回您来时的方式。
因此,与您的代码的唯一区别是记住每个位置的“尝试和失败”方向。这应该足以防止递归。
【讨论】:
【参考方案2】:我认为最简单的方法就是记住你上次出现的坐标。如果除了返回之外没有其他有效动作,请返回并将您所在的位置标记为墙壁。最后你会到达[F]。
【讨论】:
【参考方案3】:正如 DrPhill 所说,您必须跟踪您去过的地方。
您已经在函数 mark
中这样做了,但您没有在 checkValidMovement
函数中使用该信息。
您应该将该函数更改为如下所示:
private static boolean checkValidMovement(int[][] maze, int stepX, int stepY , int movement, int[][] solution)
if(checkNotOutOfBounds(maze, stepX, stepY, movement)
&& checkNotCollideWithObstacle(maze, stepX, stepY, movement)
&& isNotYetVisited(maze, stepX, stepY, movement, solution))
return true;
return false;
如果下一步的solution
不等于1
,则isNotYetVisited
函数返回false。
希望这会有所帮助。
【讨论】:
以上是关于关于回溯java的迷宫解析问题的主要内容,如果未能解决你的问题,请参考以下文章
详解Java递归(Recursion)通过递归解决迷宫回溯及八皇后问题