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 self.is_wall = is_wall self.is_start = is_start self.is_exit = is_exit def is_passable(self): return not self.is_wall class Maze: def __init__(self, width, height): self.width = width self.height = height self.grid = [[Cell(x, y) for y in range(height)] for x in range(width)] self.start_cell = None self.exit_cell = None def get_cell(self, x, y): if 0 <= x < self.width and 0 <= y < self.height: return self.grid[x][y] 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 neighbor = self.get_cell(nx, ny) if neighbor and neighbor.is_passable(): neighbors.append(neighbor) return neighbors 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() lines = [line.rstrip('\n') for line in lines if line.strip() != ''] if not lines: raise ValueError("Файл пуст") height = len(lines) width = max(len(line) for line in lines) maze = Maze(width, height) for y, line in enumerate(lines): for x, ch in enumerate(line): if x >= width: break cell = maze.get_cell(x, y) if ch == '#': cell.is_wall = True elif ch == 'S': cell.is_start = True maze.start_cell = cell elif ch == 'E': cell.is_exit = True maze.exit_cell = cell if maze.start_cell is None or maze.exit_cell is None: raise ValueError("В лабиринте должны быть S и E") 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__': builder = TextFileMazeBuilder() maze = builder.build_from_file('test_maze.txt') 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} мс")