2026-rff_mp/zhigalovrd/lab2/strategies.py

86 lines
3.2 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
from typing import List, Tuple, Dict, Optional
import heapq
from maze import Maze, Cell
class PathFindingStrategy(ABC):
@abstractmethod
def find_path(self, maze: Maze, start: Cell, exit: Cell) -> Tuple[List[Cell], int]:
"""Возвращает (путь_список_клеток, количество_посещённых_клеток)"""
pass
class BFSStrategy(PathFindingStrategy):
def find_path(self, maze: Maze, start: Cell, exit: Cell) -> Tuple[List[Cell], int]:
queue = deque([start])
visited = {start}
parent = {start: None}
while queue:
current = queue.popleft()
if current is exit:
return self._reconstruct_path(parent, exit), len(visited)
for nb in maze.get_neighbors(current):
if nb not in visited:
visited.add(nb)
parent[nb] = current
queue.append(nb)
return [], len(visited)
def _reconstruct_path(self, parent: Dict[Cell, Optional[Cell]], end: Cell) -> List[Cell]:
path = []
cur = end
while cur is not None:
path.append(cur)
cur = parent[cur]
path.reverse()
return path
class DFSStrategy(PathFindingStrategy):
def find_path(self, maze: Maze, start: Cell, exit: Cell) -> Tuple[List[Cell], int]:
stack = [(start, [start])]
visited = {start}
while stack:
current, path = stack.pop()
if current is exit:
return path, len(visited)
for nb in maze.get_neighbors(current):
if nb not in visited:
visited.add(nb)
stack.append((nb, path + [nb]))
return [], len(visited)
class AStarStrategy(PathFindingStrategy):
@staticmethod
def heuristic(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) -> Tuple[List[Cell], int]:
open_set = []
heapq.heappush(open_set, (0, start))
came_from = {}
g_score = {start: 0}
f_score = {start: self.heuristic(start, exit)}
visited_count = 0
while open_set:
_, current = heapq.heappop(open_set)
visited_count += 1
if current is exit:
path = self._reconstruct_path(came_from, exit)
return path, visited_count
for nb in maze.get_neighbors(current):
tentative_g = g_score[current] + 1
if nb not in g_score or tentative_g < g_score[nb]:
came_from[nb] = current
g_score[nb] = tentative_g
f_score[nb] = tentative_g + self.heuristic(nb, exit)
heapq.heappush(open_set, (f_score[nb], nb))
return [], visited_count
def _reconstruct_path(self, came_from: Dict[Cell, Cell], current: Cell) -> List[Cell]:
path = [current]
while current in came_from:
current = came_from[current]
path.append(current)
path.reverse()
return path