forked from UNN/2026-rff_mp
79 lines
2.1 KiB
Python
79 lines
2.1 KiB
Python
from abc import ABC, abstractmethod
|
|
from typing import List
|
|
|
|
from maze import Maze, Cell
|
|
|
|
|
|
class Command(ABC):
|
|
"""Интерфейс команды (Command pattern)."""
|
|
|
|
@abstractmethod
|
|
def execute(self) -> bool:
|
|
pass
|
|
|
|
@abstractmethod
|
|
def undo(self):
|
|
pass
|
|
|
|
|
|
class Player:
|
|
"""Игрок, перемещающийся по лабиринту."""
|
|
|
|
def __init__(self, cell: Cell):
|
|
self.current_cell = cell
|
|
self._history: List[Cell] = []
|
|
|
|
def move_to(self, cell: Cell):
|
|
self._history.append(self.current_cell)
|
|
self.current_cell = cell
|
|
|
|
def move_back(self):
|
|
if self._history:
|
|
self.current_cell = self._history.pop()
|
|
return self.current_cell
|
|
return None
|
|
|
|
def __repr__(self):
|
|
return f"Player({self.current_cell.x}, {self.current_cell.y})"
|
|
|
|
|
|
class MoveCommand(Command):
|
|
"""Команда перемещения игрока."""
|
|
|
|
DIRECTIONS = {
|
|
'W': (0, -1),
|
|
'S': (0, 1),
|
|
'A': (-1, 0),
|
|
'D': (1, 0),
|
|
}
|
|
|
|
def __init__(self, player: Player, maze: Maze, direction: str):
|
|
self.player = player
|
|
self.maze = maze
|
|
self.direction = direction.upper()
|
|
self._previous_cell = None
|
|
self._executed = False
|
|
|
|
def execute(self) -> bool:
|
|
if self.direction not in self.DIRECTIONS:
|
|
return False
|
|
|
|
dx, dy = self.DIRECTIONS[self.direction]
|
|
new_x = self.player.current_cell.x + dx
|
|
new_y = self.player.current_cell.y + dy
|
|
|
|
new_cell = self.maze.get_cell(new_x, new_y)
|
|
|
|
if new_cell and new_cell.is_passable():
|
|
self._previous_cell = self.player.current_cell
|
|
self.player.move_to(new_cell)
|
|
self._executed = True
|
|
return True
|
|
|
|
return False
|
|
|
|
def undo(self):
|
|
if self._executed and self._previous_cell:
|
|
self.player.current_cell = self._previous_cell
|
|
self._executed = False
|
|
self._previous_cell = None |