import sys import os from collections import deque class Tile: def __init__(self, x, y): self._x = x self._y = y self._wall = False self._entry = False self._goal = False @property def x(self): return self._x @property def y(self): return self._y @property def is_wall(self): return self._wall @is_wall.setter def is_wall(self, value): self._wall = value @property def is_entry(self): return self._entry @is_entry.setter def is_entry(self, value): self._entry = value @property def is_goal(self): return self._goal @is_goal.setter def is_goal(self, value): self._goal = value def can_walk(self): return not self._wall class Labyrinth: def __init__(self, width, height): self._width = width self._height = height self._grid = [[Tile(x, y) for x in range(width)] for y in range(height)] self._start = None self._exit = None @property def width(self): return self._width @property def height(self): return self._height @property def start(self): return self._start @property def exit(self): return self._exit def tile_at(self, x, y): if 0 <= x < self._width and 0 <= y < self._height: return self._grid[y][x] return None def configure_tile(self, x, y, kind): tile = self.tile_at(x, y) if tile is None: return if kind == 'wall': tile.is_wall = True elif kind == 'entry': if self._start: self._start.is_entry = False tile.is_entry = True tile.is_wall = False self._start = tile elif kind == 'goal': if self._exit: self._exit.is_goal = False tile.is_goal = True tile.is_wall = False self._exit = tile elif kind == 'floor': tile.is_wall = False def neighbours(self, tile): res = [] for dx, dy in ((0,-1),(0,1),(-1,0),(1,0)): nb = self.tile_at(tile.x+dx, tile.y+dy) if nb and nb.can_walk(): res.append(nb) return res class LabyrinthBuilder: def build(self, filename): raise NotImplementedError class TextLabyrinthBuilder(LabyrinthBuilder): def build(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(l) for l in lines) if h else 0 entries = exits = 0 lab = Labyrinth(w, h) for y, row in enumerate(lines): for x, ch in enumerate(row): if ch == '#': lab.configure_tile(x, y, 'wall') elif ch == 'S': lab.configure_tile(x, y, 'entry') entries += 1 elif ch == 'E': lab.configure_tile(x, y, 'goal') exits += 1 else: lab.configure_tile(x, y, 'floor') if entries != 1 or exits != 1: raise ValueError(f"Некорректный лабиринт: найдено S={entries}, E={exits}") return lab class Pathfinder: def find_path(self, lab, start, goal): raise NotImplementedError def _build_path(self, predecessors, start, goal): path = [] cur = goal while cur is not None: path.append(cur) cur = predecessors.get(cur) path.reverse() return path @property def visited_count(self): return getattr(self, '_visited', 0) class BFS_Pathfinder(Pathfinder): def find_path(self, lab, start, goal): q = deque([start]) preds = {start: None} seen = {start} while q: cur = q.popleft() if cur == goal: self._visited = len(seen) return self._build_path(preds, start, goal) for nb in lab.neighbours(cur): if nb not in seen: seen.add(nb) preds[nb] = cur q.append(nb) self._visited = len(seen) return [] class DFS_Pathfinder(Pathfinder): def find_path(self, lab, start, goal): stack = [start] preds = {start: None} seen = {start} while stack: cur = stack.pop() if cur == goal: self._visited = len(seen) return self._build_path(preds, start, goal) for nb in lab.neighbours(cur): if nb not in seen: seen.add(nb) preds[nb] = cur stack.append(nb) self._visited = len(seen) 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 self._strategy is None: return None path = self._strategy.find_path(self._lab, self._lab.start, self._lab.exit) return path def show_labyrinth(lab): os.system('cls' if os.name == 'nt' else 'clear') print('=' * (lab.width * 2 + 4)) print(' ЛАБИРИНТ') print('=' * (lab.width * 2 + 4)) for y in range(lab.height): print(' ', end='') for x in range(lab.width): t = lab.tile_at(x, y) if t == lab.start: print('S', end=' ') elif t == lab.exit: print('E', end=' ') elif t.is_wall: print('#', end=' ') else: print('.', end=' ') print() print('=' * (lab.width * 2 + 4)) print(' S – вход E – выход # – стена . – пол') if __name__ == '__main__': maze_file = sys.argv[1] if len(sys.argv) > 1 else 'maze1.txt' builder = TextLabyrinthBuilder() labyrinth = builder.build(maze_file) show_labyrinth(labyrinth) solver = LabyrinthSolver(labyrinth) print("\nВыберите алгоритм: 1 – BFS, 2 – DFS") choice = input("> ").strip() if choice == '1': solver.set_strategy(BFS_Pathfinder()) print("Запущен BFS...") elif choice == '2': solver.set_strategy(DFS_Pathfinder()) print("Запущен DFS...") else: print("Неверный выбор, выход.") sys.exit(0) path = solver.solve() if path: print(f"Путь найден! Длина: {len(path)} клеток") print(f"Посещено клеток: {solver._strategy.visited_count}") else: print("Путь не найден!")