I am trying to write a maze solver using recursion, and it seems that it tries each direction once, then stops and I can't figure out why. If you see a problem, please let me know. Key 0 is an open space 1 is a wall 2 is part of the path 3 is the end of the maze
public class Maze{
public static void main(String[] args){
int[][] maze =
{{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
{0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1},
{1,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,0,1,0,1},
{1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,1,0,1,0,0,0,1,0,1,0,0,0,1,0,0,0,1,0,1,0,1},
{1,0,1,0,1,1,1,0,1,0,1,1,1,1,1,1,1,1,1,0,1,0,1,1,1,0,1,0,1,1,1,1,1,0,1,1,1,0,1,0,1,0,1,1,1,0,1,1,1,0,1},
{1,0,1,0,1,0,1,0,1,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,1,0,1,0,1,0,0,0,0,0,1,0,0,0,1,0,1,0,0,0,0,0,1,0,0,0,1},
{1,0,1,1,1,0,1,0,1,1,1,0,1,0,1,0,1,0,1,1,1,1,1,0,1,0,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,0,1,0,1},
{1,0,0,0,0,0,1,0,0,0,0,0,1,0,1,0,1,0,1,0,0,0,0,0,1,0,1,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,1,0,1},
{1,1,1,0,1,1,1,1,1,1,1,1,1,0,1,0,1,0,1,0,1,0,1,1,1,0,1,1,1,1,1,1,1,0,1,0,1,0,1,1,1,0,1,1,1,1,1,1,1,0,1},
{1,0,1,0,1,0,0,0,0,0,0,0,1,0,1,0,1,0,1,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,1,0,1,0,0,0,1,0,0,0,1},
{1,0,1,0,1,0,1,1,1,1,1,0,1,0,1,0,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,0,1,1,1,0,1,0,1,1,1},
{1,0,1,0,1,0,0,0,1,0,1,0,1,0,1,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,1},
{1,0,1,0,1,1,1,0,1,0,1,0,1,0,1,1,1,1,1,1,1,0,1,0,1,0,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1},
{1,0,1,0,1,0,1,0,1,0,0,0,1,0,1,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1},
{1,0,1,0,1,0,1,0,1,0,1,1,1,0,1,0,1,1,1,1,1,1,1,1,1,0,1,0,1,1,1,0,1,1,1,0,1,1,1,1,1,0,1,0,1,1,1,1,1,0,1},
{1,0,0,0,1,0,1,0,1,0,0,0,0,0,1,0,1,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,1,0,0,0,1,0,1,0,0,0,1,0,1,0,0,0,0,0,1},
{1,0,1,1,1,0,1,0,1,1,1,1,1,1,1,0,1,0,1,1,1,1,1,0,1,1,1,1,1,0,1,0,1,0,1,1,1,0,1,0,1,1,1,1,1,0,1,1,1,0,1},
{1,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,1,0,0,0,1,0,1,0,0,0,0,0,1,0,1,0,1},
{1,1,1,1,1,0,1,1,1,0,1,1,1,0,1,0,1,0,1,0,1,1,1,1,1,1,1,0,1,0,1,1,1,1,1,0,1,0,1,0,1,0,1,1,1,1,1,0,1,0,1},
{1,0,0,0,1,0,0,0,1,0,0,0,1,0,1,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,0,0,1,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,1},
{1,0,1,1,1,1,1,0,1,1,1,0,1,1,1,0,1,0,1,1,1,0,1,0,1,1,1,0,1,1,1,1,1,0,1,0,1,1,1,1,1,1,1,0,1,0,1,0,1,0,1},
{1,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,1,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,1,0,1,0,0,0,1,0,0,0,1,0,1,0,1,0,1,0,1},
{1,1,1,0,1,0,1,1,1,0,1,1,1,0,1,0,1,1,1,1,1,0,1,1,1,0,1,1,1,0,1,0,1,0,1,1,1,0,1,0,1,0,1,0,1,0,1,1,1,0,1},
{1,0,0,0,1,0,1,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,1,0,1,0,1,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,1},
{1,0,1,1,1,0,1,0,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,0,1,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,0,1,0,1},
{1,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,1,0,0,0,1,0,1,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,1},
{1,0,1,1,1,1,1,1,1,0,1,1,1,0,1,1,1,0,1,0,1,0,1,0,1,0,1,1,1,0,1,0,1,0,1,1,1,1,1,0,1,0,1,1,1,0,1,0,1,0,1},
{1,0,0,0,0,0,0,0,1,0,1,0,1,0,1,0,0,0,1,0,1,0,1,0,1,0,0,0,0,0,1,0,1,0,0,0,0,0,1,0,1,0,1,0,0,0,1,0,1,0,1},
{1,0,1,1,1,1,1,0,1,0,1,0,1,0,1,0,1,1,1,0,1,0,1,0,1,0,1,1,1,1,1,0,1,0,1,0,1,1,1,0,1,0,1,0,1,1,1,1,1,0,1},
{1,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,1,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,1,0,1,0,0,0,1,0,1,0,0,0,0,0,1,0,1},
{1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,0,1,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,1,1,0,1,0,1},
{1,0,0,0,1,0,1,0,0,0,1,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,1,0,1},
{1,0,1,1,1,0,1,1,1,0,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,0,1,0,1,0,1,0,1},
{1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,1},
{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1}};
boolean[][] posCheck = new boolean[maze.length][maze[0].length];
int r = 0;
int c = 0;
for(int row = 0; row < maze.length; row++){
for(int col = 0; col < maze[row].length; col++){
if(maze[row][col]==0){
r = row;
c = col;
}
}
}
maze[r][c] = 3;
mazeSolver(1, 0, 0, maze, posCheck);
}
public static boolean mazeSolver(int r, int c, int d, int[][]maze, boolean[][] posCheck){
maze[r][c] = 2;
if(maze[r][c] == 3){
print(maze);
return true;
}
if((c+1 < maze.length) && maze[r][c+1]==0 && d != 1 && !posCheck[r][c+1]){
if(d != 3)
posCheck[r][c+1] = true;
if(mazeSolver(r, c + 1, 3, maze, posCheck)){
maze[r][c] = 2;
return true;
}
}
if((r-1 >= 0) && maze[r-1][c]==0 && !posCheck[r-1][c] && d != 2){
if(d != 4)
posCheck[r-1][c] = true;
if(mazeSolver(r - 1, c, 4, maze, posCheck)){
maze[r][c] = 2;
return true;
}
}
if((c-1 >= 0) && maze[r][c-1]==0 && !posCheck[r][c-1] && d != 3){
if(d != 1)
posCheck[r][c-1] = true;
if(mazeSolver(r, c - 1, 1, maze, posCheck)){
maze[r][c] = 2;
return true;
}
}
if((r+1 < maze.length) && maze[r+1][c]==0 && !posCheck[r+1][c] && d != 4){
if(d != 2)
posCheck[r+1][c] = true;
if(mazeSolver(r + 1, c, 4, maze, posCheck)){
maze[r][c] = 2;
return true;
}
}
print(maze);
return false;
}
public static void print(int[][] maze){
for(int row = 0; row<maze.length; row++){
for(int col = 0; col<maze[row].length; col++)
System.out.print(maze[row][col]);
System.out.println();
}
}
}
You have asked four questions about this maze-recursion puzzle in the past five hours, which attests to how complicated it is. This whole concept a 1/0 maze-grid has intrigued me, and I've come up with a class that should make it a whole lot simpler. If you're required to do recursion, then it will not be useful to you, but if you can use it, it eliminates much of its complexity.
There are two classes, and an Enum.
First, the enum, which defines the direction you want to move in the grid and determines the new indexes, one-at-a-time, based on its movement.
The main class is called
MazePosition
(below). First you set the maze-grid double-array into it, via itsint[][]
constructor, and store that instance statically:(This step could be designed better, but it works.)
After setting the maze-grid (which is a one-time-only thing, per-execution), then the x/y constructor is used to declare an initial position:
And after that, just move as necessary:
The value of each position is retrieved by
pos.getValue()
orpos.isPath()
--I think1
is a "wall" and0
is the "path". (As an aside: The huge 2d-array should really contain one-bitbooleans
, instead of 4-byteints
, but looking at the array's code makes sense withint
s, and doesn't with booleans... Note that it should at least be changed tobyte
s.)So regarding movement, if you attempt to get a neighbor when there is none, such as moving left at the left edge, an
IllegalStateException
is thrown. Use theis*Edge()
functions to avoid this.The MazePosition class also has a convenient debugging function called
getNineByNine()
, which returns a 9x9 grid of the array values (as a string), where the middle item is the current position.What this does not have, is "collision detection" or anything that actually figures out the maze-path for you. It just moves throughout the grid, regardless if it's moving through walls or not. There could easily be some
getNeighborIfNotWall(Direction)
andisWallToLeft()
functions added, but I'll leave that to you. ;)(Actually, these classes, without too much change, could be used to traverse any 2D array, although I'd probably add diagonal directions, such as
UP_LEFT
, and the ability to move multiple steps, such asgetNeighbor(3, Direction.DOWN)
).Here's a demo usage:
Output
And here's the entire source-code file, containing all of the above (including the mega-maze-array):
See you've already accepted an answer, but I'll add this in anyway...
Recursion can be a really elegant way to solve some problems, but it can take a bit to get your head around. So this is not an exact answer to why your code doesn't work, but more of a higher level of how to use recursion in problems like this.
Recursion problems generally have two parts to the data: some overall puzzle state, and some state associated with the current attempt. The whole recursion thing works because each time you call the recursive function you push some new state onto the call stack, and when the function exits it is removed for you, leaving you ready to try the next option. You can also manipulate the overall puzzle state within the recursive function, but generally when you're starting I'd suggest that any changes you make to the puzzle state in your function should be reverted when it exits.
So in your case, the maze itself is puzzle state, the current path is a temporary change to the overall puzzle state, and the current position is transient state associated with the current call stack.
So the overall solution starts to take the form:
and the main function simply provides the starting coords:
So the next step is the body of the "solve" function (I've set the exit position to 3 in the maze data - see the full solution at the end), which becomes:
This first checks the simple case of if we're at the exit, and returns true if that is the case. If not, we push the current cell on to the path, and look for an available neighbour. If we find one we try each in turn, and this is the core of the recursion... If none of the available neighbours work then we've failed, and have to backtrack.
Finally, if we're backtracking, we have to remove the current cell from the path.
And that's about it. The 'available' function simply checks if the potential cell is in bounds and not a wall or already on the current path:
Full code:
Finally, if you want to print out all possible solutions instead of just the first one found, then just change the top of the solved function to:
Happy recursing!!!