2026-rff_mp/ZelentsovAV/task2/strategies.py
2026-05-24 20:33:47 +03:00

99 lines
3.2 KiB
Python

from abc import ABC, abstractmethod
from collections import deque
from heapq import heappush, heappop
from typing import List, Dict, Optional
from models import Cell, Maze
class PathFindingStrategy(ABC):
@abstractmethod
def find_path(self, maze: Maze, start: Cell, exit_cell: Cell) -> List[Cell]:
pass
class BFSStrategy(PathFindingStrategy):
def find_path(self, maze: Maze, start: Cell, exit_cell: Cell) -> List[Cell]:
queue = deque([start])
visited = {start}
parent: Dict[Cell, Optional[Cell]] = {start: None}
while queue:
current = queue.popleft()
if current == exit_cell:
return self._reconstruct_path(parent, current)
for neighbor in maze.get_neighbors(current):
if neighbor not in visited:
visited.add(neighbor)
parent[neighbor] = current
queue.append(neighbor)
return []
def _reconstruct_path(self, parent: Dict[Cell, Optional[Cell]], current: Cell) -> List[Cell]:
path = []
while current is not None:
path.append(current)
current = parent.get(current)
return list(reversed(path))
class DFSStrategy(PathFindingStrategy):
def find_path(self, maze: Maze, start: Cell, exit_cell: Cell) -> List[Cell]:
stack = [(start, [start])]
visited = {start}
while stack:
current, path = stack.pop()
if current == exit_cell:
return path
for neighbor in maze.get_neighbors(current):
if neighbor not in visited:
visited.add(neighbor)
stack.append((neighbor, path + [neighbor]))
return []
class AStarStrategy(PathFindingStrategy):
def _heuristic(self, cell: Cell, exit_cell: Cell) -> int:
return abs(cell.x - exit_cell.x) + abs(cell.y - exit_cell.y)
def find_path(self, maze: Maze, start: Cell, exit_cell: Cell) -> List[Cell]:
counter = 0
open_set = [(self._heuristic(start, exit_cell), counter, start)]
g_score: Dict[Cell, float] = {start: 0}
parent: Dict[Cell, Optional[Cell]] = {start: None}
while open_set:
_, _, current = heappop(open_set)
if current == exit_cell:
return self._reconstruct_path(parent, current)
for neighbor in maze.get_neighbors(current):
tentative_g = g_score[current] + 1
if neighbor not in g_score or tentative_g < g_score[neighbor]:
parent[neighbor] = current
g_score[neighbor] = tentative_g
counter += 1
f = tentative_g + self._heuristic(neighbor, exit_cell)
heappush(open_set, (f, counter, neighbor))
return []
def _reconstruct_path(self, parent: Dict[Cell, Optional[Cell]], current: Cell) -> List[Cell]:
path = []
while current is not None:
path.append(current)
current = parent.get(current)
return list(reversed(path))