1 Commits

Author SHA1 Message Date
da7e 16d97e9912 fix(astar): function f() miscalculate the best path 2026-03-27 21:51:49 +01:00
2 changed files with 62 additions and 71 deletions
+46 -55
View File
@@ -9,44 +9,30 @@ class MazeSolver(ABC):
self.end = (end[1] - 1, end[0] - 1) self.end = (end[1] - 1, end[0] - 1)
@abstractmethod @abstractmethod
def solve(self, maze: Maze, height: int = None, def solve(
width: int = None) -> str: ... self, maze: Maze, height: int = None, width: int = None
) -> str: ...
class AStar(MazeSolver): class AStar(MazeSolver):
def __init__(self, start: tuple[int, int], end: tuple[int, int]) -> None: def __init__(self, start: tuple[int, int], end: tuple[int, int]) -> None:
super().__init__(start, end) super().__init__(start, end)
self.path = []
def f(self, n): def f(self, n):
def g(n: tuple[int, int]) -> int: def g() -> int:
res = 0 return len(self.path) + 1
if n[0] < self.start[0]:
res += self.start[0] - n[0]
else:
res += n[0] - self.start[0]
if n[1] < self.start[1]:
res += self.start[1] - n[1]
else:
res += n[1] - self.start[1]
return res
def h(n: tuple[int, int]) -> int: def h(n: tuple[int, int]) -> int:
res = 0 return (
if n[0] < self.end[0]: max(n[0], self.end[0])
res += self.end[0] - n[0] - min(n[0], self.end[0])
else: + max(n[1], self.end[1])
res += n[0] - self.end[0] - min(n[1], self.end[1])
if n[1] < self.end[1]: )
res += self.end[1] - n[1]
else:
res += n[1] - self.end[1]
return res
try: return g() + h(n)
return g(n) + h(n)
except Exception:
return 1000
def best_path( def best_path(
self, self,
@@ -113,47 +99,46 @@ class AStar(MazeSolver):
return actual return actual
def get_path(self, maze: np.ndarray) -> str | None: def get_path(self, maze: np.ndarray) -> str | None:
path = [(self.start, self.best_path(maze, self.start, None))] self.path = [(self.start, self.best_path(maze, self.start, None))]
visited = [self.start] visited = [self.start]
while len(path) > 0 and path[-1][0] != self.end: while len(self.path) > 0 and self.path[-1][0] != self.end:
if len(path[-1][1]) == 0: if len(self.path[-1][1]) == 0:
path.pop(-1) self.path.pop(-1)
if len(path) == 0: if len(self.path) == 0:
break break
k = next(iter(path[-1][1])) k = next(iter(self.path[-1][1]))
path[-1][1].pop(k) self.path[-1][1].pop(k)
continue continue
while len(path[-1][1]) > 0: while len(self.path[-1][1]) > 0:
next_pos = self.get_next_pos( next_pos = self.get_next_pos(
list(path[-1][1].keys())[0], path[-1][0] list(self.path[-1][1].keys())[0], self.path[-1][0]
) )
if next_pos in visited: if next_pos in visited:
k = next(iter(path[-1][1])) k = next(iter(self.path[-1][1]))
path[-1][1].pop(k) self.path[-1][1].pop(k)
else: else:
break break
if len(path[-1][1]) == 0: if len(self.path[-1][1]) == 0:
path.pop(-1) self.path.pop(-1)
continue continue
pre = self.get_opposit(list(path[-1][1].keys())[0]) pre = self.get_opposit(list(self.path[-1][1].keys())[0])
path.append( self.path.append(
( (
next_pos, next_pos,
self.best_path(maze, next_pos, pre), self.best_path(maze, next_pos, pre),
) )
) )
visited += [next_pos] visited += [next_pos]
if len(path) == 0: if len(self.path) == 0:
return None return None
path[-1] = (self.end, {}) self.path[-1] = (self.end, {})
return "".join( return "".join(
str(list(c[1].keys())[0]) for c in path if len(c[1]) > 0 str(list(c[1].keys())[0]) for c in self.path if len(c[1]) > 0
) )
def solve(self, maze: Maze, height: int = None, def solve(self, maze: Maze, height: int = None, width: int = None) -> str:
width: int = None) -> str:
res = self.get_path(maze.get_maze()) res = self.get_path(maze.get_maze())
if res is None: if res is None:
raise Exception("Path not found") raise Exception("Path not found")
@@ -164,8 +149,7 @@ class DepthFirstSearchSolver(MazeSolver):
def __init__(self, start, end): def __init__(self, start, end):
super().__init__(start, end) super().__init__(start, end)
def solve(self, maze: Maze, height: int = None, def solve(self, maze: Maze, height: int = None, width: int = None) -> str:
width: int = None) -> str:
path_str = "" path_str = ""
visited = np.zeros((height, width), dtype=bool) visited = np.zeros((height, width), dtype=bool)
path = list() path = list()
@@ -179,8 +163,9 @@ class DepthFirstSearchSolver(MazeSolver):
rand_p = self.random_path(visited, coord, maze_s, h_w) rand_p = self.random_path(visited, coord, maze_s, h_w)
if not rand_p: if not rand_p:
path, move = self.back_on_step(path, visited, maze_s, h_w, path, move = self.back_on_step(
move) path, visited, maze_s, h_w, move
)
if not path: if not path:
break break
coord = path[-1] coord = path[-1]
@@ -195,8 +180,9 @@ class DepthFirstSearchSolver(MazeSolver):
return path_str return path_str
@staticmethod @staticmethod
def random_path(visited: np.ndarray, coord: tuple, def random_path(
maze: np.ndarray, h_w: tuple) -> list: visited: np.ndarray, coord: tuple, maze: np.ndarray, h_w: tuple
) -> list:
random_p = [] random_p = []
h, w = h_w h, w = h_w
y, x = coord y, x = coord
@@ -219,8 +205,13 @@ class DepthFirstSearchSolver(MazeSolver):
return np.random.choice(rand_path) return np.random.choice(rand_path)
@staticmethod @staticmethod
def back_on_step(path: list, visited: np.ndarray, def back_on_step(
maze: np.ndarray, h_w: tuple, move: list) -> list: path: list,
visited: np.ndarray,
maze: np.ndarray,
h_w: tuple,
move: list,
) -> list:
while path: while path:
last = path[-1] last = path[-1]
if DepthFirstSearchSolver.random_path(visited, last, maze, h_w): if DepthFirstSearchSolver.random_path(visited, last, maze, h_w):
+16 -16
View File
@@ -1,19 +1,19 @@
D553955513B913B D53939553D13B93
9796C553AA86AC2 93AAC697A92C6AA
83C151146AC7C12 AC6A95056AE956A
C03856817C393EA A916856D1454152
96EC53A8556AC3A A843C5394555696
8553FC6AFFFABC2 A87AF96AFFFB96B
8792FD5057FAC16 AE96FC5457F8412
E946FFFAFFF83AB C52BFFFBFFFC102
92913BFAFD52AC2 B94453FAFD516EA
AEAAC6FAFFFEC3A 86953AFAFFFA956
A904553A9555382 81692C54153A853
828557AAAD5546E AC3A83950546C3A
844553C6C151553 ABA86C2D69517C2
C5395439545453A C2AC55293ABC53A
D546D546D555546 D6C55546C4457C6
1,1 1,1
2,2 2,2
EEESWSEEEEEENNESSSESWWWSSSSSSSSWNNWWWNNWSSSSEEESWWSWNWWNENWNNNENEENNWWWNENNWNE EESSWN