103 lines
2.8 KiB
Python
103 lines
2.8 KiB
Python
from collections import deque
|
|
import heapq
|
|
from math import inf
|
|
|
|
class PathFindingStrategy:
|
|
def findPath(self, maze, start, exit):
|
|
raise NotImplementedError
|
|
|
|
|
|
def reconstruct_path(parent, start, goal):
|
|
if goal not in parent and goal != start:
|
|
return []
|
|
path = []
|
|
cur = goal
|
|
while cur != start:
|
|
path.append(cur)
|
|
cur = parent[cur]
|
|
path.append(start)
|
|
path.reverse()
|
|
return path
|
|
|
|
|
|
class BFSStrategy(PathFindingStrategy):
|
|
def findPath(self, maze, start, exit):
|
|
queue = deque([start])
|
|
visited = {start}
|
|
parent = {}
|
|
visited_count = 0
|
|
|
|
while queue:
|
|
current = queue.popleft()
|
|
visited_count += 1
|
|
if current == exit:
|
|
path = reconstruct_path(parent, start, exit)
|
|
return path, visited_count
|
|
|
|
for nxt in maze.getNeighbors(current):
|
|
if nxt not in visited:
|
|
visited.add(nxt)
|
|
parent[nxt] = current
|
|
queue.append(nxt)
|
|
|
|
return [], visited_count
|
|
|
|
|
|
class DFSStrategy(PathFindingStrategy):
|
|
def findPath(self, maze, start, exit):
|
|
stack = [start]
|
|
visited = {start}
|
|
parent = {}
|
|
visited_count = 0
|
|
|
|
while stack:
|
|
current = stack.pop()
|
|
visited_count += 1
|
|
if current == exit:
|
|
path = reconstruct_path(parent, start, exit)
|
|
return path, visited_count
|
|
|
|
for nxt in maze.getNeighbors(current):
|
|
if nxt not in visited:
|
|
visited.add(nxt)
|
|
parent[nxt] = current
|
|
stack.append(nxt)
|
|
|
|
return [], visited_count
|
|
|
|
|
|
class AStarStrategy(PathFindingStrategy):
|
|
def h(self, a, b):
|
|
return abs(a.x - b.x) + abs(a.y - b.y)
|
|
|
|
def findPath(self, maze, start, exit):
|
|
open_heap = []
|
|
heapq.heappush(open_heap, (0, 0, start))
|
|
parent = {}
|
|
g = {start: 0}
|
|
visited = set()
|
|
visited_count = 0
|
|
counter = 1
|
|
|
|
while open_heap:
|
|
_, _, current = heapq.heappop(open_heap)
|
|
if current in visited:
|
|
continue
|
|
|
|
visited.add(current)
|
|
visited_count += 1
|
|
|
|
if current == exit:
|
|
path = reconstruct_path(parent, start, exit)
|
|
return path, visited_count
|
|
|
|
for nxt in maze.getNeighbors(current):
|
|
tentative_g = g[current] + nxt.weight
|
|
if tentative_g < g.get(nxt, inf):
|
|
g[nxt] = tentative_g
|
|
parent[nxt] = current
|
|
f = tentative_g + self.h(nxt, exit)
|
|
heapq.heappush(open_heap, (f, counter, nxt))
|
|
counter += 1
|
|
|
|
return [], visited_count |