from abc import ABC, abstractmethod from itertools import product import sys import os.path as path from task2.mazeObjects.maze import Maze from task2.mazeObjects.cell import Cell from task2.observerSubject import MazeEvent, MazeEventType, Subject class MazeBuilder(ABC): """Интерфейс MazeBuilder с методом buildFromFile(filename)""" @abstractmethod def buildFromFile(self, filename: str): """Создание лабиринта из файла.""" class TextFileMazeBuilder(MazeBuilder): """Читает файл, парсит символы, создаёт объекты Cell, задаёт координаты и флаги, после чего возвращает готовый Maze.""" start:dict end:dict def _cellStrategy(self, letter: str) -> Cell: if letter == '#': return Cell(isWall=True) elif letter == ' ': return Cell() elif letter == 'S': return Cell(isStart=True) elif letter == 'E': return Cell(isExit=True) else: sys.stderr.write(f"Неизвестный символ '{letter}' при загрузке из файла\n") return Cell() def _updateStartEnd(self, letter: str, x:int, y:int) -> None: if letter == 'S': self.start = {'x': x, 'y': y} elif letter == 'E': self.end = {'x': x, 'y': y} def _generate_row_from_txt(self, filename: str) -> list[str]: with open(filename) as file: text = file.read() text = text.strip() if not text: raise ValueError(f"Файл \"{filename}\" пуст") text = text.split('\n') return text def buildFromFile(self, filename: str): rows = self._generate_row_from_txt(filename) height = len(rows) width = len(rows[0]) array = [[Cell() for j in range(width)] for i in range(height)] try: for x, y in product(range(width), range(height)): cell = self._cellStrategy(rows[y][x]) self._updateStartEnd(rows[y][x], x, y) cell.x = x cell.y = y array[y][x] = cell except IndexError: raise ValueError(f"В файле {filename}: Строка {y+1} имеет длину {len(rows[y])}, ожидалось {width}") maze_name, _ = path.splitext(path.basename(filename)) return Maze(array, self.start, self.end, name=maze_name)