2026-rff_mp/YaroslavtsevAS/docs/2-nd-lab/main.py

221 lines
6.5 KiB
Python
Raw Normal View History

2026-05-24 15:32:34 +00:00
import sys
import os
2026-05-24 15:33:58 +00:00
from collections import deque
2026-05-24 15:32:34 +00:00
class Tile:
def __init__(self, x, y):
self._x = x
self._y = y
self._wall = False
self._entry = False
self._goal = False
@property
2026-05-24 15:33:58 +00:00
def x(self): return self._x
2026-05-24 15:32:34 +00:00
@property
2026-05-24 15:33:58 +00:00
def y(self): return self._y
2026-05-24 15:32:34 +00:00
@property
2026-05-24 15:33:58 +00:00
def is_wall(self): return self._wall
2026-05-24 15:32:34 +00:00
@is_wall.setter
2026-05-24 15:33:58 +00:00
def is_wall(self, value): self._wall = value
2026-05-24 15:32:34 +00:00
@property
2026-05-24 15:33:58 +00:00
def is_entry(self): return self._entry
2026-05-24 15:32:34 +00:00
@is_entry.setter
2026-05-24 15:33:58 +00:00
def is_entry(self, value): self._entry = value
2026-05-24 15:32:34 +00:00
@property
2026-05-24 15:33:58 +00:00
def is_goal(self): return self._goal
2026-05-24 15:32:34 +00:00
@is_goal.setter
2026-05-24 15:33:58 +00:00
def is_goal(self, value): self._goal = value
def can_walk(self): return not self._wall
2026-05-24 15:32:34 +00:00
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
2026-05-24 15:33:58 +00:00
def width(self): return self._width
2026-05-24 15:32:34 +00:00
@property
2026-05-24 15:33:58 +00:00
def height(self): return self._height
2026-05-24 15:32:34 +00:00
@property
2026-05-24 15:33:58 +00:00
def start(self): return self._start
2026-05-24 15:32:34 +00:00
@property
2026-05-24 15:33:58 +00:00
def exit(self): return self._exit
2026-05-24 15:32:34 +00:00
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)
2026-05-24 15:33:58 +00:00
if tile is None: return
2026-05-24 15:32:34 +00:00
if kind == 'wall':
tile.is_wall = True
elif kind == 'entry':
2026-05-24 15:33:58 +00:00
if self._start: self._start.is_entry = False
2026-05-24 15:32:34 +00:00
tile.is_entry = True
tile.is_wall = False
self._start = tile
elif kind == 'goal':
2026-05-24 15:33:58 +00:00
if self._exit: self._exit.is_goal = False
2026-05-24 15:32:34 +00:00
tile.is_goal = True
tile.is_wall = False
self._exit = tile
elif kind == 'floor':
tile.is_wall = False
def neighbours(self, tile):
2026-05-24 15:33:58 +00:00
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
2026-05-24 15:32:34 +00:00
class LabyrinthBuilder:
2026-05-24 15:33:58 +00:00
def build(self, filename): raise NotImplementedError
2026-05-24 15:32:34 +00:00
class TextLabyrinthBuilder(LabyrinthBuilder):
def build(self, filename):
with open(filename, 'r', encoding='utf-8') as f:
2026-05-24 15:33:58 +00:00
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
2026-05-24 15:32:34 +00:00
lab = Labyrinth(w, h)
2026-05-24 15:33:58 +00:00
for y, row in enumerate(lines):
2026-05-24 15:32:34 +00:00
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:
2026-05-24 15:33:58 +00:00
raise ValueError(f"Некорректный лабиринт: найдено S={entries}, E={exits}")
2026-05-24 15:32:34 +00:00
return lab
2026-05-24 15:33:58 +00:00
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
2026-05-24 15:32:34 +00:00
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)
2026-05-24 15:33:58 +00:00
if t == lab.start: print('S', end=' ')
elif t == lab.exit: print('E', end=' ')
elif t.is_wall: print('#', end=' ')
else: print('.', end=' ')
2026-05-24 15:32:34 +00:00
print()
print('=' * (lab.width * 2 + 4))
print(' S вход E выход # стена . пол')
if __name__ == '__main__':
2026-05-24 15:33:58 +00:00
maze_file = sys.argv[1] if len(sys.argv) > 1 else 'maze1.txt'
2026-05-24 15:32:34 +00:00
builder = TextLabyrinthBuilder()
labyrinth = builder.build(maze_file)
2026-05-24 15:33:58 +00:00
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("Путь не найден!")