from abc import ABC, abstractmethod from typing import List, Optional, Set from enum import Enum from maze_model import Maze, Cell class EventType(Enum): PATH_FOUND = "path_found" MOVE = "move" MAZE_LOADED = "maze_loaded" SOLVE_START = "solve_start" SOLVE_END = "solve_end" class Observer(ABC): @abstractmethod def update(self, event_type: EventType, data: any) -> None: pass class ConsoleView(Observer): def __init__(self): self.last_path: Optional[List[Cell]] = None def update(self, event_type: EventType, data: any) -> None: if event_type == EventType.MAZE_LOADED: print("Лабиринт загружен") elif event_type == EventType.SOLVE_START: print("Начинается поиск пути...") elif event_type == EventType.SOLVE_END: print(f"Поиск завершён. Статистика: {data}") elif event_type == EventType.PATH_FOUND: self.last_path = data def render(self, maze: Maze, player_pos: Optional[Cell] = None, path: Optional[List[Cell]] = None) -> None: #рисует лаб import os os.system('cls' if os.name == 'nt' else 'clear') path_set = set(path) if path else set() # Верх print("┌" + "─" * maze.width + "┐") for y in range(maze.height): line = "│" for x in range(maze.width): cell = maze.get_cell(x, y) if player_pos and player_pos.x == x and player_pos.y == y: line += "P" elif cell == maze.start: line += "S" elif cell == maze.exit: line += "E" elif cell is not None and cell.is_wall: line += "#" elif path and cell in path_set: line += "." else: line += " " line += "│" print(line) # Низ print("└" + "─" * maze.width + "┘") if path: print(f"\nПуть найден! Длина: {len(path)} шагов") elif path == []: print("\nПуть не найден:(") class Player: def __init__(self, start_cell: Cell): self.current_cell = start_cell def move_to(self, cell: Cell) -> None: self.current_cell = cell def get_position(self) -> Cell: return self.current_cell class Direction(Enum): UP = (0, -1) DOWN = (0, 1) LEFT = (-1, 0) RIGHT = (1, 0) class Command(ABC): @abstractmethod def execute(self) -> None: pass @abstractmethod def undo(self) -> None: pass class MoveCommand(Command): def __init__(self, player: Player, maze: Maze, direction: Direction): self.player = player self.maze = maze self.direction = direction self.previous_cell = player.current_cell def execute(self) -> None: dx, dy = self.direction.value new_x = self.player.current_cell.x + dx new_y = self.player.current_cell.y + dy new_cell = self.maze.get_cell(new_x, new_y) if new_cell and new_cell.is_passable(): self.previous_cell = self.player.current_cell self.player.move_to(new_cell) return True return False def undo(self) -> None: self.player.move_to(self.previous_cell) class GameController: def __init__(self, maze: Maze, view: ConsoleView): if maze.start is None: raise ValueError("Лабиринт не имеет стартовой клетки") self.maze = maze self.view = view self.player = Player(maze.start) self.command_history: List[Command] = [] self.found_path: Optional[List[Cell]] = None def move(self, direction: Direction) -> bool: command = MoveCommand(self.player, self.maze, direction) if command.execute(): self.command_history.append(command) self._render() return True return False def undo(self) -> None: if self.command_history: command = self.command_history.pop() command.undo() self._render() def set_path(self, path: List[Cell]) -> None: self.found_path = path self._render() def _render(self) -> None: self.view.render(self.maze, self.player.get_position(), self.found_path)