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
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.
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 :
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:
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],
... [0, 0, 0, 0, 0],
... [1, 0, 1, 0, 1],
... [0, 0, 1, 0, 0],
... [1, 0, 0, 1, 0]]
>>> solve_maze(maze)
[1, 0, 0, 0, 0]
[1, 1, 1, 1, 0]
[0, 0, 0, 1, 0]
[0, 0, 0, 1, 1]
[0, 0, 0, 0, 1]
True
>>> solve_maze(maze,0,0,len(maze)-1,len(maze)-1) # doctest: +NORMALIZE_WHITESPACE
[[0, 1, 1, 1, 1],
[0, 0, 0, 0, 1],
[1, 1, 1, 0, 1],
[1, 1, 1, 0, 0],
[1, 1, 1, 1, 0]]
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],
... [0, 0, 0, 0, 0],
... [0, 0, 0, 0, 1],
... [0, 0, 0, 0, 0],
... [0, 0, 0, 0, 0]]
>>> solve_maze(maze)
[1, 0, 0, 0, 0]
[1, 0, 0, 0, 0]
[1, 0, 0, 0, 0]
[1, 0, 0, 0, 0]
[1, 1, 1, 1, 1]
True
>>> solve_maze(maze,0,0,len(maze)-1,len(maze)-1) # doctest: +NORMALIZE_WHITESPACE
[[0, 1, 1, 1, 1],
[0, 1, 1, 1, 1],
[0, 1, 1, 1, 1],
[0, 1, 1, 1, 1],
[0, 0, 0, 0, 0]]
>>> maze = [[0, 0, 0],
... [0, 1, 0],
... [1, 0, 0]]
>>> solve_maze(maze)
[1, 1, 1]
[0, 0, 1]
[0, 0, 1]
True
>>> solve_maze(maze,0,0,len(maze)-1,len(maze)-1) # doctest: +NORMALIZE_WHITESPACE
[[0, 0, 0],
[1, 1, 0],
[1, 1, 0]]
>>> maze = [[0, 1, 0],
>>> maze = [[1, 0, 0],
... [0, 1, 0],
... [1, 0, 0]]
>>> solve_maze(maze)
No solution exists!
False
>>> solve_maze(maze,0,1,len(maze)-1,len(maze)-1) # doctest: +NORMALIZE_WHITESPACE
[[1, 0, 0],
[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],
... [1, 0]]
>>> solve_maze(maze)
No solution exists!
False
>>> solve_maze(maze,2,0,len(maze)-1,len(maze)-1)
Traceback (most recent call last):
...
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)
# 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.
solutions = [[0 for _ in range(size)] for _ in range(size)]
solved = run_maze(maze, 0, 0, solutions)
solutions = [[1 for _ in range(size)] for _ in range(size)]
solved = run_maze(
maze, source_row, source_column, destination_row, destination_column, solutions
)
if solved:
print("\n".join(str(row) for row in solutions))
return solutions
else:
print("No solution exists!")
return solved
raise ValueError("No solution exists!")
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:
up, down, left, right.
If a path is found to destination it returns True otherwise it returns False.
Parameters:
maze(2D matrix) : maze
Parameters
maze: A two dimensional matrix of zeros and ones.
i, j : coordinates of matrix
solutions(2D matrix) : solutions
solutions: A two dimensional matrix of solutions.
Returns:
Boolean if path is found True, Otherwise False.
"""
size = len(maze)
# Final check point.
if i == j == (size - 1):
solutions[i][j] = 1
if i == destination_row and j == destination_column and maze[i][j] == 0:
solutions[i][j] = 0
return True
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:
# 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:
# check visited
solutions[i][j] = 1
solutions[i][j] = 0
# check for directions
if (
run_maze(maze, i + 1, j, solutions)
or run_maze(maze, i, j + 1, solutions)
or run_maze(maze, i - 1, j, solutions)
or run_maze(maze, i, j - 1, solutions)
run_maze(maze, i + 1, j, destination_row, destination_column, solutions)
or run_maze(
maze, i, j + 1, destination_row, destination_column, 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
solutions[i][j] = 0
solutions[i][j] = 1
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__":
import doctest
doctest.testmod()
doctest.testmod(optionflags=doctest.NORMALIZE_WHITESPACE)