From d37835d9dd5b8fd43ef3ffb1e929c975ce619cb7 Mon Sep 17 00:00:00 2001 From: root Date: Thu, 3 Sep 2026 02:14:45 +0300 Subject: [PATCH] [2] 2-nd version of maze(with maze solver) ;) --- AgapovaDS/docs/data/2-nd/maze.py | 165 +++++++++++++++++++++++++------ 1 file changed, 133 insertions(+), 32 deletions(-) diff --git a/AgapovaDS/docs/data/2-nd/maze.py b/AgapovaDS/docs/data/2-nd/maze.py index 6bfe21a..0e6d656 100644 --- a/AgapovaDS/docs/data/2-nd/maze.py +++ b/AgapovaDS/docs/data/2-nd/maze.py @@ -1,7 +1,8 @@ -# maze.py – версия 1: модель лабиринта и загрузка из текстового файла +import time +from collections import deque +import heapq class Cell: - """Клетка лабиринта.""" def __init__(self, x, y, is_wall=False, is_start=False, is_exit=False): self.x = x self.y = y @@ -14,7 +15,6 @@ class Cell: class Maze: - """Модель лабиринта.""" def __init__(self, width, height): self.width = width self.height = height @@ -28,7 +28,6 @@ class Maze: return None def get_neighbors(self, cell): - """Возвращает список проходимых соседей (вверх, вниз, влево, вправо).""" neighbors = [] for dx, dy in [(-1,0), (1,0), (0,-1), (0,1)]: nx, ny = cell.x + dx, cell.y + dy @@ -39,13 +38,11 @@ class Maze: class MazeBuilder: - """Интерфейс строителя лабиринта.""" def build_from_file(self, filename): raise NotImplementedError class TextFileMazeBuilder(MazeBuilder): - """Строитель лабиринта из текстового файла.""" def build_from_file(self, filename): with open(filename, 'r', encoding='utf-8') as f: lines = f.readlines() @@ -73,32 +70,136 @@ class TextFileMazeBuilder(MazeBuilder): return maze -# Тестирование загрузки +class PathFindingStrategy: + def find_path(self, maze, start, exit): + raise NotImplementedError + + +class BFSStrategy(PathFindingStrategy): + def find_path(self, maze, start, exit): + if start == exit: + return [start] + queue = deque([start]) + visited = {start} + parent = {start: None} + while queue: + current = queue.popleft() + if current == exit: + break + for neighbor in maze.get_neighbors(current): + if neighbor not in visited: + visited.add(neighbor) + parent[neighbor] = current + queue.append(neighbor) + if exit not in parent: + return [] + path = [] + step = exit + while step is not None: + path.append(step) + step = parent[step] + path.reverse() + return path + + +class DFSStrategy(PathFindingStrategy): + def find_path(self, maze, start, exit): + if start == exit: + return [start] + stack = [start] + visited = {start} + parent = {start: None} + while stack: + current = stack.pop() + if current == exit: + break + for neighbor in maze.get_neighbors(current): + if neighbor not in visited: + visited.add(neighbor) + parent[neighbor] = current + stack.append(neighbor) + if exit not in parent: + return [] + path = [] + step = exit + while step is not None: + path.append(step) + step = parent[step] + path.reverse() + return path + + +class AStarStrategy(PathFindingStrategy): + def heuristic(self, a, b): + return abs(a.x - b.x) + abs(a.y - b.y) + + def find_path(self, maze, start, exit): + if start == exit: + return [start] + open_set = [] + heapq.heappush(open_set, (0, id(start), start)) + came_from = {} + g_score = {start: 0} + f_score = {start: self.heuristic(start, exit)} + while open_set: + _, _, current = heapq.heappop(open_set) + if current == exit: + path = [] + step = current + while step is not None: + path.append(step) + step = came_from.get(step) + path.reverse() + return path + 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_score[neighbor] = tentative_g + self.heuristic(neighbor, exit) + heapq.heappush(open_set, (f_score[neighbor], id(neighbor), neighbor)) + return [] + + +class MazeSolver: + def __init__(self, maze, strategy=None): + self.maze = maze + self.strategy = strategy + + def set_strategy(self, strategy): + self.strategy = strategy + + def solve(self): + if self.strategy is None: + raise ValueError("Стратегия не установлена") + start = self.maze.start_cell + exit_cell = self.maze.exit_cell + if start is None or exit_cell is None: + raise ValueError("Лабиринт не содержит старта или выхода") + start_time = time.perf_counter() + path = self.strategy.find_path(self.maze, start, exit_cell) + end_time = time.perf_counter() + elapsed_ms = (end_time - start_time) * 1000 + return path, elapsed_ms + + +# Test search if __name__ == '__main__': - # Создаём тестовый файл - test_maze = """####### -#S # -# ### # -# E # -#######""" - with open('test_maze.txt', 'w') as f: - f.write(test_maze) builder = TextFileMazeBuilder() maze = builder.build_from_file('test_maze.txt') - print(f"Лабиринт {maze.width}x{maze.height} загружен.") - print(f"Старт: ({maze.start_cell.x},{maze.start_cell.y})") - print(f"Выход: ({maze.exit_cell.x},{maze.exit_cell.y})") - # Вывод карты - for y in range(maze.height): - row = '' - for x in range(maze.width): - cell = maze.get_cell(x, y) - if cell.is_wall: - row += '#' - elif cell.is_start: - row += 'S' - elif cell.is_exit: - row += 'E' - else: - row += ' ' - print(row) + solver = MazeSolver(maze) + + solver.set_strategy(BFSStrategy()) + path, ms = solver.solve() + print("BFS путь:", [f"({c.x},{c.y})" for c in path]) + print(f"Время: {ms:.3f} мс") + + solver.set_strategy(DFSStrategy()) + path, ms = solver.solve() + print("DFS путь:", [f"({c.x},{c.y})" for c in path]) + print(f"Время: {ms:.3f} мс") + + solver.set_strategy(AStarStrategy()) + path, ms = solver.solve() + print("A* путь:", [f"({c.x},{c.y})" for c in path]) + print(f"Время: {ms:.3f} мс")