Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
ida_star_grid_example.cc
Go to the documentation of this file.
1/*
2 Aleph_w
3
4 Data structures & Algorithms
5 version 2.0.0b
6 https://github.com/lrleon/Aleph-w
7
8 This file is part of Aleph-w library
9
10 Copyright (c) 2002-2026 Leandro Rabindranath Leon
11
12 Permission is hereby granted, free of charge, to any person obtaining a copy
13 of this software and associated documentation files (the "Software"), to deal
14 in the Software without restriction, including without limitation the rights
15 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16 copies of the Software, and to permit persons to whom the Software is
17 furnished to do so, subject to the following conditions:
18
19 The above copyright notice and this permission notice shall be included in all
20 copies or substantial portions of the Software.
21
22 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28 SOFTWARE.
29*/
30
51# include <array>
52# include <iostream>
53
54# include <State_Search.H>
55
56using Aleph::Array;
57
58namespace
59{
60
61namespace Search = Aleph::Search;
62
63// ---------------------------------------------------------------------------
64// Grid layout
65// ---------------------------------------------------------------------------
66
67// 0 = free, 1 = obstacle
68// clang-format off
69static constexpr int GRID_ROWS = 6;
70static constexpr int GRID_COLS = 8;
71static constexpr std::array<std::array<int, GRID_COLS>, GRID_ROWS> GRID = {{
72 { 0, 0, 0, 0, 0, 0, 0, 0 },
73 { 0, 1, 1, 0, 1, 1, 0, 0 },
74 { 0, 0, 0, 0, 1, 0, 0, 0 },
75 { 0, 1, 0, 1, 1, 0, 1, 0 },
76 { 0, 1, 0, 0, 0, 0, 1, 0 },
77 { 0, 0, 0, 0, 0, 0, 0, 0 },
78}};
79// clang-format on
80
81static constexpr int START_ROW = 0;
82static constexpr int START_COL = 0;
83static constexpr int GOAL_ROW = 5;
84static constexpr int GOAL_COL = 7;
85
86// ---------------------------------------------------------------------------
87// Domain
88// ---------------------------------------------------------------------------
89
90struct GridState
91{
92 int row = 0;
93 int col = 0;
94
95 bool operator==(const GridState &) const = default;
96};
97
98struct GridDomain
99{
100 struct Move
101 {
102 int dr = 0;
103 int dc = 0;
104 };
105
106 using State = GridState;
107 using Distance = int;
108
109 const int goal_row;
110 const int goal_col;
111
112 explicit GridDomain(const int gr = GOAL_ROW, const int gc = GOAL_COL)
113 : goal_row(gr), goal_col(gc)
114 {
115 // empty
116 }
117
118 bool is_goal(const State &s) const noexcept
119 {
120 return s.row == goal_row and s.col == goal_col;
121 }
122
123 Distance heuristic(const State &s) const noexcept
124 {
125 return std::abs(s.row - goal_row) + std::abs(s.col - goal_col);
126 }
127
128 Distance cost(const State &, const Move &) const noexcept
129 {
130 return 1;
131 }
132
133 void apply(State &s, const Move &m) const noexcept
134 {
135 s.row += m.dr;
136 s.col += m.dc;
137 }
138
139 void undo(State &s, const Move &m) const noexcept
140 {
141 s.row -= m.dr;
142 s.col -= m.dc;
143 }
144
145 template <typename Visitor>
146 bool for_each_successor(const State &s, Visitor visit) const
147 {
148 static constexpr std::array<Move, 4> dirs = {{
149 {-1, 0}, // up
150 { 1, 0}, // down
151 { 0, -1}, // left
152 { 0, 1}, // right
153 }};
154
155 for (const auto &d : dirs)
156 {
157 const int nr = s.row + d.dr;
158 const int nc = s.col + d.dc;
159
161 continue;
162 if (GRID[static_cast<size_t>(nr)][static_cast<size_t>(nc)] != 0)
163 continue;
164
165 if (not visit(d))
166 return false;
167 }
168
169 return true;
170 }
171};
172
173// ---------------------------------------------------------------------------
174// Helpers
175// ---------------------------------------------------------------------------
176
177char cell_char(const int r, const int c)
178{
179 if (r == START_ROW and c == START_COL)
180 return 'S';
181 if (r == GOAL_ROW and c == GOAL_COL)
182 return 'G';
183 return GRID[static_cast<size_t>(r)][static_cast<size_t>(c)] ? '#' : '.';
184}
185
186void print_grid()
187{
188 std::cout << "Grid (" << GRID_ROWS << 'x' << GRID_COLS
189 << ", S=start, G=goal, #=obstacle):\n";
190 for (int r = 0; r < GRID_ROWS; ++r)
191 {
192 std::cout << " ";
193 for (int c = 0; c < GRID_COLS; ++c)
194 std::cout << cell_char(r, c);
195 std::cout << '\n';
196 }
197}
198
200 const GridState &start)
201{
202 GridState pos = start;
203 std::cout << " (" << pos.row << ',' << pos.col << ')';
204 for (const auto &m : path)
205 {
206 pos.row += m.dr;
207 pos.col += m.dc;
208 std::cout << " -> (" << pos.row << ',' << pos.col << ')';
209 }
210 std::cout << '\n';
211}
212
213} // end namespace
214
215int main()
216{
217 std::cout << "IDA* grid pathfinding example\n\n";
218 print_grid();
219 std::cout << '\n';
220
221 GridDomain domain(GOAL_ROW, GOAL_COL);
222 const GridState root{START_ROW, START_COL};
223
224 auto result = Search::ida_star_search(domain, root);
225
226 std::cout << "Status: ";
227 switch (result.status)
228 {
229 case Aleph::SearchStatus::StoppedOnSolution: std::cout << "solution found\n"; break;
230 case Aleph::SearchStatus::Exhausted: std::cout << "exhausted (no path)\n"; break;
231 case Aleph::SearchStatus::LimitReached: std::cout << "limit reached\n"; break;
232 default: std::cout << "not started\n"; break;
233 }
234
235 std::cout << "IDA* iterations: " << result.iterations.size() << '\n';
236 std::cout << "Total visited states: " << result.stats.visited_states << '\n';
237 std::cout << "Total expanded states: " << result.stats.expanded_states << '\n';
238
239 for (size_t i = 0; i < result.iterations.size(); ++i)
240 {
241 const auto &it = result.iterations[i];
242 std::cout << " Iteration " << i + 1
243 << ": threshold=" << it.threshold
244 << " visited=" << it.visited_states
245 << (it.found_solution ? " FOUND" : "") << '\n';
246 }
247
248 if (result.found_solution())
249 {
250 const auto &sol = result.best_solution.get();
251 std::cout << "\nOptimal path cost: " << result.total_cost << " steps\n";
252 std::cout << "Path:\n";
253 print_path(sol.path, root);
254 }
255 else
256 {
257 std::cout << "\nNo path found from ("
258 << START_ROW << ',' << START_COL << ") to ("
259 << GOAL_ROW << ',' << GOAL_COL << ")\n";
260 }
261
262 return 0;
263}
Umbrella header for the implicit state-space search framework.
void print_path(Path< WeightedDigraph > &path, WeightedDigraph &g)
Simple dynamic array with automatic resizing and functional operations.
Definition tpl_array.H:139
__gmp_expr< T, __gmp_binary_expr< __gmp_expr< T, U >, unsigned long int, __gmp_root_function > > root(const __gmp_expr< T, U > &expr, unsigned long int l)
Definition gmpfrxx.h:4060
User-facing facade exported by the umbrella search header.
and
Check uniqueness with explicit hash + equality functors.
bool operator==(const DynList< T > &l1, const DynList< T > &l2)
Equality operator for DynList.
@ LimitReached
Search stopped because an external hard limit was hit.
@ Exhausted
Search space within the configured bounds was exhausted.
@ StoppedOnSolution
Search stopped because solution handling requested it.
Divide_Conquer_DP_Result< Cost > divide_and_conquer_partition_dp(const size_t groups, const size_t n, Transition_Cost_Fn transition_cost, const Cost inf=dp_optimization_detail::default_inf< Cost >())
Optimize partition DP using divide-and-conquer optimization.
Distance accessor.
FooMap m(5, fst_unit_pair_hash, snd_unit_pair_hash)
gsl_rng * r