forked from UNN/2026-rff_mp
67 lines
2.6 KiB
Python
67 lines
2.6 KiB
Python
|
|
import heapq
|
|||
|
|
from typing import List, Dict
|
|||
|
|
from .path_finding_strategy import PathFindingStrategy
|
|||
|
|
|
|||
|
|
class AStarStrategy(PathFindingStrategy):
|
|||
|
|
"""A* поиск с эвристикой (манхэттенское расстояние)"""
|
|||
|
|
|
|||
|
|
def __init__(self):
|
|||
|
|
self._visited_count = 0
|
|||
|
|
|
|||
|
|
@property
|
|||
|
|
def name(self) -> str:
|
|||
|
|
return "AStar"
|
|||
|
|
|
|||
|
|
def _heuristic(self, cell, exit_cell) -> int:
|
|||
|
|
"""Манхэттенское расстояние между клетками"""
|
|||
|
|
return abs(cell.x - exit_cell.x) + abs(cell.y - exit_cell.y)
|
|||
|
|
|
|||
|
|
def find_path(self, maze, start, exit_cell) -> List:
|
|||
|
|
"""Находит путь с помощью A*"""
|
|||
|
|
if not start or not exit_cell:
|
|||
|
|
return []
|
|||
|
|
|
|||
|
|
# Приоритетная очередь (F-значение, ID для уникальности, клетка)
|
|||
|
|
open_set = []
|
|||
|
|
heapq.heappush(open_set, (0, id(start), start))
|
|||
|
|
|
|||
|
|
# Откуда пришли в каждую клетку
|
|||
|
|
came_from = {}
|
|||
|
|
|
|||
|
|
# Стоимость пути от старта до клетки (G-значение)
|
|||
|
|
g_score = {start: 0}
|
|||
|
|
|
|||
|
|
# Оценочная стоимость (F-значение = G + H)
|
|||
|
|
f_score = {start: self._heuristic(start, exit_cell)}
|
|||
|
|
|
|||
|
|
self._visited_count = 0
|
|||
|
|
|
|||
|
|
while open_set:
|
|||
|
|
_, _, current = heapq.heappop(open_set)
|
|||
|
|
self._visited_count += 1
|
|||
|
|
|
|||
|
|
# Нашли выход
|
|||
|
|
if current == exit_cell:
|
|||
|
|
return self._reconstruct_path(came_from, 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)
|
|||
|
|
f_score[neighbor] = f
|
|||
|
|
heapq.heappush(open_set, (f, id(neighbor), neighbor))
|
|||
|
|
|
|||
|
|
# Путь не найден
|
|||
|
|
return []
|
|||
|
|
|
|||
|
|
def _reconstruct_path(self, came_from: Dict, current) -> List:
|
|||
|
|
"""Восстанавливает путь от старта до exit"""
|
|||
|
|
path = [current]
|
|||
|
|
while current in came_from:
|
|||
|
|
current = came_from[current]
|
|||
|
|
path.append(current)
|
|||
|
|
return list(reversed(path))
|