我正在尝试制作一个可以解决迷宫的应用程序, 试图通过回溯技术实现它。
我已经开发了一个代码,并且可以在一些简单的场景下工作,但是至少在一个更复杂的情况下失败了。
在公开代码和具体问题之前,我想解释一下它的工作原理。
关于代码
所以我有两种方法 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 |
因此,该代码尝试首先向右移动,如果不尝试,则向下尝试,如果不尝试向左,如果不尝试,则向上尝试。我们有预设运动。
所以向右移动,好的。 然后尝试再次向右移动,但有一堵墙。 所以下去,好吧。 然后,向右移动直到最后一列。 尝试向右移动,他不能,因为出去了。 尝试下移,他不能,有一堵墙。 他可以尝试向左移动,所以移到那里。 我有这个无限循环。
我认为的第一件事是,增加更多限制,并避免 他可以搬到他已经去过的地方。
但是我认为这不是一个好的解决方案。
您知道如何解决此问题吗?也许,如果我在代码中犯了一些错误,或者如果我选择的解决问题的策略不好,我将不胜感激。
谢谢。
代码
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;
}
}
答案 0 :(得分:2)
与解决真实迷宫的方式几乎一样(想想你)。
对于每个位置,请记录下您来自哪个方向以及您离开哪个(有效)方向(我想在离开之前)。
返回某个位置(应允许再次访问)时,请像对待墙壁一样对待已经尝试过的方向-即无效。
当您没有更多有效的路线时,请返回您的出行方式。
因此与您的代码唯一的不同是记住每个位置的“尝试和失败”指示。这应该足以防止递归。
答案 1 :(得分:1)
我认为最简单的方法就是记住您最后一次在场的坐标。如果除了返回以外没有其他有效的移动,请返回并标记您所在的地点为墙。最后,您将进入[F]。
答案 2 :(得分:1)
正如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;
}
如果下一步的isNotYetVisited
不等于solution
,则1
函数将返回false。
希望这会有所帮助。