diff --git a/MylnikovAS/task_2/docs/data/steps_123.py b/MylnikovAS/task_2/docs/data/steps_123.py new file mode 100644 index 0000000..fffb5a4 --- /dev/null +++ b/MylnikovAS/task_2/docs/data/steps_123.py @@ -0,0 +1,190 @@ +import time +import csv +from collections import deque +import heapq +from abc import ABC, abstractmethod + + +class Cell: + def __init__(self, x: int, y: int): + self.x = x + self.y = y + self.isWall = False + self.isStart = False + self.isExit = False + self.weight = 1 + + def isPassable(self) -> bool: + return not self.isWall + + def __lt__(self, other): + return (self.x, self.y) < (other.x, other.y) + + +class Maze: + def __init__(self, width: int, height: int): + self.width = width + self.height = height + self.cells = [[Cell(x, y) for y in range(height)] for x in range(width)] + self.start = None + self.exit = None + + def getCell(self, x: int, y: int) -> Cell: + if 0 <= x < self.width and 0 <= y < self.height: + return self.cells[x][y] + return None + + def getNeighbors(self, cell: Cell): + neighbors = [] + directions = [(0, -1), (0, 1), (-1, 0), (1, 0)] + for dx, dy in directions: + nx, ny = cell.x + dx, cell.y + dy + neighbor = self.getCell(nx, ny) + if neighbor and neighbor.isPassable(): + neighbors.append(neighbor) + return neighbors + + +class MazeBuilder(ABC): + @abstractmethod + def buildFromStringList(self, lines: list) -> Maze: + pass + + +class TextMazeBuilder(MazeBuilder): + + def buildFromStringList(self, lines: list) -> Maze: + height = len(lines) + width = len(lines[0]) if height > 0 else 0 + maze = Maze(width, height) + + for y, line in enumerate(lines): + for x, char in enumerate(line): + cell = maze.getCell(x, y) + if char == '#': + cell.isWall = True + elif char == 'S': + cell.isStart = True + maze.start = cell + elif char == 'E': + cell.isExit = True + maze.exit = cell + elif char == 'W': + cell.weight = 3 + elif char == 'D': + cell.weight = 2 + return maze + + +class PathFindingStrategy(ABC): + def __init__(self): + self.visited_count = 0 + + @abstractmethod + def findPath(self, maze: Maze, start: Cell, exit: Cell) -> list: + pass + + def _reconstruct_path(self, came_from: dict, start: Cell, exit: Cell) -> list: + if exit not in came_from: + return [] + path = [] + current = exit + while current != start: + path.append(current) + current = came_from[current] + path.append(start) + path.reverse() + return path + + +class BFSStrategy(PathFindingStrategy): + def findPath(self, maze: Maze, start: Cell, exit: Cell) -> list: + self.visited_count = 0 + queue = deque([start]) + came_from = {start: None} + + while queue: + current = queue.popleft() + self.visited_count += 1 + if current == exit: + break + for neighbor in maze.getNeighbors(current): + if neighbor not in came_from: + queue.append(neighbor) + came_from[neighbor] = current + return self._reconstruct_path(came_from, start, exit) + + +class DFSStrategy(PathFindingStrategy): + def findPath(self, maze: Maze, start: Cell, exit: Cell) -> list: + self.visited_count = 0 + stack = [start] + came_from = {start: None} + + while stack: + current = stack.pop() + self.visited_count += 1 + if current == exit: + break + for neighbor in maze.getNeighbors(current): + if neighbor not in came_from: + stack.append(neighbor) + came_from[neighbor] = current + return self._reconstruct_path(came_from, start, exit) + + +class AStarStrategy(PathFindingStrategy): + def findPath(self, maze: Maze, start: Cell, exit: Cell) -> list: + self.visited_count = 0 + + def heuristic(a, b): + return abs(a.x - b.x) + abs(a.y - b.y) + + pq = [] + heapq.heappush(pq, (0, start)) + came_from = {start: None} + g_score = {start: 0} + + while pq: + _, current = heapq.heappop(pq) + self.visited_count += 1 + if current == exit: + break + + for neighbor in maze.getNeighbors(current): + tentative_g_score = g_score[current] + neighbor.weight + + if neighbor not in g_score or tentative_g_score < g_score[neighbor]: + came_from[neighbor] = current + g_score[neighbor] = tentative_g_score + f_score = tentative_g_score + heuristic(neighbor, exit) + heapq.heappush(pq, (f_score, neighbor)) + + return self._reconstruct_path(came_from, start, exit) + + +class DijkstraStrategy(PathFindingStrategy): + + def findPath(self, maze: Maze, start: Cell, exit: Cell) -> list: + self.visited_count = 0 + pq = [] + heapq.heappush(pq, (0, start)) + came_from = {start: None} + g_score = {start: 0} + + while pq: + current_g, current = heapq.heappop(pq) + self.visited_count += 1 + if current == exit: + break + + for neighbor in maze.getNeighbors(current): + tentative_g_score = g_score[current] + neighbor.weight + + if neighbor not in g_score or tentative_g_score < g_score[neighbor]: + came_from[neighbor] = current + g_score[neighbor] = tentative_g_score + heapq.heappush(pq, (tentative_g_score, neighbor)) + + return self._reconstruct_path(came_from, start, exit) +