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 sys
|
||||||
import os
|
import os
|
||||||
|
from collections import deque
|
||||||
|
import heapq
|
||||||
|
import time
|
||||||
|
|
||||||
|
|
||||||
class Tile:
|
class Tile:
|
||||||
"""Клетка лабиринта."""
|
"""Клетка лабиринта."""
|
||||||
|
|
@ -92,26 +96,125 @@ class TextLabyrinthLoader(LabyrinthLoader):
|
||||||
return lab
|
return lab
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
class Pathfinder:
|
||||||
# Простая проверка загрузки и вывода лабиринта
|
def find_path(self, lab, start, goal):
|
||||||
loader = TextLabyrinthLoader()
|
raise NotImplementedError
|
||||||
lab = loader.load("maze/maze1.txt") # временно создадим позже
|
|
||||||
|
|
||||||
os.system('cls' if os.name == 'nt' else 'clear')
|
def _build_path(self, came_from, start, goal):
|
||||||
print("=" * (lab.width * 2 + 4))
|
path = []
|
||||||
print(" ЛАБИРИНТ (загружен)")
|
cur = goal
|
||||||
print("=" * (lab.width * 2 + 4))
|
while cur is not None:
|
||||||
for y in range(lab.height):
|
path.append(cur)
|
||||||
print(" ", end='')
|
cur = came_from.get(cur)
|
||||||
for x in range(lab.width):
|
path.reverse()
|
||||||
t = lab.get_tile(x, y)
|
return path
|
||||||
if t == lab.start_tile:
|
|
||||||
print('S', end=' ')
|
def visited_count(self):
|
||||||
elif t == lab.exit_tile:
|
return getattr(self, '_visited', 0)
|
||||||
print('E', end=' ')
|
|
||||||
elif t.wall:
|
|
||||||
print('#', end=' ')
|
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:
|
else:
|
||||||
print('.', end=' ')
|
print("Путь не найден")
|
||||||
print()
|
|
||||||
print("=" * (lab.width * 2 + 4))
|
|
||||||
Loading…
Reference in New Issue
Block a user