UPDATED rat_in_maze.py (#9148)

* UPDATED rat_in_maze.py

* Update reddit.py in Webprogramming b/c it was causing error in pre-commit tests while raising PR.

* UPDATED rat_in_maze.py

* fixed return type to only maze,otherwise raise valueError.

* fixed whitespaces error,improved matrix visual.

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* updated.

* Try

* updated

* updated

* Apply suggestions from code review

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: Christian Clauss <cclauss@me.com>
This commit is contained in:
Muhammad Umer Farooq 2023-10-04 23:43:17 +05:00 committed by GitHub
parent d5806258d4
commit c16d2f8865
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -1,91 +1,164 @@
from __future__ import annotations from __future__ import annotations
def solve_maze(maze: list[list[int]]) -> bool: def solve_maze(
maze: list[list[int]],
source_row: int,
source_column: int,
destination_row: int,
destination_column: int,
) -> list[list[int]]:
""" """
This method solves the "rat in maze" problem. This method solves the "rat in maze" problem.
In this problem we have some n by n matrix, a start point and an end point.
We want to go from the start to the end. In this matrix zeroes represent walls
and ones paths we can use.
Parameters : Parameters :
maze(2D matrix) : maze - maze: A two dimensional matrix of zeros and ones.
- source_row: The row index of the starting point.
- source_column: The column index of the starting point.
- destination_row: The row index of the destination point.
- destination_column: The column index of the destination point.
Returns: Returns:
Return: True if the maze has a solution or False if it does not. - solution: A 2D matrix representing the solution path if it exists.
Raises:
- ValueError: If no solution exists or if the source or
destination coordinates are invalid.
Description:
This method navigates through a maze represented as an n by n matrix,
starting from a specified source cell and
aiming to reach a destination cell.
The maze consists of walls (1s) and open paths (0s).
By providing custom row and column values, the source and destination
cells can be adjusted.
>>> maze = [[0, 1, 0, 1, 1], >>> maze = [[0, 1, 0, 1, 1],
... [0, 0, 0, 0, 0], ... [0, 0, 0, 0, 0],
... [1, 0, 1, 0, 1], ... [1, 0, 1, 0, 1],
... [0, 0, 1, 0, 0], ... [0, 0, 1, 0, 0],
... [1, 0, 0, 1, 0]] ... [1, 0, 0, 1, 0]]
>>> solve_maze(maze) >>> solve_maze(maze,0,0,len(maze)-1,len(maze)-1) # doctest: +NORMALIZE_WHITESPACE
[1, 0, 0, 0, 0] [[0, 1, 1, 1, 1],
[1, 1, 1, 1, 0] [0, 0, 0, 0, 1],
[0, 0, 0, 1, 0] [1, 1, 1, 0, 1],
[0, 0, 0, 1, 1] [1, 1, 1, 0, 0],
[0, 0, 0, 0, 1] [1, 1, 1, 1, 0]]
True
Note:
In the output maze, the zeros (0s) represent one of the possible
paths from the source to the destination.
>>> maze = [[0, 1, 0, 1, 1], >>> maze = [[0, 1, 0, 1, 1],
... [0, 0, 0, 0, 0], ... [0, 0, 0, 0, 0],
... [0, 0, 0, 0, 1], ... [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]]
>>> solve_maze(maze) >>> solve_maze(maze,0,0,len(maze)-1,len(maze)-1) # doctest: +NORMALIZE_WHITESPACE
[1, 0, 0, 0, 0] [[0, 1, 1, 1, 1],
[1, 0, 0, 0, 0] [0, 1, 1, 1, 1],
[1, 0, 0, 0, 0] [0, 1, 1, 1, 1],
[1, 0, 0, 0, 0] [0, 1, 1, 1, 1],
[1, 1, 1, 1, 1] [0, 0, 0, 0, 0]]
True
>>> maze = [[0, 0, 0], >>> maze = [[0, 0, 0],
... [0, 1, 0], ... [0, 1, 0],
... [1, 0, 0]] ... [1, 0, 0]]
>>> solve_maze(maze) >>> solve_maze(maze,0,0,len(maze)-1,len(maze)-1) # doctest: +NORMALIZE_WHITESPACE
[1, 1, 1] [[0, 0, 0],
[0, 0, 1] [1, 1, 0],
[0, 0, 1] [1, 1, 0]]
True
>>> maze = [[0, 1, 0], >>> maze = [[1, 0, 0],
... [0, 1, 0], ... [0, 1, 0],
... [1, 0, 0]] ... [1, 0, 0]]
>>> solve_maze(maze) >>> solve_maze(maze,0,1,len(maze)-1,len(maze)-1) # doctest: +NORMALIZE_WHITESPACE
No solution exists! [[1, 0, 0],
False [1, 1, 0],
[1, 1, 0]]
>>> maze = [[1, 1, 0, 0, 1, 0, 0, 1],
... [1, 0, 1, 0, 0, 1, 1, 1],
... [0, 1, 0, 1, 0, 0, 1, 0],
... [1, 1, 1, 0, 0, 1, 0, 1],
... [0, 1, 0, 0, 1, 0, 1, 1],
... [0, 0, 0, 1, 1, 1, 0, 1],
... [0, 1, 0, 1, 0, 1, 1, 1],
... [1, 1, 0, 0, 0, 0, 0, 1]]
>>> solve_maze(maze,0,2,len(maze)-1,2) # doctest: +NORMALIZE_WHITESPACE
[[1, 1, 0, 0, 1, 1, 1, 1],
[1, 1, 1, 0, 0, 1, 1, 1],
[1, 1, 1, 1, 0, 1, 1, 1],
[1, 1, 1, 0, 0, 1, 1, 1],
[1, 1, 0, 0, 1, 1, 1, 1],
[1, 1, 0, 1, 1, 1, 1, 1],
[1, 1, 0, 1, 1, 1, 1, 1],
[1, 1, 0, 1, 1, 1, 1, 1]]
>>> maze = [[1, 0, 0],
... [0, 1, 1],
... [1, 0, 1]]
>>> solve_maze(maze,0,1,len(maze)-1,len(maze)-1)
Traceback (most recent call last):
...
ValueError: No solution exists!
>>> maze = [[0, 0],
... [1, 1]]
>>> solve_maze(maze,0,0,len(maze)-1,len(maze)-1)
Traceback (most recent call last):
...
ValueError: No solution exists!
>>> maze = [[0, 1], >>> maze = [[0, 1],
... [1, 0]] ... [1, 0]]
>>> solve_maze(maze) >>> solve_maze(maze,2,0,len(maze)-1,len(maze)-1)
No solution exists! Traceback (most recent call last):
False ...
ValueError: Invalid source or destination coordinates
>>> maze = [[1, 0, 0],
... [0, 1, 0],
... [1, 0, 0]]
>>> solve_maze(maze,0,1,len(maze),len(maze)-1)
Traceback (most recent call last):
...
ValueError: Invalid source or destination coordinates
""" """
size = len(maze) size = len(maze)
# Check if source and destination coordinates are Invalid.
if not (0 <= source_row <= size - 1 and 0 <= source_column <= size - 1) or (
not (0 <= destination_row <= size - 1 and 0 <= destination_column <= size - 1)
):
raise ValueError("Invalid source or destination coordinates")
# We need to create solution object to save path. # We need to create solution object to save path.
solutions = [[0 for _ in range(size)] for _ in range(size)] solutions = [[1 for _ in range(size)] for _ in range(size)]
solved = run_maze(maze, 0, 0, solutions) solved = run_maze(
maze, source_row, source_column, destination_row, destination_column, solutions
)
if solved: if solved:
print("\n".join(str(row) for row in solutions)) return solutions
else: else:
print("No solution exists!") raise ValueError("No solution exists!")
return solved
def run_maze(maze: list[list[int]], i: int, j: int, solutions: list[list[int]]) -> bool: def run_maze(
maze: list[list[int]],
i: int,
j: int,
destination_row: int,
destination_column: int,
solutions: list[list[int]],
) -> bool:
""" """
This method is recursive starting from (i, j) and going in one of four directions: This method is recursive starting from (i, j) and going in one of four directions:
up, down, left, right. up, down, left, right.
If a path is found to destination it returns True otherwise it returns False. If a path is found to destination it returns True otherwise it returns False.
Parameters: Parameters
maze(2D matrix) : maze maze: A two dimensional matrix of zeros and ones.
i, j : coordinates of matrix i, j : coordinates of matrix
solutions(2D matrix) : solutions solutions: A two dimensional matrix of solutions.
Returns: Returns:
Boolean if path is found True, Otherwise False. Boolean if path is found True, Otherwise False.
""" """
size = len(maze) size = len(maze)
# Final check point. # Final check point.
if i == j == (size - 1): if i == destination_row and j == destination_column and maze[i][j] == 0:
solutions[i][j] = 1 solutions[i][j] = 0
return True return True
lower_flag = (not i < 0) and (not j < 0) # Check lower bounds lower_flag = (not i < 0) and (not j < 0) # Check lower bounds
@ -93,21 +166,27 @@ def run_maze(maze: list[list[int]], i: int, j: int, solutions: list[list[int]])
if lower_flag and upper_flag: if lower_flag and upper_flag:
# check for already visited and block points. # check for already visited and block points.
block_flag = (not solutions[i][j]) and (not maze[i][j]) block_flag = (solutions[i][j]) and (not maze[i][j])
if block_flag: if block_flag:
# check visited # check visited
solutions[i][j] = 1 solutions[i][j] = 0
# check for directions # check for directions
if ( if (
run_maze(maze, i + 1, j, solutions) run_maze(maze, i + 1, j, destination_row, destination_column, solutions)
or run_maze(maze, i, j + 1, solutions) or run_maze(
or run_maze(maze, i - 1, j, solutions) maze, i, j + 1, destination_row, destination_column, solutions
or run_maze(maze, i, j - 1, solutions) )
or run_maze(
maze, i - 1, j, destination_row, destination_column, solutions
)
or run_maze(
maze, i, j - 1, destination_row, destination_column, solutions
)
): ):
return True return True
solutions[i][j] = 0 solutions[i][j] = 1
return False return False
return False return False
@ -115,4 +194,4 @@ def run_maze(maze: list[list[int]], i: int, j: int, solutions: list[list[int]])
if __name__ == "__main__": if __name__ == "__main__":
import doctest import doctest
doctest.testmod() doctest.testmod(optionflags=doctest.NORMALIZE_WHITESPACE)