Skip to content

Commit 7d194a5

Browse files
authored
Merge pull request #95 from orange-cpp/pathfinding_improvement
removed brackets
2 parents 765d5e7 + eec34c1 commit 7d194a5

File tree

5 files changed

+135
-101
lines changed

5 files changed

+135
-101
lines changed

.clang-format

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ SpaceBeforeParensOptions:
5656
AfterIfMacros: true
5757
AfterOverloadedOperator: false
5858
BeforeNonEmptyParentheses: false
59-
SpaceBeforeRangeBasedForLoopColon: false
59+
SpaceBeforeRangeBasedForLoopColon: true
6060
SpaceInEmptyParentheses: false
6161
SpacesInCStyleCastParentheses: false
6262
SpacesInConditionalStatement: false

include/omath/pathfinding/a_star.hpp

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,5 @@ namespace omath::pathfinding
2222
static std::vector<Vector3<float>>
2323
reconstruct_final_path(const std::unordered_map<Vector3<float>, PathNode>& closed_list,
2424
const Vector3<float>& current) noexcept;
25-
26-
[[nodiscard]]
27-
static auto get_perfect_node(const std::unordered_map<Vector3<float>, PathNode>& open_list,
28-
const Vector3<float>& end_vertex) noexcept;
2925
};
3026
} // namespace omath::pathfinding

source/pathfinding/a_star.cpp

Lines changed: 37 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,25 @@
44
#include "omath/pathfinding/a_star.hpp"
55
#include <algorithm>
66
#include <optional>
7+
#include <queue>
78
#include <unordered_map>
89
#include <unordered_set>
910

11+
namespace
12+
{
13+
struct OpenListNode final
14+
{
15+
omath::Vector3<float> position;
16+
float f_cost;
17+
18+
[[nodiscard]]
19+
bool operator>(const OpenListNode& other) const noexcept
20+
{
21+
return f_cost > other.f_cost;
22+
}
23+
};
24+
}
25+
1026
namespace omath::pathfinding
1127
{
1228
struct PathNode final
@@ -37,23 +53,13 @@ namespace omath::pathfinding
3753
std::ranges::reverse(path);
3854
return path;
3955
}
40-
auto Astar::get_perfect_node(const std::unordered_map<Vector3<float>, PathNode>& open_list,
41-
const Vector3<float>& end_vertex) noexcept
42-
{
43-
return std::ranges::min_element(open_list,
44-
[&end_vertex](const auto& a, const auto& b)
45-
{
46-
const float fa = a.second.g_cost + a.first.distance_to(end_vertex);
47-
const float fb = b.second.g_cost + b.first.distance_to(end_vertex);
48-
return fa < fb;
49-
});
50-
}
5156

5257
std::vector<Vector3<float>> Astar::find_path(const Vector3<float>& start, const Vector3<float>& end,
5358
const NavigationMesh& nav_mesh) noexcept
5459
{
5560
std::unordered_map<Vector3<float>, PathNode> closed_list;
56-
std::unordered_map<Vector3<float>, PathNode> open_list;
61+
std::unordered_map<Vector3<float>, PathNode> node_data;
62+
std::priority_queue<OpenListNode, std::vector<OpenListNode>, std::greater<>> open_list;
5763

5864
auto maybe_start_vertex = nav_mesh.get_closest_vertex(start);
5965
auto maybe_end_vertex = nav_mesh.get_closest_vertex(end);
@@ -64,20 +70,27 @@ namespace omath::pathfinding
6470
const auto start_vertex = maybe_start_vertex.value();
6571
const auto end_vertex = maybe_end_vertex.value();
6672

67-
open_list.emplace(start_vertex, PathNode{std::nullopt, 0.f});
73+
node_data.emplace(start_vertex, PathNode{std::nullopt, 0.f});
74+
open_list.push({start_vertex, start_vertex.distance_to(end_vertex)});
6875

6976
while (!open_list.empty())
7077
{
71-
auto current_it = get_perfect_node(open_list, end_vertex);
78+
auto current = open_list.top().position;
79+
open_list.pop();
80+
81+
if (closed_list.contains(current))
82+
continue;
83+
84+
auto current_node_it = node_data.find(current);
85+
if (current_node_it == node_data.end())
86+
continue;
7287

73-
const auto current = current_it->first;
74-
const auto current_node = current_it->second;
88+
const auto current_node = current_node_it->second;
7589

7690
if (current == end_vertex)
7791
return reconstruct_final_path(closed_list, current);
7892

7993
closed_list.emplace(current, current_node);
80-
open_list.erase(current_it);
8194

8295
for (const auto& neighbor: nav_mesh.get_neighbors(current))
8396
{
@@ -86,11 +99,14 @@ namespace omath::pathfinding
8699

87100
const float tentative_g_cost = current_node.g_cost + neighbor.distance_to(current);
88101

89-
// ReSharper disable once CppTooWideScopeInitStatement
90-
const auto open_it = open_list.find(neighbor);
102+
auto node_it = node_data.find(neighbor);
91103

92-
if (open_it == open_list.end() || tentative_g_cost < open_it->second.g_cost)
93-
open_list[neighbor] = PathNode{current, tentative_g_cost};
104+
if (node_it == node_data.end() || tentative_g_cost < node_it->second.g_cost)
105+
{
106+
node_data[neighbor] = PathNode{current, tentative_g_cost};
107+
const float f_cost = tentative_g_cost + neighbor.distance_to(end_vertex);
108+
open_list.push({neighbor, f_cost});
109+
}
94110
}
95111
}
96112

source/pathfinding/navigation_mesh.cpp

Lines changed: 34 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
//
44
#include "omath/pathfinding/navigation_mesh.hpp"
55
#include <algorithm>
6+
#include <cstring>
7+
#include <limits>
68
#include <stdexcept>
79
namespace omath::pathfinding
810
{
@@ -30,55 +32,68 @@ namespace omath::pathfinding
3032

3133
std::vector<uint8_t> NavigationMesh::serialize() const noexcept
3234
{
33-
auto dump_to_vector = []<typename T>(const T& t, std::vector<uint8_t>& vec)
34-
{
35-
for (size_t i = 0; i < sizeof(t); i++)
36-
vec.push_back(*(reinterpret_cast<const uint8_t*>(&t) + i));
37-
};
38-
39-
std::vector<uint8_t> raw;
35+
std::vector<std::uint8_t> raw;
4036

41-
for (const auto& [vertex, neighbors]: m_vertex_map)
37+
// Pre-calculate total size for better performance
38+
std::size_t total_size = 0;
39+
for (const auto& [vertex, neighbors] : m_vertex_map)
4240
{
43-
const auto neighbors_count = neighbors.size();
41+
total_size += sizeof(vertex) + sizeof(std::uint16_t) + sizeof(Vector3<float>) * neighbors.size();
42+
}
43+
raw.reserve(total_size);
4444

45-
dump_to_vector(vertex, raw);
46-
dump_to_vector(neighbors_count, raw);
45+
auto dump_to_vector = [&raw]<typename T>(const T& t)
46+
{
47+
const auto* byte_ptr = reinterpret_cast<const std::uint8_t*>(&t);
48+
raw.insert(raw.end(), byte_ptr, byte_ptr + sizeof(T));
49+
};
4750

48-
for (const auto& neighbor: neighbors)
49-
dump_to_vector(neighbor, raw);
51+
for (const auto& [vertex, neighbors] : m_vertex_map)
52+
{
53+
// Clamp neighbors count to fit in uint16_t (prevents silent data corruption)
54+
// NOTE: If neighbors.size() > 65535, only the first 65535 neighbors will be serialized.
55+
// This is a limitation of the current serialization format using uint16_t for count.
56+
const auto clamped_count =
57+
std::min<std::size_t>(neighbors.size(), std::numeric_limits<std::uint16_t>::max());
58+
const auto neighbors_count = static_cast<std::uint16_t>(clamped_count);
59+
60+
dump_to_vector(vertex);
61+
dump_to_vector(neighbors_count);
62+
63+
// Only serialize up to the clamped count
64+
for (std::size_t i = 0; i < clamped_count; ++i)
65+
dump_to_vector(neighbors[i]);
5066
}
5167
return raw;
5268
}
5369

5470
void NavigationMesh::deserialize(const std::vector<uint8_t>& raw) noexcept
5571
{
56-
auto load_from_vector = [](const std::vector<uint8_t>& vec, size_t& offset, auto& value)
72+
auto load_from_vector = [](const std::vector<uint8_t>& vec, std::size_t& offset, auto& value)
5773
{
5874
if (offset + sizeof(value) > vec.size())
59-
{
6075
throw std::runtime_error("Deserialize: Invalid input data size.");
61-
}
76+
6277
std::copy_n(vec.data() + offset, sizeof(value), reinterpret_cast<uint8_t*>(&value));
6378
offset += sizeof(value);
6479
};
6580

6681
m_vertex_map.clear();
6782

68-
size_t offset = 0;
83+
std::size_t offset = 0;
6984

7085
while (offset < raw.size())
7186
{
7287
Vector3<float> vertex;
7388
load_from_vector(raw, offset, vertex);
7489

75-
uint16_t neighbors_count;
90+
std::uint16_t neighbors_count;
7691
load_from_vector(raw, offset, neighbors_count);
7792

7893
std::vector<Vector3<float>> neighbors;
7994
neighbors.reserve(neighbors_count);
8095

81-
for (size_t i = 0; i < neighbors_count; ++i)
96+
for (std::size_t i = 0; i < neighbors_count; ++i)
8297
{
8398
Vector3<float> neighbor;
8499
load_from_vector(raw, offset, neighbor);

0 commit comments

Comments
 (0)