From 5b0eb0874afe6ba0bbd9f8ffbf745922fa4b7c83 Mon Sep 17 00:00:00 2001 From: volkovva Date: Mon, 25 May 2026 06:35:06 +0300 Subject: [PATCH] =?UTF-8?q?=D1=81=D0=B4=D0=B5=D0=BB=D0=B0=D0=BB=20Command?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- VolkovVA/cod.py | 330 ++++++++++++++++++++++++++++-------------------- 1 file changed, 192 insertions(+), 138 deletions(-) diff --git a/VolkovVA/cod.py b/VolkovVA/cod.py index 97ff105..5e55397 100644 --- a/VolkovVA/cod.py +++ b/VolkovVA/cod.py @@ -3,177 +3,231 @@ import heapq import time from abc import ABC, abstractmethod -# Модель +# Модель  class Cell: def __init__(self, x, y, is_wall=False, is_start=False, is_exit=False): - self.x = x - self.y = y - self.is_wall = is_wall - self.is_start = is_start - self.is_exit = is_exit - self.visited = False +        self.x = x +        self.y = y +        self.is_wall = is_wall +        self.is_start = is_start +        self.is_exit = is_exit +        self.visited = False   - def is_passable(self): - return not self.is_wall +    def is_passable(self): +        return not self.is_wall + +class Player: + def __init__(self, start_cell): + self.current_cell = start_cell + + class Maze: - def __init__(self, width, height): - self.width = width - self.height = height - self.cells = [[Cell(x, y) for x in range(width)] for y in range(height)] - self.start_cell = None - self.exit_cell = None - - def get_cell(self, x, y): - if 0 <= x < self.width and 0 <= y < self.height: - return self.cells[y][x] - return None +    def __init__(self, width, height): +        self.width = width +        self.height = height +        self.cells = [[Cell(x, y) for x in range(width)] for y in range(height)] +        self.start_cell = self.cells[0][0] + self.exit_cell = self.cells[height-1][width-1] +  +    def get_cell(self, x, y): +        if 0 <= x < self.width and 0 <= y < self.height: +            return self.cells[y][x] +        return None - def get_neighbors(self, cell): - neighbors = [] - directions = [(0, 1), (0, -1), (1, 0), (-1, 0)] - for dx, dy in directions: - neighbor = self.get_cell(cell.x + dx, cell.y + dy) - if neighbor and neighbor.is_passable(): - neighbors.append(neighbor) - return neighbors +    def get_neighbors(self, cell): +        neighbors = [] +        directions = [(0, 1), (0, -1), (1, 0), (-1, 0)] +        for dx, dy in directions: +            neighbor = self.get_cell(cell.x + dx, cell.y + dy) +            if neighbor and neighbor.is_passable(): +                neighbors.append(neighbor) +        return neighbors -# Строитель +# Строитель  class MazeBuilder: - def buildFromFile(self, filename): - with open(filename, 'r') as f: - lines = f.readlines() - height = len(lines) - width = len(lines[0].strip()) - maze = Maze(width, height) - for y, line in enumerate(lines): - for x, char in enumerate(line.strip()): - cell = maze.get_cell(x, y) - if char == '#': cell.is_wall = True - elif char == 'S': - cell.is_start = True - maze.start_cell = cell - elif char == 'E': - cell.is_exit = True - maze.exit_cell = cell - if not maze.start_cell or not maze.exit_cell: - raise ValueError("Лабиринт сломан") - return maze +    def buildFromFile(self, filename): +        with open(filename, 'r') as f: +            lines = f.readlines() +        height = len(lines) +        width = len(lines[0].strip()) +        maze = Maze(width, height) +        for y, line in enumerate(lines): +            for x, char in enumerate(line.strip()): +                cell = maze.get_cell(x, y) +                if char == '#': cell.is_wall = True +                elif char == 'S': +                    cell.is_start = True +                    maze.start_cell = cell +                elif char == 'E': +                    cell.is_exit = True +                    maze.exit_cell = cell +        if not maze.start_cell or not maze.exit_cell: +            raise ValueError("Лабиринт сломан") +        return maze -# Strategy + +#  Strategy  class PathFindingStrategy: - def findPath(self, maze, start, exit): - raise NotImplementedError("Этот метод должен быть реализован в стратегии!") +    def findPath(self, maze, start, exit): +        raise NotImplementedError("Этот метод должен быть реализован в стратегии!") - def _reconstruct_path(self, parents, current): - path = [] - while current: - path.append(current) - current = parents.get(current) - return path[::-1] +    def _reconstruct_path(self, parents, current): +        path = [] +        while current: +            path.append(current) +            current = parents.get(current) +        return path[::-1] +class Command(ABC): + @abstractmethod + def execute(self): pass + @abstractmethod + def undo(self): pass + +class MoveCommand(Command): + def __init__(self, player, dx, dy, maze): + self.player = player + self.dx = dx + self.dy = dy + self.maze = maze + self.prev_cell = None + + def execute(self): + self.prev_cell = self.player.current_cell + target = self.maze.get_cell(self.prev_cell.x + self.dx, self.prev_cell.y + self.dy) + if target and target.is_passable(): + self.player.current_cell = target + return True + return False + + def undo(self): + self.player.current_cell = self.prev_cell class BFSStrategy(PathFindingStrategy): - def findPath(self, maze, start, exit): - queue = deque([start]) - parents = {start: None} - start.visited = True - while queue: - current = queue.popleft() - if current == exit: - return self._reconstruct_path(parents, exit) - for neighbor in maze.get_neighbors(current): - if not neighbor.visited: - neighbor.visited = True - parents[neighbor] = current - queue.append(neighbor) - return [] +    def findPath(self, maze, start, exit): +        queue = deque([start]) +        parents = {start: None} +        start.visited = True +        while queue: +            current = queue.popleft() +            if current == exit: +                return self._reconstruct_path(parents, exit) +            for neighbor in maze.get_neighbors(current): +                if not neighbor.visited: +                    neighbor.visited = True +                    parents[neighbor] = current +                    queue.append(neighbor) +        return [] class AStarStrategy(PathFindingStrategy): - def _heuristic(self, a, b): - return abs(a.x - b.x) + abs(a.y - b.y) +    def _heuristic(self, a, b): +        return abs(a.x - b.x) + abs(a.y - b.y) - def findPath(self, maze, start, exit): - heap = [(0, start)] - parents = {start: None} - g_score = {start: 0} - while heap: - _, current = heapq.heappop(heap) - if current == exit: - return self._reconstruct_path(parents, exit) - for neighbor in maze.get_neighbors(current): - new_g = g_score[current] + 1 - if new_g < g_score.get(neighbor, float('inf')): - parents[neighbor] = current - g_score[neighbor] = new_g - f = new_g + self._heuristic(neighbor, exit) - heapq.heappush(heap, (f, neighbor)) - return [] +    def findPath(self, maze, start, exit): +        heap = [(0, start)] +        parents = {start: None} +        g_score = {start: 0} +        while heap: +            _, current = heapq.heappop(heap) +            if current == exit: +                return self._reconstruct_path(parents, exit) +            for neighbor in maze.get_neighbors(current): +                new_g = g_score[current] + 1 +                if new_g < g_score.get(neighbor, float('inf')): +                    parents[neighbor] = current +                    g_score[neighbor] = new_g +                    f = new_g + self._heuristic(neighbor, exit) +                    heapq.heappush(heap, (f, neighbor)) +        return [] -# Статистика +# Статистика  class SearchStats: - def __init__(self, time_ms, visited, length): - self.time_ms = time_ms - self.visited = visited - self.length = length +    def __init__(self, time_ms, visited, length): +        self.time_ms = time_ms +        self.visited = visited +        self.length = length -# Паттерн Observer +# Паттерн Observer  class Observer(ABC): - @abstractmethod - def update(self, event: str, data=None): - pass +    @abstractmethod +    def update(self, event: str, data=None): +        pass class ConsoleView(Observer): - def update(self, event: str, data=None): - if event == "path_found": - print(f"Событие '{event}': время={data.time_ms:.2f}мс, посещено={data.visited}, путь={data.length}") - elif event == "maze_loaded": - print(f"Событие '{event}': Лабиринт загружен.") +    def update(self, event: str, data=None): +        if event == "path_found": +            print(f"Событие '{event}': время={data.time_ms:.2f}мс, посещено={data.visited}, путь={data.length}") +        elif event == "maze_loaded": +            print(f"Событие '{event}': Лабиринт загружен.") # --- 6. Оркестратор (MazeSolver) --- class MazeSolver: - def __init__(self, maze): + def __init__(self, maze, player): self.maze = maze + self.player = player self.strat = None self._observers = [] + self._history = [] # Стек для undo - def attach(self, observer: Observer): + def attach(self, observer): self._observers.append(observer) - def notify(self, event: str, data=None): - for observer in self._observers: - observer.update(event, data) + def notify(self, event, data=None): + for obs in self._observers: + obs.update(event, data) - def setStrategy(self, strategy): - self.strat = strategy + # Метод для ручного управления (Command) + def move_player(self, dx, dy): + cmd = MoveCommand(self.player, dx, dy, self.maze) + if cmd.execute(): + self._history.append(cmd) + self.notify("player_moved", self.player.current_cell) + else: + self.notify("error", "Стена!") - def solve(self): - if not self.strat: return None - - t0 = time.perf_counter() - path = self.strat.findPath(self.maze, self.maze.start_cell, self.maze.exit_cell) - t1 = time.perf_counter() - - visited_count = sum(c.visited for row in self.maze.cells for c in row) - stats = SearchStats((t1 - t0) * 1000, visited_count, len(path)) - - self.notify("path_found", stats) - return stats + def undo_move(self): + if self._history: + cmd = self._history.pop() + cmd.undo() + self.notify("player_moved", self.player.current_cell) + + + +    def solve(self): +        if not self.strat: return None +         +        t0 = time.perf_counter() +        path = self.strat.findPath(self.maze, self.maze.start_cell, self.maze.exit_cell) +        t1 = time.perf_counter() +         +        visited_count = sum(c.visited for row in self.maze.cells for c in row) +        stats = SearchStats((t1 - t0) * 1000, visited_count, len(path)) +         +        self.notify("path_found", stats) +        return stats # --- Запуск --- if __name__ == "__main__": - builder = MazeBuilder() - try: - path = r"C:\Users\vva26\2026-rff_mp\VolkovVA\docs\data\maze.txt" - maze = builder.buildFromFile(path) - solver = MazeSolver(maze) - - # Регистрация наблюдателя - solver.attach(ConsoleView()) - solver.notify("maze_loaded") - - # Решение - solver.setStrategy(BFSStrategy()) - solver.solve() - - except Exception as e: - print(f"Ошибка: {e}") \ No newline at end of file + maze = Maze(10, 10) + player = Player(maze.start_cell) + solver = MazeSolver(maze, player) + solver.attach(ConsoleView()) + + solver.move_player(1, 0) + solver.undo_move() + + print("Используйте WASD для движения, Z для отмены хода, Q для выхода") +while True: + cmd = input("Введите команду: ").lower() + if cmd == 'd': + solver.move_player(1, 0) + elif cmd == 'a': + solver.move_player(-1, 0) + elif cmd == 's': + solver.move_player(0, 1) + elif cmd == 'w': + solver.move_player(0, -1) + elif cmd == 'z': + solver.undo_move() + elif cmd == 'q': + break