import sys import os from collections import deque import heapq import time class Tile: """Клетка лабиринта.""" def __init__(self, x, y): self.x = x self.y = y self.wall = False self.start = False self.exit = False def passable(self): return not self.wall class Labyrinth: """Модель лабиринта.""" def __init__(self, width, height): self.width = width self.height = height self._tiles = [[Tile(x, y) for x in range(width)] for y in range(height)] self.start_tile = None self.exit_tile = None def get_tile(self, x, y): if 0 <= x < self.width and 0 <= y < self.height: return self._tiles[y][x] return None def set_tile(self, x, y, kind): tile = self.get_tile(x, y) if tile is None: return if kind == 'wall': tile.wall = True elif kind == 'start': if self.start_tile: self.start_tile.start = False tile.start = True tile.wall = False self.start_tile = tile elif kind == 'exit': if self.exit_tile: self.exit_tile.exit = False tile.exit = True tile.wall = False self.exit_tile = tile elif kind == 'path': tile.wall = False def neighbours(self, tile): dirs = [(0, -1), (0, 1), (-1, 0), (1, 0)] result = [] for dx, dy in dirs: nx, ny = tile.x + dx, tile.y + dy nb = self.get_tile(nx, ny) if nb and nb.passable(): result.append(nb) return result class LabyrinthLoader: def load(self, filename): raise NotImplementedError class TextLabyrinthLoader(LabyrinthLoader): def load(self, filename): with open(filename, 'r', encoding='utf-8') as f: lines = [line.rstrip('\n') for line in f] h = len(lines) w = max(len(line) for line in lines) if h > 0 else 0 start_cnt = 0 exit_cnt = 0 lab = Labyrinth(w, h) for y, line in enumerate(lines): for x, ch in enumerate(line): if ch == '#': lab.set_tile(x, y, 'wall') elif ch == 'S': lab.set_tile(x, y, 'start') start_cnt += 1 elif ch == 'E': lab.set_tile(x, y, 'exit') exit_cnt += 1 else: lab.set_tile(x, y, 'path') if start_cnt != 1 or exit_cnt != 1: raise ValueError(f"Нужны ровно S и E, найдено S={start_cnt}, E={exit_cnt}") return lab class Pathfinder: def find_path(self, lab, start, goal): raise NotImplementedError def _build_path(self, came_from, start, goal): path = [] cur = goal while cur is not None: path.append(cur) cur = came_from.get(cur) path.reverse() return path def visited_count(self): return getattr(self, '_visited', 0) class BFS(Pathfinder): def find_path(self, lab, start, goal): q = deque([start]) parent = {start: None} visited = {start} while q: cur = q.popleft() if cur == goal: self._visited = len(visited) return self._build_path(parent, start, goal) for nb in lab.neighbours(cur): if nb not in visited: visited.add(nb) parent[nb] = cur q.append(nb) self._visited = len(visited) return [] class DFS(Pathfinder): def find_path(self, lab, start, goal): stack = [start] parent = {start: None} visited = {start} while stack: cur = stack.pop() if cur == goal: self._visited = len(visited) return self._build_path(parent, start, goal) for nb in lab.neighbours(cur): if nb not in visited: visited.add(nb) parent[nb] = cur stack.append(nb) self._visited = len(visited) return [] class AStar(Pathfinder): def _heuristic(self, a, b): return abs(a.x - b.x) + abs(a.y - b.y) def find_path(self, lab, start, goal): heap = [] counter = 0 start_f = self._heuristic(start, goal) heapq.heappush(heap, (start_f, counter, start)) counter += 1 parent = {} g = {start: 0} f = {start: start_f} visited = set() while heap: cur_f, _, cur = heapq.heappop(heap) visited.add(cur) if cur == goal: self._visited = len(visited) return self._build_path(parent, start, goal) if cur_f > f.get(cur, float('inf')): continue for nb in lab.neighbours(cur): new_g = g[cur] + 1 if new_g < g.get(nb, float('inf')): parent[nb] = cur g[nb] = new_g new_f = new_g + self._heuristic(nb, goal) f[nb] = new_f heapq.heappush(heap, (new_f, counter, nb)) counter += 1 self._visited = len(visited) return [] class LabyrinthSolver: def __init__(self, lab): self.lab = lab self.strategy = None def set_strategy(self, strategy): self.strategy = strategy def solve(self): if not self.strategy: return None t0 = time.perf_counter() path = self.strategy.find_path(self.lab, self.lab.start_tile, self.lab.exit_tile) t1 = time.perf_counter() return { 'time_ms': (t1 - t0) * 1000, 'visited': self.strategy.visited_count(), 'length': len(path) } if __name__ == "__main__": loader = TextLabyrinthLoader() lab = loader.load("maze/maze1.txt") print("Загружен лабиринт, пробуем BFS...") solver = LabyrinthSolver(lab) solver.set_strategy(BFS()) stats = solver.solve() if stats['length'] > 0: print(f"BFS: время={stats['time_ms']:.3f}мс, посещено={stats['visited']}, длина={stats['length']}") else: print("Путь не найден")