2026-rff_mp/SavelevMI/docs/data/2-nd-exersize/main.py

269 lines
8.4 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Основной модуль: оркестратор MazeSolver, Observer для визуализации,
# Player, Command для пошагового управления, интерактивная игра
import sys
import time
import os
from maze_core import TextFileMazeBuilder, Maze
from pathfinding import BFSStrategy, DFSStrategy, AStarStrategy
class SearchStats:
def __init__(self, time_ms, visited_cells, path_length):
self.time_ms = time_ms
self.visited_cells = visited_cells
self.path_length = path_length
class Observer:
def update(self, event_type, data):
raise NotImplementedError
class ConsoleView(Observer):
def __init__(self, player=None):
self._last_path = None
self._player = player
def update(self, event_type, data):
if event_type == "maze_loaded":
self.render_maze(data)
elif event_type == "path_found":
self._last_path = data
self.render_path(data)
elif event_type == "player_moved":
self.render_maze_with_player(data)
def render_maze(self, maze):
os.system('cls' if os.name == 'nt' else 'clear')
print("=" * (maze.width * 2 + 4))
print(" ЛАБИРИНТ")
print("=" * (maze.width * 2 + 4))
for y in range(maze.height):
print(" ", end='')
for x in range(maze.width):
cell = maze.get_cell(x, y)
if cell == maze.start:
print('S', end=' ')
elif cell == maze.exit:
print('E', end=' ')
elif cell.is_wall:
print('#', end=' ')
else:
print('.', end=' ')
print()
print("=" * (maze.width * 2 + 4))
print(" S - вход E - выход # - стена . - проход")
def render_maze_with_player(self, maze):
os.system('cls' if os.name == 'nt' else 'clear')
print("=" * (maze.width * 2 + 4))
print(" ЛАБИРИНТ (P - игрок)")
print("=" * (maze.width * 2 + 4))
for y in range(maze.height):
print(" ", end='')
for x in range(maze.width):
cell = maze.get_cell(x, y)
if self._player and cell == self._player.current:
print('P', end=' ')
elif cell == maze.start:
print('S', end=' ')
elif cell == maze.exit:
print('E', end=' ')
elif cell.is_wall:
print('#', end=' ')
else:
print('.', end=' ')
print()
print("=" * (maze.width * 2 + 4))
print(f" Позиция игрока: ({self._player.current.x}, {self._player.current.y})")
print(" S - вход E - выход # - стена . - проход P - игрок")
def render_path(self, path):
if not path:
print("\n Путь не найден!")
return
print(f"\n Путь найден! Длина: {len(path)}")
class Player:
def __init__(self, start_cell, maze):
self._current = start_cell
self._previous = None
self._maze = maze
@property
def current(self):
return self._current
def move_to(self, cell):
if cell and cell.is_passable():
self._previous = self._current
self._current = cell
return True
return False
def undo_move(self):
if self._previous:
self._current, self._previous = self._previous, None
return True
return False
class Command:
def execute(self):
raise NotImplementedError
def undo(self):
raise NotImplementedError
class MoveCommand(Command):
def __init__(self, player, direction, maze):
self._player = player
self._direction = direction
self._maze = maze
self._executed = False
def execute(self):
dx, dy = self._direction
new_x = self._player.current.x + dx
new_y = self._player.current.y + dy
target_cell = self._maze.get_cell(new_x, new_y)
if target_cell and target_cell.is_passable():
self._player.move_to(target_cell)
self._executed = True
return True
return False
def undo(self):
if self._executed:
self._player.undo_move()
self._executed = False
return True
return False
class MazeSolver:
def __init__(self, maze):
self._maze = maze
self._strategy = None
self._observers = []
def attach(self, observer):
self._observers.append(observer)
def notify(self, event_type, data):
for observer in self._observers:
observer.update(event_type, data)
def set_strategy(self, strategy):
self._strategy = strategy
def solve(self):
if self._strategy is None:
return None
start_time = time.perf_counter()
path = self._strategy.find_path(self._maze, self._maze.start, self._maze.exit)
end_time = time.perf_counter()
time_ms = (end_time - start_time) * 1000
self.notify("path_found", path)
return SearchStats(time_ms, self._strategy.get_visited_count(), len(path))
def main():
builder = TextFileMazeBuilder()
# Загрузка лабиринта из файла
if len(sys.argv) > 1:
maze = builder.build_from_file(sys.argv[1])
else:
maze = builder.build_from_file("maze1.txt")
# Создание игрока и визуализации
player = Player(maze.start, maze)
view = ConsoleView(player)
view.render_maze(maze)
# Создание решателя
solver = MazeSolver(maze)
solver.attach(view)
print("\n УПРАВЛЕНИЕ:")
print(" H (влево) J (вниз) K (вверх) L (вправо)")
print(" U - отменить ход Q - выход")
print("\n АВТО-ПОИСК:")
print(" B - BFS (поиск в ширину)")
print(" D - DFS (поиск в глубину)")
print(" A - A* (звездочка)")
print("\n" + "=" * 50)
command_stack = []
while True:
key = input("\n Команда > ").lower()
if key == 'q':
print("\n До свидания!")
break
elif key == 'b':
solver.set_strategy(BFSStrategy())
stats = solver.solve()
print(f"\n BFS: время={stats.time_ms:.3f}мс, посещено={stats.visited_cells}, длина={stats.path_length}")
elif key == 'd':
solver.set_strategy(DFSStrategy())
stats = solver.solve()
print(f"\n DFS: время={stats.time_ms:.3f}мс, посещено={stats.visited_cells}, длина={stats.path_length}")
elif key == 'a':
solver.set_strategy(AStarStrategy())
stats = solver.solve()
print(f"\n A*: время={stats.time_ms:.3f}мс, посещено={stats.visited_cells}, длина={stats.path_length}")
elif key in ['h', 'j', 'k', 'l']:
dirs = {'h': (-1, 0), 'l': (1, 0), 'k': (0, -1), 'j': (0, 1)}
cmd = MoveCommand(player, dirs[key], maze)
if cmd.execute():
command_stack.append(cmd)
view.render_maze_with_player(maze)
if player.current == maze.exit:
print("\n ПОЗДРАВЛЯЮ! ВЫ НАШЛИ ВЫХОД!")
print(f" Всего ходов: {len(command_stack)}")
break
else:
print("\n Туда нельзя там стена!")
elif key == 'u':
if command_stack:
cmd = command_stack.pop()
cmd.undo()
view.render_maze_with_player(maze)
print("\n Ход отменён")
else:
print("\n Нечего отменять")
else:
print("\n Неизвестная команда. Используйте H,J,K,L для движения, U для отмены, Q для выхода")
if __name__ == "__main__":
main()