diff --git a/nikolaevda/task2/Zadanie2.py b/nikolaevda/task2/Zadanie2.py index 1ce8a09..3654457 100644 --- a/nikolaevda/task2/Zadanie2.py +++ b/nikolaevda/task2/Zadanie2.py @@ -98,4 +98,185 @@ class TextFileMazeBuilder(MazeBuilder): if start_count != 1 or exit_count != 1: raise ValueError(f"Ошибка: S={start_count}, E={exit_count} (нужно по одному)") - return maze \ No newline at end of file + return maze + +class SearchStats: + """статистика поиска""" + def __init__(self, time_ms=0, visited_cells=0, path_length=0): + self.time_ms = time_ms + self.visited_cells = visited_cells + self.path_length = path_length + + def __str__(self): + return f"Время: {self.time_ms:.2f} мс, Посещено: {self.visited_cells}, Длина пути: {self.path_length}" + + +class PathFindingStrategy: + """интерфейс стратегии поиска пути""" + + def findPath(self, maze, start, exit): + raise NotImplementedError + + def get_name(self): + raise NotImplementedError + + +class BFSStrategy(PathFindingStrategy): + """BFS - гарантирует кратчайший путь""" + + def get_name(self): + return "BFS (Поиск в ширину)" + + def findPath(self, maze, start, exit): + from collections import deque + + if not start or not exit: + return [], 0 + + queue = deque([(start, [start])]) + visited = {start} + + while queue: + current, path = queue.popleft() + + if current == exit: + return path, len(visited) + + for neighbor in maze.get_neighbors(current): + if neighbor not in visited: + visited.add(neighbor) + queue.append((neighbor, path + [neighbor])) + + return [], len(visited) + + +class DFSStrategy(PathFindingStrategy): + """DFS - быстрый, но не обязательно кратчайший""" + + def get_name(self): + return "DFS (Поиск в глубину)" + + def findPath(self, maze, start, exit): + if not start or not exit: + return [], 0 + + stack = [(start, [start])] + visited = {start} + + while stack: + current, path = stack.pop() + + if current == exit: + return path, len(visited) + + for neighbor in maze.get_neighbors(current): + if neighbor not in visited: + visited.add(neighbor) + stack.append((neighbor, path + [neighbor])) + + return [], len(visited) + + +class AStarStrategy(PathFindingStrategy): + """алгоритм A Star - оптимальный и быстрый с эвристикой""" + + def get_name(self): + return "A Star" + + def _heuristic(self, a, b): + return abs(a.x - b.x) + abs(a.y - b.y) + + def findPath(self, maze, start, exit): + if not start or not exit: + return [], 0 + + import heapq + + heap = [] + counter = 0 + start_f = self._heuristic(start, exit) + heapq.heappush(heap, (start_f, counter, start)) + + came_from = {} + g_score = {start: 0} + f_score = {start: start_f} + visited = set() + visited.add(start) + + while heap: + current_f, _, current = heapq.heappop(heap) + + if current == exit: + path = [] + while current in came_from: + path.append(current) + current = came_from[current] + path.append(start) + path.reverse() + return path, len(visited) + + if current_f > f_score.get(current, float('inf')): + continue + + for neighbor in maze.get_neighbors(current): + tentative_g = g_score[current] + 1 + + if tentative_g < g_score.get(neighbor, float('inf')): + came_from[neighbor] = current + g_score[neighbor] = tentative_g + new_f = tentative_g + self._heuristic(neighbor, exit) + f_score[neighbor] = new_f + counter += 1 + heapq.heappush(heap, (new_f, counter, neighbor)) + visited.add(neighbor) + + return [], len(visited) + + +class DijkstraStrategy(PathFindingStrategy): + """алгоритм Дейкстры""" + + def get_name(self): + return "Дейкстра (Dijkstra)" + + def findPath(self, maze, start, exit): + if not start or not exit: + return [], 0 + + import heapq + + heap = [] + counter = 0 + heapq.heappush(heap, (0, counter, start)) + + distances = {start: 0} + came_from = {} + visited = set() + visited.add(start) + + while heap: + current_dist, _, current = heapq.heappop(heap) + + if current == exit: + path = [] + while current in came_from: + path.append(current) + current = came_from[current] + path.append(start) + path.reverse() + return path, len(visited) + + if current_dist > distances.get(current, float('inf')): + continue + + for neighbor in maze.get_neighbors(current): + new_dist = current_dist + 1 + + if new_dist < distances.get(neighbor, float('inf')): + distances[neighbor] = new_dist + came_from[neighbor] = current + counter += 1 + heapq.heappush(heap, (new_dist, counter, neighbor)) + visited.add(neighbor) + + return [], len(visited) \ No newline at end of file