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

This commit is contained in:
Hardik Pawar
2024-10-07 22:17:29 +05:30
committed by GitHub
parent 62144f61af
commit 676d451aa6
2 changed files with 116 additions and 149 deletions

View File

@ -1,152 +1,125 @@
package com.thealgorithms.backtracking; 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 { public final class MazeRecursion {
private MazeRecursion() { private MazeRecursion() {
} }
public static void mazeRecursion() { /**
// First create a 2 dimensions array to mimic a maze map * This method solves the maze using the "down -> right -> up -> left"
int[][] map = new int[8][7]; * movement strategy.
int[][] map2 = new int[8][7]; *
* @param map The 2D array representing the maze (walls, paths, etc.)
// We use 1 to indicate wall * @return The solved maze with paths marked, or null if no solution exists.
// Set the ceiling and floor to 1 */
for (int i = 0; i < 7; i++) { public static int[][] solveMazeUsingFirstStrategy(int[][] map) {
map[0][i] = 1; if (setWay(map, 1, 1)) {
map[7][i] = 1; return map;
}
// 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 map1show 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();
}
// Print out the new map2, with the ball footprint
System.out.println("After the ball goes through the map2show 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();
} }
return null;
} }
/** /**
* Using recursive path finding to help the ball find its way in the maze * This method solves the maze using the "up -> right -> down -> left"
* Description * movement strategy.
* 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
* *
* @author OngLipWei * @param map The 2D array representing the maze (walls, paths, etc.)
* @version Jun 23, 2021 11:36:14 AM * @return The solved maze with paths marked, or null if no solution exists.
* @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 ballreturn trueelse false
*/ */
public static boolean setWay(int[][] map, int i, int j) { public static int[][] solveMazeUsingSecondStrategy(int[][] map) {
if (map[6][5] == 2) { // means the ball find its path, ending condition if (setWay2(map, 1, 1)) {
return true; return map;
}
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
return true;
} else if (setWay(map, i, j + 1)) { // go right
return true;
} else if (setWay(map, i - 1, j)) { // go up
return true;
} else if (setWay(map, i, j - 1)) { // go left
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.
return false;
} }
return null;
} }
// Here is another move strategy for the ball: up->right->down->left /**
public static boolean setWay2(int[][] map, int i, int j) { * Attempts to find a path through the maze using a "down -> right -> up -> left"
if (map[6][5] == 2) { // means the ball find its path, ending condition * movement strategy. The path is marked with '2' for valid paths and '3' for dead ends.
*
* @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 setWay(int[][] map, int i, int j) {
if (map[6][5] == 2) {
return true; 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 // If the current position is unvisited (0), explore it
map[i][j] = 2; // we assume that this path is feasible first, set the current point to 2 if (map[i][j] == 0) {
// first。 // Mark the current position as '2'
if (setWay2(map, i - 1, j)) { // go up map[i][j] = 2;
// Move down
if (setWay(map, i + 1, j)) {
return true; return true;
} else if (setWay2(map, i, j + 1)) { // go right
return true;
} else if (setWay2(map, i + 1, j)) { // go down
return true;
} else if (setWay2(map, i, j - 1)) { // go left
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 // Move right
// ball cannot hit the wall, cannot go to the path that has gone through before, else if (setWay(map, i, j + 1)) {
// and cannot head to deadend. return true;
}
// Move up
else if (setWay(map, i - 1, j)) {
return true;
}
// Move left
else if (setWay(map, i, j - 1)) {
return true;
}
map[i][j] = 3; // Mark as dead end (3) if no direction worked
return false; return false;
} }
return false;
}
/**
* 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) {
map[i][j] = 2;
// Move up
if (setWay2(map, i - 1, j)) {
return true;
}
// Move right
else if (setWay2(map, i, j + 1)) {
return true;
}
// Move down
else if (setWay2(map, i + 1, j)) {
return true;
}
// Move left
else if (setWay2(map, i, j - 1)) {
return true;
}
map[i][j] = 3; // Mark as dead end (3) if no direction worked
return false;
}
return false;
} }
} }

View File

@ -11,41 +11,35 @@ import org.junit.jupiter.api.Test;
public class MazeRecursionTest { public class MazeRecursionTest {
@Test @Test
public void testMaze() { public void testSolveMazeUsingFirstAndSecondStrategy() {
// First create a 2 dimensions array to mimic a maze map
int[][] map = new int[8][7]; int[][] map = new int[8][7];
int[][] map2 = 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 // Set the ceiling and floor to 1
for (int i = 0; i < 7; i++) { for (int i = 0; i < 7; i++) {
map[0][i] = 1; map[0][i] = 1;
map[7][i] = 1; map[7][i] = 1;
} }
// Set the left and right wall to 1
// Then we set the left and right wall to 1
for (int i = 0; i < 8; i++) { for (int i = 0; i < 8; i++) {
map[i][0] = 1; map[i][0] = 1;
map[i][6] = 1; map[i][6] = 1;
} }
// Set obstacles
// Now we have created a maze with its wall initialized
// Here we set the obstacle
map[3][1] = 1; map[3][1] = 1;
map[3][2] = 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 i = 0; i < map.length; i++) {
for (int j = 0; j < map[i].length; j++) { System.arraycopy(map[i], 0, map2[i], 0, map[i].length);
map2[i][j] = map[i][j];
}
} }
MazeRecursion.setWay(map, 1, 1); // Solve the maze using the first strategy
MazeRecursion.setWay2(map2, 1, 1); int[][] solvedMap1 = MazeRecursion.solveMazeUsingFirstStrategy(map);
// Solve the maze using the second strategy
int[][] expectedMap = new int[][] { int[][] solvedMap2 = MazeRecursion.solveMazeUsingSecondStrategy(map2);
int[][] expectedMap1 = new int[][] {
{1, 1, 1, 1, 1, 1, 1}, {1, 1, 1, 1, 1, 1, 1},
{1, 2, 0, 0, 0, 0, 1}, {1, 2, 0, 0, 0, 0, 1},
{1, 2, 2, 2, 0, 0, 1}, {1, 2, 2, 2, 0, 0, 1},
@ -55,7 +49,6 @@ public class MazeRecursionTest {
{1, 0, 0, 2, 2, 2, 1}, {1, 0, 0, 2, 2, 2, 1},
{1, 1, 1, 1, 1, 1, 1}, {1, 1, 1, 1, 1, 1, 1},
}; };
int[][] expectedMap2 = new int[][] { int[][] expectedMap2 = new int[][] {
{1, 1, 1, 1, 1, 1, 1}, {1, 1, 1, 1, 1, 1, 1},
{1, 2, 2, 2, 2, 2, 1}, {1, 2, 2, 2, 2, 2, 1},
@ -67,7 +60,8 @@ public class MazeRecursionTest {
{1, 1, 1, 1, 1, 1, 1}, {1, 1, 1, 1, 1, 1, 1},
}; };
assertArrayEquals(map, expectedMap); // Assert the results
assertArrayEquals(map2, expectedMap2); assertArrayEquals(expectedMap1, solvedMap1);
assertArrayEquals(expectedMap2, solvedMap2);
} }
} }