Skip to content

Commit bfd9b81

Browse files
Add A* algorithm tests and update CMake configuration for navigation and listeners
1 parent 46c3988 commit bfd9b81

File tree

4 files changed

+107
-7
lines changed

4 files changed

+107
-7
lines changed

CMakeLists.txt

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@ if(${LOGGING_LEVEL_INDEX} EQUAL -1)
2323
message(FATAL_ERROR "Invalid logging level: ${LOGGING_LEVEL}")
2424
endif()
2525

26-
option(BUILD_LISTENERS "Build listners")
26+
option(BUILD_LISTENERS "Build listners" OFF)
27+
option(BUILD_NAVIGATION "Build navigation" OFF)
2728
option(BUILD_CRYPTO "Build crypto" OFF)
2829

2930
if(LOGGING_LEVEL STREQUAL "TRACE")
@@ -54,6 +55,11 @@ if(BUILD_LISTENERS)
5455
target_compile_definitions(utils PUBLIC BUILD_LISTENERS)
5556
endif()
5657

58+
message(STATUS "Build navigation: ${BUILD_NAVIGATION}")
59+
if(BUILD_NAVIGATION)
60+
target_compile_definitions(utils PUBLIC BUILD_NAVIGATION)
61+
endif()
62+
5763
message(STATUS "Build crypto: ${BUILD_CRYPTO}")
5864
if(BUILD_CRYPTO)
5965
find_package(OpenSSL REQUIRED)

include/a_star.hpp

Lines changed: 58 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#include <memory>
55
#include <queue>
66
#include <unordered_set>
7+
#include <stdexcept>
78

89
namespace utils
910
{
@@ -116,12 +117,23 @@ namespace utils
116117
{
117118
while (!open_list.empty())
118119
{
119-
auto c_node = open_list.top();
120+
auto next = open_list.top();
121+
open_list.pop();
122+
#ifdef BUILD_NAVIGATION
123+
backtrack_to(find_common_ancestor(*c_node, *next));
124+
if (!go_to(*next))
125+
{ // Conflict detected, backtrack..
126+
#ifdef BUILD_LISTENERS
127+
inconsistent_node(*next);
128+
#endif
129+
continue;
130+
}
131+
#else
132+
c_node = next;
120133
#ifdef BUILD_LISTENERS
121134
current_node(*c_node);
122135
#endif
123-
open_list.pop();
124-
136+
#endif
125137
if (c_node->is_goal())
126138
return c_node;
127139

@@ -138,11 +150,12 @@ namespace utils
138150
}
139151

140152
#ifdef BUILD_LISTENERS
141-
virtual void current_node(const node<Tp> &c_node) {}
153+
virtual void current_node(const node<Tp> &n) {}
154+
virtual void inconsistent_node(const node<Tp> &n) {}
142155
#endif
143156

144157
protected:
145-
const node<Tp> &find_common_ancestor(const node &a, const node &b) const
158+
const node<Tp> &find_common_ancestor(const node<Tp> &a, const node<Tp> &b) const
146159
{
147160
std::unordered_set<const node<Tp> *> ancestors;
148161
auto c_a = &a;
@@ -161,7 +174,47 @@ namespace utils
161174
throw std::runtime_error("No common ancestor found");
162175
}
163176

177+
void backtrack_to(const node<Tp> &n) noexcept
178+
{
179+
while (&c_node->get() != &n)
180+
{
181+
retract(*c_node);
182+
c_node = c_node->get_parent();
183+
#ifdef BUILD_LISTENERS
184+
current_node(*c_node);
185+
#endif
186+
}
187+
}
188+
189+
virtual void retract(const node<Tp> &n) noexcept {}
190+
191+
bool go_to(const node<Tp> &target) noexcept
192+
{
193+
std::vector<const node<Tp> *> path;
194+
auto temp_node = &target;
195+
while (temp_node != &c_node->get())
196+
{
197+
path.push_back(temp_node);
198+
temp_node = temp_node->get_parent().get();
199+
}
200+
for (auto it = path.rbegin(); it != path.rend(); ++it)
201+
{
202+
if (!apply_transition(**it))
203+
return false;
204+
c_node = (*it)->get_parent();
205+
#ifdef BUILD_LISTENERS
206+
current_node(*c_node);
207+
#endif
208+
}
209+
return true;
210+
}
211+
212+
virtual bool apply_transition(const node<Tp> &n) noexcept { return true; }
213+
214+
[[nodiscard]] node<Tp> &current_node() noexcept { return *c_node; }
215+
164216
private:
217+
std::shared_ptr<node<Tp>> c_node;
165218
std::priority_queue<std::shared_ptr<node<Tp>>, std::vector<std::shared_ptr<node<Tp>>>, node_cmp> open_list;
166219
std::unordered_set<std::shared_ptr<const node<Tp>>> closed_list;
167220
};

tests/CMakeLists.txt

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,13 @@ add_dependencies(floyd_warshall_tests utils)
1818
target_link_libraries(floyd_warshall_tests PRIVATE utils)
1919
setup_sanitizers(floyd_warshall_tests)
2020

21+
add_executable(a_star_tests test_a_star.cpp)
22+
add_dependencies(a_star_tests utils)
23+
target_link_libraries(a_star_tests PRIVATE utils)
24+
setup_sanitizers(a_star_tests)
25+
2126
add_test(NAME UTILS_LibTest COMMAND utils_lib_tests WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
2227
add_test(NAME CryptoTest COMMAND crypto_tests WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
2328
add_test(NAME PointersTest COMMAND pointers_tests WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
24-
add_test(NAME FloydWarshallTest COMMAND floyd_warshall_tests WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
29+
add_test(NAME FloydWarshallTest COMMAND floyd_warshall_tests WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
30+
add_test(NAME AStarTest COMMAND a_star_tests WORKING_DIRECTORY ${CMAKE_BINARY_DIR})

tests/test_a_star.cpp

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
#include "a_star.hpp"
2+
#include <iostream>
3+
#include <cassert>
4+
5+
class my_node : public utils::node<int>, public std::enable_shared_from_this<my_node>
6+
{
7+
public:
8+
my_node(std::weak_ptr<my_node> parent, const int &g_cost) noexcept : utils::node<int>(std::move(parent), g_cost) {}
9+
~my_node() override = default;
10+
11+
[[nodiscard]] int h_cost() const noexcept override { return 0; }
12+
13+
[[nodiscard]] std::vector<std::shared_ptr<utils::node<int>>> generate_successors() const override
14+
{
15+
std::vector<std::shared_ptr<utils::node<int>>> successors;
16+
if (g_cost() < 10)
17+
{
18+
auto succ = std::make_shared<my_node>(shared_from_this(), g_cost() + 1);
19+
successors.push_back(succ);
20+
}
21+
return successors;
22+
}
23+
24+
[[nodiscard]] bool is_goal() const noexcept override { return g_cost() >= 10; }
25+
};
26+
27+
int main()
28+
{
29+
auto root = std::make_shared<my_node>(std::weak_ptr<my_node>(), 0);
30+
utils::a_star<int> astar(root);
31+
auto goal_node = astar.search();
32+
assert(goal_node);
33+
assert(goal_node->g_cost() == 10);
34+
return 0;
35+
}

0 commit comments

Comments
 (0)