from abc import ABC, abstractmethod from typing import List, Optional, Any from models import Cell, Maze class Observer(ABC): @abstractmethod def update(self, event_type: str, data: Any = None) -> None: pass class Subject: def __init__(self): self._observers: List[Observer] = [] def attach(self, observer: Observer) -> None: self._observers.append(observer) def detach(self, observer: Observer) -> None: self._observers.remove(observer) def notify(self, event_type: str, data: Any = None) -> None: for observer in self._observers: observer.update(event_type, data) class ConsoleView(Observer): def __init__(self): self.last_path: List[Cell] = [] self.player_pos: Optional[Cell] = None def update(self, event_type: str, data: Any = None) -> None: if event_type == "path_found": self.last_path = data.get("path", []) print(f"\n=== Путь найден! Длина: {len(self.last_path)} ===") elif event_type == "path_not_found": print("\n=== Путь не найден! ===") elif event_type == "player_moved": self.player_pos = data.get("position") if data.get("redraw", True): self.render(data.get("maze"), self.player_pos, self.last_path) elif event_type == "maze_loaded": print("Лабиринт загружен") self.render(data.get("maze"), None, []) def render(self, maze: Maze, player_pos: Optional[Cell] = None, path: Optional[List[Cell]] = None) -> None: path_set = set(path) if path else set() print("\n" + "=" * (maze.width + 2)) for y in range(maze.height): line = "|" for x in range(maze.width): cell = maze.get_cell(x, y) if player_pos and cell == player_pos: line += "P" elif cell == maze.start: line += "S" elif cell == maze.exit: line += "E" elif cell in path_set and cell != maze.start and cell != maze.exit: line += "." elif cell.is_wall: line += "#" else: line += " " line += "|" print(line) print("=" * (maze.width + 2)) if path: print(f"Длина пути: {len(path)}")