2026-rff_mp/osipovamd/maze_project/pathfinding_strategies.py
2026-05-27 22:49:24 +03:00

123 lines
4.0 KiB
Python

from abc import ABC, abstractmethod
from typing import List, Dict, Optional
from collections import deque
import heapq
from maze_model import Maze, Cell
class PathFindingStrategy(ABC):
@abstractmethod
def find_path(self, maze: Maze, start: Cell, exit_cell: Cell) -> List[Cell]:
pass
@abstractmethod
def get_name(self) -> str:
pass
class BFSStrategy(PathFindingStrategy):
def find_path(self, maze: Maze, start: Cell, exit_cell: Cell) -> List[Cell]:
if start == exit_cell:
return [start]
queue = deque([start])
came_from: Dict[Cell, Optional[Cell]] = {start: None}
while queue:
current = queue.popleft()
if current == exit_cell:
return self._reconstruct_path(came_from, start, exit_cell)
for neighbor in maze.get_neighbors(current):
if neighbor not in came_from:
came_from[neighbor] = current
queue.append(neighbor)
return []
def _reconstruct_path(self, came_from, start, exit_cell):
path = []
current = exit_cell
while current is not None:
path.append(current)
current = came_from.get(current)
path.reverse()
return path
def get_name(self) -> str:
return "BFS (Поиск в ширину)"
class DFSStrategy(PathFindingStrategy):
def find_path(self, maze: Maze, start: Cell, exit_cell: Cell) -> List[Cell]:
if start == exit_cell:
return [start]
stack = [start]
came_from: Dict[Cell, Optional[Cell]] = {start: None}
while stack:
current = stack.pop()
if current == exit_cell:
return self._reconstruct_path(came_from, start, exit_cell)
for neighbor in maze.get_neighbors(current):
if neighbor not in came_from:
came_from[neighbor] = current
stack.append(neighbor)
return []
def _reconstruct_path(self, came_from, start, exit_cell):
path = []
current = exit_cell
while current is not None:
path.append(current)
current = came_from.get(current)
path.reverse()
return path
def get_name(self) -> str:
return "DFS (Поиск в глубину)"
class AStarStrategy(PathFindingStrategy):
def _heuristic(self, cell: Cell, target: Cell) -> int:
return abs(cell.x - target.x) + abs(cell.y - target.y)
def find_path(self, maze: Maze, start: Cell, exit_cell: Cell) -> List[Cell]:
if start == exit_cell:
return [start]
counter = 0
open_set = [(0, counter, start)]
g_score: Dict[Cell, float] = {start: 0}
came_from: Dict[Cell, Optional[Cell]] = {start: None}
open_set_cells = {start}
while open_set:
_, _, current = heapq.heappop(open_set)
open_set_cells.remove(current)
if current == exit_cell:
return self._reconstruct_path(came_from, start, exit_cell)
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]:
came_from[neighbor] = current
g_score[neighbor] = tentative_g
f = tentative_g + self._heuristic(neighbor, exit_cell)
if neighbor not in open_set_cells:
counter += 1
heapq.heappush(open_set, (f, counter, neighbor))
open_set_cells.add(neighbor)
return []
def _reconstruct_path(self, came_from, start, exit_cell):
path = []
current = exit_cell
while current is not None:
path.append(current)
current = came_from.get(current)
path.reverse()
return path
def get_name(self) -> str:
return "A* (A-Star)"