diff --git a/MusinAA/task2/mazeObjects/path.py b/MusinAA/task2/mazeObjects/path.py new file mode 100644 index 0000000..9579dbc --- /dev/null +++ b/MusinAA/task2/mazeObjects/path.py @@ -0,0 +1,4 @@ +class Path: + def __init__(self, array:list[Cell]|None, visited_cells:int): + self.array = array + self.visited_cells = visited_cells \ No newline at end of file diff --git a/MusinAA/task2/mazeSolver.py b/MusinAA/task2/mazeSolver.py new file mode 100644 index 0000000..d346b36 --- /dev/null +++ b/MusinAA/task2/mazeSolver.py @@ -0,0 +1,43 @@ +from task2.mazeObjects.maze import Maze +from task2.mazeObjects.cell import Cell +from task2.strategyObjects.pathFindingStrategy import PathFindingStrategy + +import time + +class SearchStats: + """Время выполнения в миллисекундах, количество посещённых клеток, длина найденного пути""" + def __init__(self, path: list[Cell]|None, duration:float, visited_cells:int, path_len:int, strategy_name:str): + self.duration = duration + self.visited_cells = visited_cells + self.path_len = path_len + self.path = path + self.strategy_name = strategy_name + +class MazeSolver: + """ + MazeSolver содержит поля maze и strategy. + Метод setStrategy(strategy) для динамической смены алгоритма. + Метод solve() вызывает strategy.findPath(...) и возвращает объект SearchStats (время выполнения в миллисекундах, + количество посещённых клеток, длина найденного пути). + Для замера времени используйте time.perf_counter() до и после вызова стратегии. + """ + + def __init__(self, maze:Maze, strategy:PathFindingStrategy): + self.maze = maze + self.strategy = strategy + + def setStrategy(self, strategy:PathFindingStrategy): + self.strategy = strategy + + def getStrategyName(self): + return self.strategy.__class__.__name__ + + def solve(self): + t_start = time.perf_counter() + path = self.strategy.findPath(self.maze, self.maze.startCell, self.maze.endCell) + duration = time.perf_counter() - t_start + + path_len = len(path.array) if path.array else 0 + strategy_name = self.getStrategyName() + + return SearchStats(path.array, duration, path.visited_cells, path_len, strategy_name) \ No newline at end of file diff --git a/MusinAA/task2/strategyObjects/AStar.py b/MusinAA/task2/strategyObjects/AStar.py index 5b4dde1..43024bd 100644 --- a/MusinAA/task2/strategyObjects/AStar.py +++ b/MusinAA/task2/strategyObjects/AStar.py @@ -6,13 +6,14 @@ 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): + 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]] = [ @@ -29,7 +30,7 @@ class AStar(PathFindingStrategy): visited.add(current) if current == exit: - return restorePath(parents, exit) + return Path(restorePath(parents, exit), len(visited)) for neighbor in maze.getNeighbors(current): tentative_score = g_score[current] @@ -42,4 +43,4 @@ class AStar(PathFindingStrategy): heap, (priority, heuristic, next(tie_breaker), neighbor), ) - return [] \ No newline at end of file + return Path(None, len(visited)) \ No newline at end of file diff --git a/MusinAA/task2/strategyObjects/BFS.py b/MusinAA/task2/strategyObjects/BFS.py index 6379a6a..aa84fb9 100644 --- a/MusinAA/task2/strategyObjects/BFS.py +++ b/MusinAA/task2/strategyObjects/BFS.py @@ -3,13 +3,14 @@ from task2.strategyObjects.util import restorePath from task2.mazeObjects.maze import Maze from task2.mazeObjects.cell import Cell +from task2.mazeObjects.path import Path import queue class BFS(PathFindingStrategy): """Поиск в ширину – гарантирует кратчайший путь по количеству шагов. Возвращает None, если пути нет""" - def findPath(self, maze: Maze, start: Cell, exit: Cell): + def findPath(self, maze: Maze, start: Cell, exit: Cell) -> Path: visited = dict() parents = dict() q = queue.Queue() @@ -31,4 +32,5 @@ class BFS(PathFindingStrategy): visited[hood] = visited[current] + 1 parents[hood] = current q.put(hood) - return restorePath(parents, exit) \ No newline at end of file + + return Path(restorePath(parents, exit), len(visited)) \ No newline at end of file diff --git a/MusinAA/task2/strategyObjects/DFS.py b/MusinAA/task2/strategyObjects/DFS.py index b4e0fb6..e72dd00 100644 --- a/MusinAA/task2/strategyObjects/DFS.py +++ b/MusinAA/task2/strategyObjects/DFS.py @@ -3,12 +3,12 @@ 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 DFS(PathFindingStrategy): """Поиск в глубину – быстрый, но не обязательно кратчайший. Возвращает None, если пути нет""" - def findPath(self, maze: Maze, start: Cell, exit: Cell): + def findPath(self, maze: Maze, start: Cell, exit: Cell) -> Path: visited = dict() parents = dict() stack = [] @@ -31,4 +31,4 @@ class DFS(PathFindingStrategy): parents[hood] = current stack.append(hood) - return restorePath(parents, exit) \ No newline at end of file + return Path(restorePath(parents, exit), len(visited)) \ No newline at end of file diff --git a/MusinAA/task2/strategyObjects/pathFindingStrategy.py b/MusinAA/task2/strategyObjects/pathFindingStrategy.py index 800cb5b..9417065 100644 --- a/MusinAA/task2/strategyObjects/pathFindingStrategy.py +++ b/MusinAA/task2/strategyObjects/pathFindingStrategy.py @@ -2,12 +2,13 @@ from abc import ABC, abstractmethod from task2.mazeObjects.maze import Maze from task2.mazeObjects.cell import Cell +from task2.mazeObjects.path import Path class PathFindingStrategy(ABC): """Интерфейс PathFindingStrategy с методом findPath(maze, start, exit), возвращающим список клеток пути (от старта до выхода включительно) или пустой список, если пути нет.""" @abstractmethod - def findPath(self, maze: Maze, start: Cell, exit: Cell): + def findPath(self, maze: Maze, start: Cell, exit: Cell) -> Path: """Возвращает список клеток пути от старта до выхода включительно. Пути нет - пустой список.""" raise NotImplementedError \ No newline at end of file