2026-rff_mp/novikovsd/maze.py

121 lines
3.4 KiB
Python
Raw Normal View History

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):