84 lines
2.8 KiB
Python
84 lines
2.8 KiB
Python
|
|
from abc import ABC, abstractmethod
|
|||
|
|
from maze_model import Maze
|
|||
|
|
|
|||
|
|
|
|||
|
|
class MazeBuilder(ABC):
|
|||
|
|
@abstractmethod
|
|||
|
|
def build_from_file(self, filename: str) -> Maze:
|
|||
|
|
pass
|
|||
|
|
|
|||
|
|
@abstractmethod
|
|||
|
|
def build_from_string(self, content: str) -> Maze:
|
|||
|
|
pass
|
|||
|
|
|
|||
|
|
|
|||
|
|
class TextFileMazeBuilder(MazeBuilder):
|
|||
|
|
def __init__(self):
|
|||
|
|
self._maze = None
|
|||
|
|
self._lines = []
|
|||
|
|
self._start_found = False
|
|||
|
|
self._exit_found = False
|
|||
|
|
|
|||
|
|
def build_from_file(self, filename: str) -> Maze:
|
|||
|
|
try:
|
|||
|
|
with open(filename, 'r', encoding='utf-8') as file:
|
|||
|
|
content = file.read()
|
|||
|
|
return self.build_from_string(content)
|
|||
|
|
except FileNotFoundError:
|
|||
|
|
raise FileNotFoundError(f"Файл не найден: {filename}")
|
|||
|
|
|
|||
|
|
def build_from_string(self, content: str) -> Maze:
|
|||
|
|
self._reset()
|
|||
|
|
self._lines = [line.rstrip('\n\r') for line in content.split('\n')]
|
|||
|
|
while self._lines and not self._lines[-1].strip():
|
|||
|
|
self._lines.pop()
|
|||
|
|
|
|||
|
|
if not self._lines:
|
|||
|
|
raise ValueError("Пустой файл лабиринта")
|
|||
|
|
|
|||
|
|
height = len(self._lines)
|
|||
|
|
width = max(len(line) for line in self._lines)
|
|||
|
|
|
|||
|
|
for i, line in enumerate(self._lines):
|
|||
|
|
if len(line) != width:
|
|||
|
|
self._lines[i] = line.ljust(width)
|
|||
|
|
|
|||
|
|
self._maze = Maze(width, height)
|
|||
|
|
|
|||
|
|
for y, line in enumerate(self._lines):
|
|||
|
|
for x, char in enumerate(line):
|
|||
|
|
self._parse_cell(x, y, char)
|
|||
|
|
|
|||
|
|
self._validate_maze()
|
|||
|
|
return self._maze
|
|||
|
|
|
|||
|
|
def _reset(self):
|
|||
|
|
self._maze = None
|
|||
|
|
self._lines = []
|
|||
|
|
self._start_found = False
|
|||
|
|
self._exit_found = False
|
|||
|
|
|
|||
|
|
def _parse_cell(self, x: int, y: int, char: str):
|
|||
|
|
cell = self._maze.get_cell(x, y)
|
|||
|
|
if char == '#':
|
|||
|
|
cell.is_wall = True
|
|||
|
|
elif char == 'S':
|
|||
|
|
if self._start_found:
|
|||
|
|
raise ValueError(f"Найден второй старт в ({x}, {y})")
|
|||
|
|
self._maze.set_start(x, y)
|
|||
|
|
self._start_found = True
|
|||
|
|
elif char == 'E':
|
|||
|
|
if self._exit_found:
|
|||
|
|
raise ValueError(f"Найден второй выход в ({x}, {y})")
|
|||
|
|
self._maze.set_exit(x, y)
|
|||
|
|
self._exit_found = True
|
|||
|
|
elif char == ' ':
|
|||
|
|
pass
|
|||
|
|
else:
|
|||
|
|
raise ValueError(f"Неизвестный символ '{char}' в ({x}, {y})")
|
|||
|
|
|
|||
|
|
def _validate_maze(self):
|
|||
|
|
if not self._start_found:
|
|||
|
|
raise ValueError("В лабиринте не найден старт (символ 'S')")
|
|||
|
|
if not self._exit_found:
|
|||
|
|
raise ValueError("В лабиринте не найден выход (символ 'E')")
|