2026-rff_mp/MylnikovAS/task_2/docs/data/steps_123.py

191 lines
5.7 KiB
Python
Raw Normal View History

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)