forked from UNN/2026-rff_mp
[2] realising BFS DFS and A*
This commit is contained in:
parent
4e1fab741f
commit
539dba32f9
|
|
@ -1,5 +1,9 @@
|
|||
import sys
|
||||
import os
|
||||
from collections import deque
|
||||
import heapq
|
||||
import time
|
||||
|
||||
|
||||
class Tile:
|
||||
"""Клетка лабиринта."""
|
||||
|
|
@ -92,26 +96,125 @@ class TextLabyrinthLoader(LabyrinthLoader):
|
|||
return lab
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Простая проверка загрузки и вывода лабиринта
|
||||
loader = TextLabyrinthLoader()
|
||||
lab = loader.load("maze/maze1.txt") # временно создадим позже
|
||||
class Pathfinder:
|
||||
def find_path(self, lab, start, goal):
|
||||
raise NotImplementedError
|
||||
|
||||
os.system('cls' if os.name == 'nt' else 'clear')
|
||||
print("=" * (lab.width * 2 + 4))
|
||||
print(" ЛАБИРИНТ (загружен)")
|
||||
print("=" * (lab.width * 2 + 4))
|
||||
for y in range(lab.height):
|
||||
print(" ", end='')
|
||||
for x in range(lab.width):
|
||||
t = lab.get_tile(x, y)
|
||||
if t == lab.start_tile:
|
||||
print('S', end=' ')
|
||||
elif t == lab.exit_tile:
|
||||
print('E', end=' ')
|
||||
elif t.wall:
|
||||
print('#', end=' ')
|
||||
else:
|
||||
print('.', end=' ')
|
||||
print()
|
||||
print("=" * (lab.width * 2 + 4))
|
||||
def _build_path(self, came_from, start, goal):
|
||||
path = []
|
||||
cur = goal
|
||||
while cur is not None:
|
||||
path.append(cur)
|
||||
cur = came_from.get(cur)
|
||||
path.reverse()
|
||||
return path
|
||||
|
||||
def visited_count(self):
|
||||
return getattr(self, '_visited', 0)
|
||||
|
||||
|
||||
class BFS(Pathfinder):
|
||||
def find_path(self, lab, start, goal):
|
||||
q = deque([start])
|
||||
parent = {start: None}
|
||||
visited = {start}
|
||||
while q:
|
||||
cur = q.popleft()
|
||||
if cur == goal:
|
||||
self._visited = len(visited)
|
||||
return self._build_path(parent, start, goal)
|
||||
for nb in lab.neighbours(cur):
|
||||
if nb not in visited:
|
||||
visited.add(nb)
|
||||
parent[nb] = cur
|
||||
q.append(nb)
|
||||
self._visited = len(visited)
|
||||
return []
|
||||
|
||||
|
||||
class DFS(Pathfinder):
|
||||
def find_path(self, lab, start, goal):
|
||||
stack = [start]
|
||||
parent = {start: None}
|
||||
visited = {start}
|
||||
while stack:
|
||||
cur = stack.pop()
|
||||
if cur == goal:
|
||||
self._visited = len(visited)
|
||||
return self._build_path(parent, start, goal)
|
||||
for nb in lab.neighbours(cur):
|
||||
if nb not in visited:
|
||||
visited.add(nb)
|
||||
parent[nb] = cur
|
||||
stack.append(nb)
|
||||
self._visited = len(visited)
|
||||
return []
|
||||
|
||||
|
||||
class AStar(Pathfinder):
|
||||
def _heuristic(self, a, b):
|
||||
return abs(a.x - b.x) + abs(a.y - b.y)
|
||||
|
||||
def find_path(self, lab, start, goal):
|
||||
heap = []
|
||||
counter = 0
|
||||
start_f = self._heuristic(start, goal)
|
||||
heapq.heappush(heap, (start_f, counter, start))
|
||||
counter += 1
|
||||
parent = {}
|
||||
g = {start: 0}
|
||||
f = {start: start_f}
|
||||
visited = set()
|
||||
while heap:
|
||||
cur_f, _, cur = heapq.heappop(heap)
|
||||
visited.add(cur)
|
||||
if cur == goal:
|
||||
self._visited = len(visited)
|
||||
return self._build_path(parent, start, goal)
|
||||
if cur_f > f.get(cur, float('inf')):
|
||||
continue
|
||||
for nb in lab.neighbours(cur):
|
||||
new_g = g[cur] + 1
|
||||
if new_g < g.get(nb, float('inf')):
|
||||
parent[nb] = cur
|
||||
g[nb] = new_g
|
||||
new_f = new_g + self._heuristic(nb, goal)
|
||||
f[nb] = new_f
|
||||
heapq.heappush(heap, (new_f, counter, nb))
|
||||
counter += 1
|
||||
self._visited = len(visited)
|
||||
return []
|
||||
|
||||
|
||||
class LabyrinthSolver:
|
||||
def __init__(self, lab):
|
||||
self.lab = lab
|
||||
self.strategy = None
|
||||
|
||||
def set_strategy(self, strategy):
|
||||
self.strategy = strategy
|
||||
|
||||
def solve(self):
|
||||
if not self.strategy:
|
||||
return None
|
||||
t0 = time.perf_counter()
|
||||
path = self.strategy.find_path(self.lab, self.lab.start_tile, self.lab.exit_tile)
|
||||
t1 = time.perf_counter()
|
||||
return {
|
||||
'time_ms': (t1 - t0) * 1000,
|
||||
'visited': self.strategy.visited_count(),
|
||||
'length': len(path)
|
||||
}
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
loader = TextLabyrinthLoader()
|
||||
lab = loader.load("maze/maze1.txt")
|
||||
print("Загружен лабиринт, пробуем BFS...")
|
||||
solver = LabyrinthSolver(lab)
|
||||
solver.set_strategy(BFS())
|
||||
stats = solver.solve()
|
||||
if stats['length'] > 0:
|
||||
print(f"BFS: время={stats['time_ms']:.3f}мс, посещено={stats['visited']}, длина={stats['length']}")
|
||||
else:
|
||||
print("Путь не найден")
|
||||
Loading…
Reference in New Issue
Block a user