diff --git a/semyanovra/scr/maze.py b/semyanovra/scr/maze.py index 9d55726..bd40478 100644 --- a/semyanovra/scr/maze.py +++ b/semyanovra/scr/maze.py @@ -149,7 +149,115 @@ class TxtLabyrinthBuilder(LabyrinthBuilder): return lab +# ----------------------------- Алгоритмы поиска ----------------------------- +class SearchAlgorithm: + def compute_path(self, maze, start, goal): + raise NotImplementedError + + 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_nodes(self): + return getattr(self, '_visited', 0) + + +class BFS(SearchAlgorithm): + def compute_path(self, maze, start, goal): + q = deque() + q.append(start) + came_from = {start: None} + visited = {start} + + while q: + cur = q.popleft() + if cur == goal: + self._visited = len(visited) + return self._build_path(came_from, start, goal) + for nb in maze.adjacent_cells(cur): + if nb not in visited: + visited.add(nb) + came_from[nb] = cur + q.append(nb) + self._visited = len(visited) + return [] + + +class DFS(SearchAlgorithm): + def compute_path(self, maze, start, goal): + stack = [start] + came_from = {start: None} + visited = {start} + + while stack: + cur = stack.pop() + if cur == goal: + self._visited = len(visited) + return self._build_path(came_from, start, goal) + for nb in maze.adjacent_cells(cur): + if nb not in visited: + visited.add(nb) + came_from[nb] = cur + stack.append(nb) + self._visited = len(visited) + return [] + + +class AStar(SearchAlgorithm): + def _heuristic(self, cell, goal): + return abs(cell.x - goal.x) + abs(cell.y - goal.y) + + def compute_path(self, maze, start, goal): + heap = [] + counter = 0 + start_f = self._heuristic(start, goal) + heapq.heappush(heap, (start_f, counter, start)) + counter += 1 + + came_from = {} + g_score = {start: 0} + f_score = {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(came_from, start, goal) + if cur_f > f_score.get(cur, float('inf')): + continue + for nb in maze.adjacent_cells(cur): + tentative_g = g_score[cur] + 1 + if tentative_g < g_score.get(nb, float('inf')): + came_from[nb] = cur + g_score[nb] = tentative_g + new_f = tentative_g + self._heuristic(nb, goal) + f_score[nb] = new_f + heapq.heappush(heap, (new_f, counter, nb)) + counter += 1 + self._visited = len(visited) + return [] + + if __name__ == "__main__": builder = TxtLabyrinthBuilder() maze = builder.build_from_file("maze/level1.txt") - print(f"Maze loaded: {maze.width}x{maze.height}") \ No newline at end of file + + bfs = BFS() + path = bfs.compute_path(maze, maze.start, maze.exit) + print(f"BFS path length: {len(path)}") + + dfs = DFS() + path = dfs.compute_path(maze, maze.start, maze.exit) + print(f"DFS path length: {len(path)}") + + astar = AStar() + path = astar.compute_path(maze, maze.start, maze.exit) + print(f"A* path length: {len(path)}") \ No newline at end of file