import sys import time import csv from collections import deque from heapq import heappush, heappop from abc import ABC, abstractmethod from typing import List, Optional, Tuple, Dict, Any import os class Cell: def __init__(self, x: int, y: int, is_wall: bool = False): self.x = x self.y = y self.is_wall = is_wall self.is_start = False self.is_exit = False def is_passable(self) -> bool: return not self.is_wall def __repr__(self): return f"Cell({self.x},{self.y})" class Maze: def __init__(self, width: int, height: int): self.width = width self.height = height self.cells: List[List[Cell]] = [] self.start: Optional[Cell] = None self.exit: Optional[Cell] = None def set_cell(self, x: int, y: int, cell: Cell): if not self.cells: self.cells = [[None] * self.width for _ in range(self.height)] self.cells[y][x] = cell def get_cell(self, x: int, y: int) -> Optional[Cell]: if 0 <= x < self.width and 0 <= y < self.height: return self.cells[y][x] return None def get_neighbors(self, cell: Cell) -> List[Cell]: neighbors = [] for dx, dy in [(0, 1), (0, -1), (1, 0), (-1, 0)]: nx, ny = cell.x + dx, cell.y + dy neighbor = self.get_cell(nx, ny) if neighbor and neighbor.is_passable(): neighbors.append(neighbor) return neighbors class MazeBuilder(ABC): @abstractmethod def build_from_file(self, filename: str) -> Maze: pass class TextFileMazeBuilder(MazeBuilder): def build_from_file(self, filename: str) -> Maze: with open(filename, 'r', encoding='utf-8') as f: lines = [line.rstrip('\n') for line in f.readlines()] if not lines: raise ValueError("Файл пуст") height = len(lines) width = max(len(line) for line in lines) maze = Maze(width, height) start_cell = None exit_cell = None for y, line in enumerate(lines): for x, ch in enumerate(line): is_wall = (ch == '#') cell = Cell(x, y, is_wall) if ch == 'S': cell.is_start = True start_cell = cell elif ch == 'E': cell.is_exit = True exit_cell = cell maze.set_cell(x, y, cell) if start_cell is None or exit_cell is None: for y in range(height): for x in range(width): cell = maze.get_cell(x, y) if cell and cell.is_start: start_cell = cell if cell and cell.is_exit: exit_cell = cell if start_cell is None: raise ValueError("Нет стартовой клетки (S)") if exit_cell is None: raise ValueError("Нет выходной клетки (E)") maze.start = start_cell maze.exit = exit_cell return maze class PathFindingStrategy(ABC): class BFSStrategy(PathFindingStrategy): class DFSStrategy(PathFindingStrategy): class AStarStrategy(PathFindingStrategy): class SearchStats: class MazeSolver: class Observer(ABC): class ConsoleView(Observer): class MoveCommand(ABC): class Player: class MoveCommandImpl(MoveCommand):