import heapq from itertools import count from typing import Optional from task2.strategyObjects.pathFindingStrategy import PathFindingStrategy from task2.strategyObjects.util import restorePath from task2.mazeObjects.maze import Maze from task2.mazeObjects.cell import Cell from task2.mazeObjects.path import Path class AStar(PathFindingStrategy): """Алгоритм с эвристикой (etc. манхэттенское расстояние) – компромисс между скоростью и оптимальностью.""" def heuristic(self, first: Cell, second: Cell) -> int: return abs(first.x - second.x) + abs(first.y - second.y) def findPath(self, maze: Maze, start: Cell, exit: Cell) -> Path: tie_breaker = count() start_heuristic = self.heuristic(start, exit) heap: list[tuple[int, int, int, Cell]] = [ (start_heuristic, start_heuristic, next(tie_breaker), start) ] g_score: dict[Cell, int] = {start: 0} parents: dict[Cell, Optional[Cell]] = {start: None} visited: set[Cell] = set() while heap: _, _, _, current = heapq.heappop(heap) if current in visited: continue visited.add(current) if current.isExit: return Path(restorePath(parents, exit), len(visited)) for neighbor in maze.getNeighbors(current): tentative_score = g_score[current] if tentative_score < g_score.get(neighbor, 10**12): g_score[neighbor] = tentative_score parents[neighbor] = current heuristic = self.heuristic(neighbor, exit) priority = tentative_score + heuristic heapq.heappush( heap, (priority, heuristic, next(tie_breaker), neighbor), ) return Path(None, len(visited))