2026-rff_mp/shahovaa/zadanie 2/maze_solver/builders.py
2026-05-19 22:39:51 +03:00

76 lines
2.5 KiB
Python

from __future__ import annotations
from abc import ABC, abstractmethod
from pathlib import Path
from .models import Cell, Maze
class MazeBuilder(ABC):
@abstractmethod
def build_from_file(self, filename: str | Path) -> Maze:
raise NotImplementedError
def buildFromFile(self, filename: str | Path) -> Maze:
return self.build_from_file(filename)
class TextFileMazeBuilder(MazeBuilder):
WALL = "#"
START = "S"
EXIT = "E"
PASSAGES = {" ", "."}
WEIGHTS = {"1": 1, "2": 2, "3": 3, "~": 3}
def build_from_file(self, filename: str | Path) -> Maze:
path = Path(filename)
rows = path.read_text(encoding="utf-8").splitlines()
if not rows:
raise ValueError(f"Maze file is empty: {path}")
width = len(rows[0])
if width == 0:
raise ValueError("Maze width must be greater than zero")
if any(len(row) != width for row in rows):
raise ValueError("All maze rows must have the same width")
cells: list[list[Cell]] = []
start: Cell | None = None
exit: Cell | None = None
for y, row in enumerate(rows):
cell_row: list[Cell] = []
for x, char in enumerate(row):
cell = self._create_cell(x, y, char)
if cell.is_start:
if start is not None:
raise ValueError("Maze must contain exactly one start cell")
start = cell
if cell.is_exit:
if exit is not None:
raise ValueError("Maze must contain exactly one exit cell")
exit = cell
cell_row.append(cell)
cells.append(cell_row)
if start is None:
raise ValueError("Maze must contain a start cell marked with 'S'")
if exit is None:
raise ValueError("Maze must contain an exit cell marked with 'E'")
return Maze(cells, start, exit)
def _create_cell(self, x: int, y: int, char: str) -> Cell:
if char == self.WALL:
return Cell(x=x, y=y, is_wall=True, symbol=char)
if char == self.START:
return Cell(x=x, y=y, is_start=True, symbol=char)
if char == self.EXIT:
return Cell(x=x, y=y, is_exit=True, symbol=char)
if char in self.PASSAGES:
return Cell(x=x, y=y, symbol=" ")
if char in self.WEIGHTS:
return Cell(x=x, y=y, weight=self.WEIGHTS[char], symbol=char)
raise ValueError(f"Unsupported maze symbol {char!r} at ({x}, {y})")