Skip to content

Add class documentation, improve comments in MazeRecursion.java #5576

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Oct 7, 2024
205 changes: 89 additions & 116 deletions src/main/java/com/thealgorithms/backtracking/MazeRecursion.java
Original file line number Diff line number Diff line change
@@ -1,152 +1,125 @@
package com.thealgorithms.backtracking;

/**
* This class contains methods to solve a maze using recursive backtracking.
* The maze is represented as a 2D array where walls, paths, and visited/dead
* ends are marked with different integers.
*
* The goal is to find a path from a starting position to the target position
* (map[6][5]) while navigating through the maze.
*/
public final class MazeRecursion {

private MazeRecursion() {
}

public static void mazeRecursion() {
// First create a 2 dimensions array to mimic a maze map
int[][] map = new int[8][7];
int[][] map2 = new int[8][7];

// We use 1 to indicate wall
// Set the ceiling and floor to 1
for (int i = 0; i < 7; i++) {
map[0][i] = 1;
map[7][i] = 1;
}

// Then we set the left and right wall to 1
for (int i = 0; i < 8; i++) {
map[i][0] = 1;
map[i][6] = 1;
}

// Now we have created a maze with its wall initialized

// Here we set the obstacle
map[3][1] = 1;
map[3][2] = 1;

// Print the current map
System.out.println("The condition of the map: ");
for (int i = 0; i < 8; i++) {
for (int j = 0; j < 7; j++) {
System.out.print(map[i][j] + " ");
}
System.out.println();
}

// clone another map for setWay2 method
for (int i = 0; i < map.length; i++) {
System.arraycopy(map[i], 0, map2[i], 0, map[i].length);
}

// By using recursive backtracking to let your ball(target) find its way in the
// maze
// The first parameter is the map
// Second parameter is x coordinate of your target
// Third parameter is the y coordinate of your target
setWay(map, 1, 1);
setWay2(map2, 1, 1);

// Print out the new map1, with the ball footprint
System.out.println("After the ball goes through the map1,show the current map1 condition");
for (int i = 0; i < 8; i++) {
for (int j = 0; j < 7; j++) {
System.out.print(map[i][j] + " ");
}
System.out.println();
/**
* This method solves the maze using the "down -> right -> up -> left"
* movement strategy.
*
* @param map The 2D array representing the maze (walls, paths, etc.)
* @return The solved maze with paths marked, or null if no solution exists.
*/
public static int[][] solveMazeUsingFirstStrategy(int[][] map) {
if (setWay(map, 1, 1)) {
return map;
}
return null;
}

// Print out the new map2, with the ball footprint
System.out.println("After the ball goes through the map2,show the current map2 condition");
for (int i = 0; i < 8; i++) {
for (int j = 0; j < 7; j++) {
System.out.print(map2[i][j] + " ");
}
System.out.println();
/**
* This method solves the maze using the "up -> right -> down -> left"
* movement strategy.
*
* @param map The 2D array representing the maze (walls, paths, etc.)
* @return The solved maze with paths marked, or null if no solution exists.
*/
public static int[][] solveMazeUsingSecondStrategy(int[][] map) {
if (setWay2(map, 1, 1)) {
return map;
}
return null;
}

/**
* Using recursive path finding to help the ball find its way in the maze
* Description:
* 1. map (means the maze)
* 2. i, j (means the initial coordinate of the ball in the maze)
* 3. if the ball can reach the end of maze, that is position of map[6][5],
* means the we have found a path for the ball
* 4. Additional Information: 0 in the map[i][j] means the ball has not gone
* through this position, 1 means the wall, 2 means the path is feasible, 3
* means the ball has gone through the path but this path is dead end
* 5. We will need strategy for the ball to pass through the maze for example:
* Down -> Right -> Up -> Left, if the path doesn't work, then backtrack
* Attempts to find a path through the maze using a "down -> right -> up -> left"
* movement strategy. The path is marked with '2' for valid paths and '3' for dead ends.
*
* @author OngLipWei
* @version Jun 23, 2021 11:36:14 AM
* @param map The maze
* @param i x coordinate of your ball(target)
* @param j y coordinate of your ball(target)
* @return If we did find a path for the ball,return true,else false
* @param map The 2D array representing the maze (walls, paths, etc.)
* @param i The current x-coordinate of the ball (row index)
* @param j The current y-coordinate of the ball (column index)
* @return True if a path is found to (6,5), otherwise false
*/
public static boolean setWay(int[][] map, int i, int j) {
if (map[6][5] == 2) { // means the ball find its path, ending condition
private static boolean setWay(int[][] map, int i, int j) {
if (map[6][5] == 2) {
return true;
}
if (map[i][j] == 0) { // if the ball haven't gone through this point
// then the ball follows the move strategy : down -> right -> up -> left
map[i][j] = 2; // we assume that this path is feasible first, set the current point to 2
// first。
if (setWay(map, i + 1, j)) { // go down

// If the current position is unvisited (0), explore it
if (map[i][j] == 0) {
// Mark the current position as '2'
map[i][j] = 2;

// Move down
if (setWay(map, i + 1, j)) {
return true;
} else if (setWay(map, i, j + 1)) { // go right
}
// Move right
else if (setWay(map, i, j + 1)) {
return true;
} else if (setWay(map, i - 1, j)) { // go up
}
// Move up
else if (setWay(map, i - 1, j)) {
return true;
} else if (setWay(map, i, j - 1)) { // go left
}
// Move left
else if (setWay(map, i, j - 1)) {
return true;
} else {
// means that the current point is the dead end, the ball cannot proceed, set
// the current point to 3 and return false, the backtracking will start, it will
// go to the previous step and check for feasible path again
map[i][j] = 3;
return false;
}
} else { // if the map[i][j] != 0 , it will probably be 1,2,3, return false because the
// ball cannot hit the wall, cannot go to the path that has gone though before,
// and cannot head to deadened.

map[i][j] = 3; // Mark as dead end (3) if no direction worked
return false;
}
return false;
}

// Here is another move strategy for the ball: up->right->down->left
public static boolean setWay2(int[][] map, int i, int j) {
if (map[6][5] == 2) { // means the ball find its path, ending condition
/**
* Attempts to find a path through the maze using an alternative movement
* strategy "up -> right -> down -> left".
*
* @param map The 2D array representing the maze (walls, paths, etc.)
* @param i The current x-coordinate of the ball (row index)
* @param j The current y-coordinate of the ball (column index)
* @return True if a path is found to (6,5), otherwise false
*/
private static boolean setWay2(int[][] map, int i, int j) {
if (map[6][5] == 2) {
return true;
}
if (map[i][j] == 0) { // if the ball haven't gone through this point
// then the ball follows the move strategy : up->right->down->left
map[i][j] = 2; // we assume that this path is feasible first, set the current point to 2
// first。
if (setWay2(map, i - 1, j)) { // go up

if (map[i][j] == 0) {
map[i][j] = 2;

// Move up
if (setWay2(map, i - 1, j)) {
return true;
} else if (setWay2(map, i, j + 1)) { // go right
}
// Move right
else if (setWay2(map, i, j + 1)) {
return true;
} else if (setWay2(map, i + 1, j)) { // go down
}
// Move down
else if (setWay2(map, i + 1, j)) {
return true;
} else if (setWay2(map, i, j - 1)) { // go left
}
// Move left
else if (setWay2(map, i, j - 1)) {
return true;
} else {
// means that the current point is the dead end, the ball cannot proceed, set
// the current point to 3 and return false, the backtracking will start, it will
// go to the previous step and check for feasible path again
map[i][j] = 3;
return false;
}
} else { // if the map[i][j] != 0 , it will probably be 1,2,3, return false because the
// ball cannot hit the wall, cannot go to the path that has gone through before,
// and cannot head to deadend.

map[i][j] = 3; // Mark as dead end (3) if no direction worked
return false;
}
return false;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,41 +11,35 @@
public class MazeRecursionTest {

@Test
public void testMaze() {
// First create a 2 dimensions array to mimic a maze map
public void testSolveMazeUsingFirstAndSecondStrategy() {
int[][] map = new int[8][7];
int[][] map2 = new int[8][7];

// We use 1 to indicate wall
// We use 1 to indicate walls
// Set the ceiling and floor to 1
for (int i = 0; i < 7; i++) {
map[0][i] = 1;
map[7][i] = 1;
}

// Then we set the left and right wall to 1
// Set the left and right wall to 1
for (int i = 0; i < 8; i++) {
map[i][0] = 1;
map[i][6] = 1;
}

// Now we have created a maze with its wall initialized

// Here we set the obstacle
// Set obstacles
map[3][1] = 1;
map[3][2] = 1;

// clone another map for setWay2 method
// Clone the original map for the second pathfinding strategy
for (int i = 0; i < map.length; i++) {
for (int j = 0; j < map[i].length; j++) {
map2[i][j] = map[i][j];
}
System.arraycopy(map[i], 0, map2[i], 0, map[i].length);
}

MazeRecursion.setWay(map, 1, 1);
MazeRecursion.setWay2(map2, 1, 1);

int[][] expectedMap = new int[][] {
// Solve the maze using the first strategy
int[][] solvedMap1 = MazeRecursion.solveMazeUsingFirstStrategy(map);
// Solve the maze using the second strategy
int[][] solvedMap2 = MazeRecursion.solveMazeUsingSecondStrategy(map2);
int[][] expectedMap1 = new int[][] {
{1, 1, 1, 1, 1, 1, 1},
{1, 2, 0, 0, 0, 0, 1},
{1, 2, 2, 2, 0, 0, 1},
Expand All @@ -55,7 +49,6 @@ public void testMaze() {
{1, 0, 0, 2, 2, 2, 1},
{1, 1, 1, 1, 1, 1, 1},
};

int[][] expectedMap2 = new int[][] {
{1, 1, 1, 1, 1, 1, 1},
{1, 2, 2, 2, 2, 2, 1},
Expand All @@ -67,7 +60,8 @@ public void testMaze() {
{1, 1, 1, 1, 1, 1, 1},
};

assertArrayEquals(map, expectedMap);
assertArrayEquals(map2, expectedMap2);
// Assert the results
assertArrayEquals(expectedMap1, solvedMap1);
assertArrayEquals(expectedMap2, solvedMap2);
}
}