BFS & DFS
from abc import abstractmethod
from enum import IntEnum
from typing import NamedTuple, Optional
import matplotlib.pyplot as plt
import numpy as np
from utils import Stack,Queue
class Cell(IntEnum):
EMPTY = 90
BLOCKED = 0
START = 210
END = 190
PATH = 150
class MazeLocation(NamedTuple):
row: int
col: int
class Maze():
class _Node():
def __init__(self, state, parent):
self.state = state
self.parent = parent
def __init__(self, rows: int = 10, cols: int = 10,
sparse: float = 0.2, seed: int = 365,
start: MazeLocation = MazeLocation(0, 0),
end: MazeLocation = MazeLocation(9, 9), *,
grid: Optional[np.array] = None) -> None:
np.random.seed(seed)
self._start: MazeLocation = start
self._end: MazeLocation = end
self.A = 0
print('起点坐标是:{}'.format (self._start))
if grid is None:
self._grid = np.random.choice([Cell.BLOCKED, Cell.EMPTY],
(rows, cols), p=[sparse, 1 - sparse])
else:
self._grid = grid
self._grid[start] = Cell.START
self._grid[end] = Cell.END
def _test_goal(self, m1: MazeLocation) -> bool:
return m1 == self._end
def _success(self, m1):
location = []
row, col = self._grid.shape
if m1.row + 1 < row and self._grid[m1.row + 1, m1.col] != Cell.BLOCKED:
location.append(MazeLocation(m1.row + 1, m1.col))
if m1.row - 1 >= 0 and self._grid[m1.row - 1, m1.col] != Cell.BLOCKED:
location.append(MazeLocation(m1.row - 1, m1.col))
if m1.col + 1 < col and self._grid[m1.row, m1.col + 1] != Cell.BLOCKED:
location.append(MazeLocation(m1.row, m1.col + 1))
if m1.col - 1 >= 0 and self._grid[m1.row, m1.col - 1] != Cell.BLOCKED:
location.append(MazeLocation(m1.row, m1.col - 1))
return location
def _draw(self, pause: float) -> None:
if self.A == 0:
plt.title('Depth First Search')
else:
plt.title("Bread thFirst Search")
plt.imshow(self._grid, cmap='rainbow', interpolation='nearest')
plt.xticks([])
plt.yticks([])
plt.pause(interval=pause)
plt.cla()
def draw(self, colormap='rainbow') -> None:
plt.close()
fig, ax = plt.subplots()
ax.imshow(self._grid, cmap=colormap)
ax.set_xticks([])
ax.set_yticks([])
if self.A == 0:
plt.title("DFS")
else:
plt.title("BFS")
plt.show()
def show_path(self, pause: float = 0.5, *, plot: bool = True) -> None:
if pause <= 0:
raise ValueError('pause must be more than 0')
path = self._search()
if path is None:
print('没有找到路径')
return
path = path.parent
while path.parent is not None:
self._grid[path.state] = Cell.PATH
if plot:
self._draw(pause)
path = path.parent
print('Path Done')
class DepthFirstSearch(Maze):
def _search(self):
self.A = 0
stack = Stack()
initial = self._Node(self._start, None)
marked = {initial.state}
stack.push(initial)
while stack:
parent = stack.pop()
state = parent.state
if self._test_goal(state):
return parent
children = self._success(state)
for child in children:
if child not in marked:
marked.add(child)
stack.push(self._Node(child, parent))
class BreadthFirstSearch(Maze):
def _search(self):
self.A = 1
queue = Queue()
initial: BreadthFirstSearch._Node = self._Node(self._start, None)
marked: Set[MazeLocation] = {initial.state}
queue.push(initial)
while queue:
parent: DepthFirstSearch._Node = queue.pop()
state: MazeLocation = parent.state
if self._test_goal(state):
return parent
children: List[MazeLocation] = self._success(state)
for child in children:
if child not in marked:
marked.add(child)
queue.push(self._Node(child, parent))
if __name__ == "__main__":
maze = BreadthFirstSearch(rows=500, cols=500, sparse = 0.5, start = MazeLocation(499,499), end=MazeLocation(0, 0), seed=50)
maze.show_path(0.001, plot=True)
maze.draw()