class Cell: def __init__(self, x, y): self.x = x self.y = y self.is_wall = False self.is_start = False self.is_exit = False def is_passable(self): return not self.is_wall def __repr__(self): return f"Cell({self.x}, {self.y})" class Maze: def __init__(self, width, height): self.width = width self.height = height self.cells = [] self.start = None self.exit = None for y in range(height): row = [] for x in range(width): row.append(Cell(x, y)) self.cells.append(row) def get_cell(self, x, y): if 0 <= x < self.width and 0 <= y < self.height: return self.cells[y][x] return None def get_neighbors(self, cell): neighbors = [] directions = [(0, -1), (0, 1), (-1, 0), (1,0)] for dx, dy in directions: 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 def __repr__(self): return f"Maze({self.width}x{self.height})" from abc import ABC, abstractmethod class MazeBuilder(ABC): @abstractmethod def build_from_file(self, filename): pass 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\r') for line in lines] height = len(lines) width = len(lines[0]) if height > 0 else 0 for i, line in enumerate(lines): if len(line) != width: raise ValueError(f"Строка {i+1} имеет длину {len(line)}, ожидается {width}") maze = Maze(width, height) start = None exit_cell = None for y, line in enumerate(lines): for x, ch in enumerate(line): cell = maze.get_cell(x, y) if ch == '#': cell.is_wall = True elif ch == ' ': cell.is_wall = False elif ch == 'S': cell.is_wall = False cell.is_start = True start = cell elif ch == 'E': cell.is_wall = False cell.ia_exit = True exit_cell = cell else: cell.is_wall = True if start is None: raise ValueError("В лабиринте не найден старт (S)") if exit_cell is None: raise ValueError("В лабиринте не найден выход (E)") maze.start = start maze.exit = exit_cell return maze from collections import deque import heapq from abc import ABC, abstractmethod class PathfindingStrategy(ABC): @abstractmethod def find_path(self, maze, start, exit): pass class BFSStrategy(PathfindingStrategy): def find_path(self, maze, start, exit): if start is None or exit is None: return [] queue = deque() queue.append((start, [start])) visited = set() visited.add(start) while queue: current, path = queue.popleft() if current == exit: return path neighbors = maze.get_neighbors(current) for neighbor in neighbors: if neighbor not in visited: visited.add(neighbor) queue.append((neighbor, path + [neighbor])) return [] class DFSStrategy(PathfindingStrategy): def find_path(self, maze, start, exit): if start is None or exit is None: return [] stack = [(start, [start])] visited = set() visited.add(start) while stack: current, path = stack.pop() if current == exit: return path for neighbor in maze.get_neighbors(current): if neighbor not in visited: visited.add(neighbor) stack.append((neighbor, path + [neighbor])) return [] class AStartStrategy(PathfindingStrategy): def _heuristic(self, cell, exit): return abs(cell.x - exit.x) + abs(cell.y -exit.y) def find_path(self, maze, start, exit): if start is None or exit is None: return [] counter = 0 heap = [] heapq.heappush(heap, (self._heuristic(start, exit), counter, start, [start])) g_score = {start: 0} visited = set() while heap: f_score, _, current, path = heapq.heappop(heap) if current in visited: continue visited.add(current) if current == exit: 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]: g_score[neighbor] = tentative_g f_score = tentative_g + self._heuristic(neighbor, exit) counter += 1 heapq.heappush(heap, (f_score, counter, neighbor, path + [neighbor])) return [] #тест if __name__ == "__main__": builder = TextFileMazeBuilder() maze = builder.build_from_file("maze1.txt") print("Лабиринт загружен") print(f"Старт: {maze.start}") print(f"Выход: {maze.exit}") # Проверяем, что старт и выход проходимые print(f"Старт проходим: {maze.start.is_passable()}") print(f"Выход проходим: {maze.exit.is_passable()}") # Проверяем соседей старта neighbors = maze.get_neighbors(maze.start) print(f"Соседи старта: {neighbors}") # Тестируем BFS bfs = BFSStrategy() path = bfs.find_path(maze, maze.start, maze.exit) print(f"BFS путь: {[f'({c.x},{c.y})' for c in path]}") print(f"BFS длина пути: {len(path)}") # Тестируем DFS dfs = DFSStrategy() path = dfs.find_path(maze, maze.start, maze.exit) print(f"DFS путь: {[f'({c.x},{c.y})' for c in path]}") print(f"DFS длина пути: {len(path)}") # Тестируем A* astar = AStartStrategy() path = astar.find_path(maze, maze.start, maze.exit) print(f"A* путь: {[f'({c.x},{c.y})' for c in path]}") print(f"A* длина пути: {len(path)}")