2026-rff_mp/MarkinAM/2/strategies.py
2026-05-25 09:57:30 +03:00

119 lines
4.3 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

from abc import ABC, abstractmethod
from collections import deque
import heapq
from classes import Cell, Maze
class PathFindingStrategy(ABC):
"""Интерфейс стратегии поиска пути."""
@abstractmethod
def find_path(self, maze: Maze, start: Cell, exit_cell: Cell) -> list[Cell]:
...
# Вспомогательный метод восстановления пути по словарю предшественников
@staticmethod
def _reconstruct_path(came_from: dict, start: Cell, goal: Cell) -> list[Cell]:
path = []
current = goal
while current != start:
path.append(current)
current = came_from[current]
path.append(start)
path.reverse()
return path
# ── BFS ──────────────────────────────────────────────────────────────────────
class BFSStrategy(PathFindingStrategy):
def find_path(self, maze: Maze, start: Cell, exit_cell: Cell) -> list[Cell]:
queue = deque([start])
came_from: dict[Cell, Cell | None] = {start: None}
self.visited_count = 0
while queue:
current = queue.popleft()
self.visited_count += 1
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 [] # путь не найден
# ── DFS ──────────────────────────────────────────────────────────────────────
class DFSStrategy(PathFindingStrategy):
def find_path(self, maze: Maze, start: Cell, exit_cell: Cell) -> list[Cell]:
stack = [start]
came_from: dict[Cell, Cell | None] = {start: None}
self.visited_count = 0
while stack:
current = stack.pop()
self.visited_count += 1
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 []
# ── A* ───────────────────────────────────────────────────────────────────────
class AStarStrategy(PathFindingStrategy):
"""A* с манхэттенской эвристикой"""
def __init__(self):
self.visited_count = 0
def _heuristic(self, a: Cell, b: Cell) -> int:
return abs(a.x - b.x) + abs(a.y - b.y)
def find_path(self, maze: Maze, start: Cell, exit_cell: Cell) -> list[Cell]:
g_score = {start: 0}
parent: dict[Cell] = {start: None}
open_heap = [(self._heuristic(start, exit_cell), 0, start)]
closed_set: set[Cell] = set() # уже обработанные клетки
self.visited_count = 0
counter = 0 # счётчик для устранения неоднозначности
while open_heap:
_, _, current = heapq.heappop(open_heap)
if current in closed_set:
continue
closed_set.add(current)
self.visited_count += 1
if current == exit_cell:
return self._reconstruct_path(parent, start, exit_cell)
for neighbor in maze.get_neighbors(current):
if neighbor in closed_set:
continue
tentative_g = g_score[current]
if tentative_g < g_score.get(neighbor, float('inf')):
g_score[neighbor] = tentative_g
parent[neighbor] = current
f = tentative_g + self._heuristic(neighbor, exit_cell)
counter += 1
heapq.heappush(open_heap, (f, counter, neighbor))
return []