Horizon Official Technical Documentation
AStar.hpp
Go to the documentation of this file.
1/***************************************************
2 * _ _ _ *
3 * | | | | (_) *
4 * | |_| | ___ _ __ _ _______ _ __ *
5 * | _ |/ _ \| '__| |_ / _ \| '_ \ *
6 * | | | | (_) | | | |/ / (_) | | | | *
7 * \_| |_/\___/|_| |_/___\___/|_| |_| *
8 ***************************************************
9 * This file is part of Horizon (c).
10 *
11 * Copyright (c) 2019 Sagun K. (sagunxp@gmail.com).
12 * Copyright (c) 2019 Horizon Dev Team.
13 * Copyright (c) 2015 Damian Barczynski <daan.net@wp.eu>
14 *
15 * This library is free software; you can redistribute it and/or modify
16 * it under the terms of the GNU General Public License as published by
17 * the Free Software Foundation, either version 3 of the License, or
18 * (at your option) any later version.
19 *
20 * This library is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
24 *
25 * You should have received a copy of the GNU General Public License
26 * along with this library. If not, see <http://www.gnu.org/licenses/>.
27
28 *
29 * Following tool is licensed under the terms and conditions of the ISC license.
30 * License terms - https://github.com/daancode/a-star/blob/master/LICENSE
31 **************************************************/
32
33#ifndef HORIZON_ZONE_GAME_MAP_PATH_ASTAR_HPP
34#define HORIZON_ZONE_GAME_MAP_PATH_ASTAR_HPP
35
39#include <cmath>
40#include <memory>
41#include <functional>
42#include <vector>
43
44namespace Horizon
45{
46namespace Zone
47{
48namespace AStar
49{
51{
52 static MapCoords getDelta(MapCoords source_, MapCoords target_) { return MapCoords(abs(target_.x() - source_.x()), abs(target_.y() - source_.y())); }
53
54public:
55 static uint32_t manhattan(MapCoords source_, MapCoords target_)
56 {
57 auto delta = getDelta(source_, target_);
58 return static_cast<uint32_t>(10 * (delta.x() + delta.y()));
59 }
60
61 static uint32_t euclidean(MapCoords source_, MapCoords target_)
62 {
63 auto delta = getDelta(source_, target_);
64 return static_cast<uint32_t>(10 * std::sqrt(std::pow(delta.x(), 2) + std::pow(delta.y(), 2)));
65 }
66
67 static uint32_t octagonal(MapCoords source_, MapCoords target_)
68 {
69 auto delta = getDelta(source_, target_);
70 return 10 * (delta.x() + delta.y()) + (-6) * std::min(delta.x(), delta.y());
71 }
72};
73
74typedef std::function<uint32_t(MapCoords, MapCoords)> HeuristicFunction;
77typedef std::vector<MapCoords> CoordinateList;
78typedef std::function<bool(uint16_t x, uint16_t y)> CollisionDetectionFunction;
79
80struct Node
81{
82 uint32_t G, H;
84 std::shared_ptr<Node> parent;
85
86 explicit Node(MapCoords coord_, std::shared_ptr<Node> parent_ = nullptr)
87 {
88 parent = parent_;
89 coordinates = coord_;
90 G = H = 0;
91 }
92
93 uint32_t getFScore() const { return G + H; }
94};
95
96using NodeSet = std::vector<std::shared_ptr<Node>>;
97
99{
100 static std::shared_ptr<Node> findNodeOnList(NodeSet& nodes_, MapCoords coordinates_)
101 {
102 for (auto node : nodes_) {
103 if (node->coordinates == coordinates_) {
104 return node;
105 }
106 }
107 return nullptr;
108 }
109 static void releaseNodes(NodeSet nodes_)
110 {
111 for (auto it = nodes_.begin(); it != nodes_.end();) {
112 it = nodes_.erase(it);
113 }
114 }
115
116public:
118 {
121 }
122
123 Generator(MapCoords worldSize_, CollisionDetectionFunction c, bool diagonal_movement = true, HeuristicFunction h = &Heuristic::manhattan)
124 {
125 setWorldSize(worldSize_);
126 setCollisionDetectionFunction(std::move(c));
127 setDiagonalMovement(diagonal_movement);
128 setHeuristic(h);
129 }
130
131 void setWorldSize(MapCoords worldSize_) { worldSize = worldSize_; }
132
134
135 void setDiagonalMovement(bool enable_) { directions = (enable_ ? 8 : 4); }
136
137 void setHeuristic(const HeuristicFunction& heuristic_) { heuristic = [heuristic_](auto && PH1, auto && PH2) { return heuristic_(std::forward<decltype(PH1)>(PH1), std::forward<decltype(PH2)>(PH2)); }; }
138
140 {
141 CoordinateList path;
142 std::shared_ptr<Node> current = nullptr;
143 NodeSet openSet, closedSet;
144 int searchStep = 0;
145
146 openSet.reserve(20);
147 closedSet.reserve(20);
148 openSet.push_back(std::make_shared<Node>(source_));
149
150 if (check_collision(target_.x(), target_.y()))
151 return path;
152
153 while (!openSet.empty() && searchStep < MAX_VIEW_RANGE) {
154 auto current_it = openSet.begin();
155
156 current = *current_it;
157
158 for (auto it = openSet.begin(); it != openSet.end(); it++) {
159 auto node = *it;
160 if (node->getFScore() <= current->getFScore()) {
161 current = node;
162 current_it = it;
163 }
164 }
165
166 if (current->coordinates == target_)
167 break;
168
169 closedSet.push_back(current);
170 openSet.erase(current_it);
171
172 for (uint32_t i = 0; i < directions; ++i) {
173 MapCoords newCoordinates(current->coordinates + direction[i]);
174
175 if (check_collision(newCoordinates.x(), newCoordinates.y())
176 || findNodeOnList(closedSet, newCoordinates)) {
177 continue;
178 }
179
180 newCoordinates.set_move_cost((i < 4) ? 10 : 14);
181 uint32_t totalCost = current->G + newCoordinates.move_cost();
182
183 std::shared_ptr<Node> successor = findNodeOnList(openSet, newCoordinates);
184 if (successor == nullptr) {
185 successor = std::make_shared<Node>(newCoordinates, current);
186 successor->G = totalCost;
187 successor->H = heuristic(successor->coordinates, target_);
188 openSet.push_back(successor);
189 } else if (totalCost < successor->G) {
190 successor->parent = current;
191 successor->G = totalCost;
192 }
193 }
194
195 searchStep++;
196 }
197
198 while (current != nullptr) {
199 path.push_back(current->coordinates);
200 current = current->parent;
201 }
202
203 releaseNodes(openSet);
204 releaseNodes(closedSet);
205
206 return path;
207 }
208
209private:
213 { 0, 1 }, { 1, 0 }, { 0, -1 }, { -1, 0 },
214 { -1, -1 }, { 1, 1 }, { -1, 1 }, { 1, -1 }
215 };
217 uint32_t directions{0};
218};
219}
220}
221}
222
223#endif /* HORIZON_ZONE_GAME_MAP_PATH_ASTAR_HPP */
Coordinates< MAX_CELLS_PER_MAP > MapCoords
Definition: GridDefinitions.hpp:83
#define MAX_VIEW_RANGE
Definition: Horizon.hpp:59
directions
Definition: UnitDefinitions.hpp:75
int16_t y() const
Definition: Coordinates.hpp:120
int16_t move_cost() const
Definition: Coordinates.hpp:121
int16_t x() const
Definition: Coordinates.hpp:119
void set_move_cost(int16_t move_cost)
Definition: Coordinates.hpp:122
Definition: AStar.hpp:99
CoordinateList direction
Definition: AStar.hpp:212
static void releaseNodes(NodeSet nodes_)
Definition: AStar.hpp:109
void setDiagonalMovement(bool enable_)
Definition: AStar.hpp:135
Generator()
Definition: AStar.hpp:117
void setCollisionDetectionFunction(CollisionDetectionFunction c)
Definition: AStar.hpp:133
CollisionDetectionFunction check_collision
Definition: AStar.hpp:211
Generator(MapCoords worldSize_, CollisionDetectionFunction c, bool diagonal_movement=true, HeuristicFunction h=&Heuristic::manhattan)
Definition: AStar.hpp:123
void setHeuristic(const HeuristicFunction &heuristic_)
Definition: AStar.hpp:137
MapCoords worldSize
Definition: AStar.hpp:216
CoordinateList findPath(MapCoords source_, MapCoords target_)
Definition: AStar.hpp:139
uint32_t directions
Definition: AStar.hpp:217
static std::shared_ptr< Node > findNodeOnList(NodeSet &nodes_, MapCoords coordinates_)
Definition: AStar.hpp:100
void setWorldSize(MapCoords worldSize_)
Definition: AStar.hpp:131
HeuristicFunction heuristic
Definition: AStar.hpp:210
Definition: AStar.hpp:51
static uint32_t manhattan(MapCoords source_, MapCoords target_)
Definition: AStar.hpp:55
static uint32_t octagonal(MapCoords source_, MapCoords target_)
Definition: AStar.hpp:67
static MapCoords getDelta(MapCoords source_, MapCoords target_)
Definition: AStar.hpp:52
static uint32_t euclidean(MapCoords source_, MapCoords target_)
Definition: AStar.hpp:61
std::function< uint32_t(MapCoords, MapCoords)> HeuristicFunction
Definition: AStar.hpp:74
std::vector< std::shared_ptr< Node > > NodeSet
Definition: AStar.hpp:96
std::vector< MapCoords > CoordinateList
We use a vector because the AStar algorithm is only searching on small datasets. Other data structure...
Definition: AStar.hpp:77
std::function< bool(uint16_t x, uint16_t y)> CollisionDetectionFunction
Definition: AStar.hpp:78
Definition: Element.hpp:7
Definition: AStar.hpp:81
uint32_t G
Definition: AStar.hpp:82
MapCoords coordinates
Definition: AStar.hpp:83
Node(MapCoords coord_, std::shared_ptr< Node > parent_=nullptr)
Definition: AStar.hpp:86
uint32_t H
Definition: AStar.hpp:82
std::shared_ptr< Node > parent
Definition: AStar.hpp:84
uint32_t getFScore() const
Definition: AStar.hpp:93