diff --git a/VolkovVA/cod.py b/VolkovVA/cod.py index 5e55397..2896c98 100644 --- a/VolkovVA/cod.py +++ b/VolkovVA/cod.py @@ -3,81 +3,79 @@ 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   - -    def is_passable(self): -        return not self.is_wall + 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 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 = self.cells[0][0] + 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_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 + +# Строитель 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 @@ -104,61 +102,63 @@ class MoveCommand(Command): 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 == "player_moved": + print(f"Игрок переместился в: ({data.x}, {data.y})") + elif event == "error": + print(f"Ошибка: {data}") # --- 6. Оркестратор (MazeSolver) --- class MazeSolver: @@ -191,20 +191,17 @@ class MazeSolver: cmd.undo() self.notify("player_moved", self.player.current_cell) - + def solve(self): + if not self.strat: return None -    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 + 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__": @@ -217,17 +214,17 @@ if __name__ == "__main__": 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 + 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 \ No newline at end of file