// // Created by Vlad on 28.07.2024. // #include "omath/pathfinding/a_star.hpp" #include #include #include #include #include namespace { struct OpenListNode final { omath::Vector3 position; float f_cost; [[nodiscard]] bool operator>(const OpenListNode& other) const noexcept { return f_cost > other.f_cost; } }; } namespace omath::pathfinding { struct PathNode final { std::optional> came_from; float g_cost = 0.f; }; std::vector> Astar::reconstruct_final_path(const std::unordered_map, PathNode>& closed_list, const Vector3& current) noexcept { std::vector> path; std::optional current_opt = current; while (current_opt) { path.push_back(*current_opt); auto it = closed_list.find(*current_opt); if (it == closed_list.end()) break; current_opt = it->second.came_from; } std::ranges::reverse(path); return path; } std::vector> Astar::find_path(const Vector3& start, const Vector3& end, const NavigationMesh& nav_mesh) noexcept { std::unordered_map, PathNode> closed_list; std::unordered_map, PathNode> node_data; std::priority_queue, std::greater<>> open_list; auto maybe_start_vertex = nav_mesh.get_closest_vertex(start); auto maybe_end_vertex = nav_mesh.get_closest_vertex(end); if (!maybe_start_vertex || !maybe_end_vertex) return {}; const auto start_vertex = maybe_start_vertex.value(); const auto end_vertex = maybe_end_vertex.value(); node_data.emplace(start_vertex, PathNode{std::nullopt, 0.f}); open_list.push({start_vertex, start_vertex.distance_to(end_vertex)}); while (!open_list.empty()) { auto current = open_list.top().position; open_list.pop(); if (closed_list.contains(current)) continue; auto current_node_it = node_data.find(current); if (current_node_it == node_data.end()) continue; const auto current_node = current_node_it->second; if (current == end_vertex) return reconstruct_final_path(closed_list, current); closed_list.emplace(current, current_node); for (const auto& neighbor: nav_mesh.get_neighbors(current)) { if (closed_list.contains(neighbor)) continue; const float tentative_g_cost = current_node.g_cost + neighbor.distance_to(current); auto node_it = node_data.find(neighbor); if (node_it == node_data.end() || tentative_g_cost < node_it->second.g_cost) { node_data[neighbor] = PathNode{current, tentative_g_cost}; const float f_cost = tentative_g_cost + neighbor.distance_to(end_vertex); open_list.push({neighbor, f_cost}); } } } return {}; } } // namespace omath::pathfinding