OpenTTD Source 20250524-master-gc366e6a48e
aystar.cpp
Go to the documentation of this file.
1/*
2 * This file is part of OpenTTD.
3 * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
4 * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
5 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
6 */
7
16#include "../../stdafx.h"
17#include "aystar.h"
18
19#include "../../safeguards.h"
20
25void AyStar::OpenListAdd(PathNode *parent, const AyStarNode *node, int f, int g)
26{
27 /* Add a new Node to the OpenList */
28 PathNode &new_node = this->nodes.CreateNewNode();
29 new_node.Set(parent, node->tile, node->td, true);
30 new_node.estimate = f;
31 new_node.cost = g;
32 this->nodes.InsertOpenNode(new_node);
33}
34
38void AyStar::CheckTile(AyStarNode *current, PathNode *parent)
39{
40 /* Check the new node against the ClosedList */
41 if (this->nodes.FindClosedNode(*current) != nullptr) return;
42
43 /* Calculate the G-value for this node */
44 int new_g = this->CalculateG(*current, *parent);
45 /* If the value was INVALID_NODE, we don't do anything with this node */
46 if (new_g == AYSTAR_INVALID_NODE) return;
47
48 /* There should not be given any other error-code.. */
49 assert(new_g >= 0);
50 /* Add the parent g-value to the new g-value */
51 new_g += parent->cost;
52
53 /* Calculate the h-value */
54 int new_h = this->CalculateH(*current, *parent);
55 /* There should not be given any error-code.. */
56 assert(new_h >= 0);
57
58 /* The f-value if g + h */
59 int new_f = new_g + new_h;
60
61 /* Get the pointer to the parent in the ClosedList (the current one is to a copy of the one in the OpenList) */
62 PathNode *closedlist_parent = this->nodes.FindClosedNode(parent->key);
63
64 /* Check if this item is already in the OpenList */
65 PathNode *check = this->nodes.FindOpenNode(*current);
66 if (check != nullptr) {
67 /* Yes, check if this g value is lower.. */
68 if (new_g > check->cost) return;
69 this->nodes.PopOpenNode(check->key);
70 /* It is lower, so change it to this item */
71 check->estimate = new_f;
72 check->cost = new_g;
73 check->parent = closedlist_parent;
74 /* Re-add it in the openlist_queue. */
75 this->nodes.InsertOpenNode(*check);
76 } else {
77 /* A new node, add it to the OpenList */
78 this->OpenListAdd(closedlist_parent, current, new_f, new_g);
79 }
80}
81
92{
93 /* Get the best node from OpenList */
94 PathNode *current = this->nodes.PopBestOpenNode();
95 /* If empty, drop an error */
96 if (current == nullptr) return AyStarStatus::EmptyOpenList;
97
98 /* Check for end node and if found, return that code */
99 if (this->EndNodeCheck(*current) == AyStarStatus::FoundEndNode && current->parent != nullptr) {
100 this->FoundEndNode(*current);
102 }
103
104 /* Add the node to the ClosedList */
105 this->nodes.InsertClosedNode(*current);
106
107 /* Load the neighbours */
108 this->GetNeighbours(*current, this->neighbours);
109
110 /* Go through all neighbours */
111 for (auto &neighbour : this->neighbours) {
112 /* Check and add them to the OpenList if needed */
113 this->CheckTile(&neighbour, current);
114 }
115
116 if (this->nodes.ClosedCount() >= AYSTAR_DEF_MAX_SEARCH_NODES) {
117 /* We've expanded enough nodes */
119 } else {
120 /* Return that we are still busy */
122 }
123}
124
133{
134 AyStarStatus r;
135 do {
136 r = this->Loop();
137 } while (r == AyStarStatus::StillBusy);
138#ifdef AYSTAR_DEBUG
139 switch (r) {
140 case AyStarStatus::FoundEndNode: Debug(misc, 0, "[AyStar] Found path!"); break;
141 case AyStarStatus::EmptyOpenList: Debug(misc, 0, "[AyStar] OpenList run dry, no path found"); break;
142 case AyStarStatus::LimitReached: Debug(misc, 0, "[AyStar] Exceeded search_nodes, no path found"); break;
143 default: break;
144 }
145#endif
146
147 switch (r) {
151 default: return AyStarStatus::StillBusy;
152 }
153}
154
161void AyStar::AddStartNode(AyStarNode *start_node, int g)
162{
163#ifdef AYSTAR_DEBUG
164 Debug(misc, 0, "[AyStar] Starting A* Algorithm from node ({}, {}, {})\n",
165 TileX(start_node->tile), TileY(start_node->tile), start_node->direction);
166#endif
167 this->OpenListAdd(nullptr, start_node, 0, g);
168}
This file has the header for AyStar.
AyStarStatus
Return status of AyStar methods.
Definition aystar.h:25
@ EmptyOpenList
All items are tested, and no path has been found.
@ StillBusy
Some checking was done, but no path found yet, and there are still items left to try.
@ LimitReached
The AYSTAR_DEF_MAX_SEARCH_NODES limit has been reached, aborting search.
@ NoPath
No path to the goal was found.
@ FoundEndNode
An end node was found.
static const int AYSTAR_INVALID_NODE
Item is not valid (for example, not walkable).
Definition aystar.h:34
static const int AYSTAR_DEF_MAX_SEARCH_NODES
Reference limit for #AyStar::max_search_nodes.
Definition aystar.h:22
void OpenListAdd(PathNode *parent, const AyStarNode *node, int f, int g)
Adds a node to the open list.
Definition aystar.cpp:25
virtual AyStarStatus EndNodeCheck(const PathNode &current) const =0
Check whether the end-tile is found.
virtual void GetNeighbours(const PathNode &current, std::vector< AyStarNode > &neighours) const =0
This function requests the tiles around the current tile.
AyStarStatus Loop()
This function is the core of AyStar.
Definition aystar.cpp:91
AyStarStatus Main()
This is the function you call to run AyStar.
Definition aystar.cpp:132
virtual int32_t CalculateH(const AyStarNode &current, const PathNode &parent) const =0
Calculate the H-value for the AyStar algorithm.
void CheckTile(AyStarNode *current, PathNode *parent)
Checks one tile and calculate its f-value.
Definition aystar.cpp:38
void AddStartNode(AyStarNode *start_node, int g)
Adds a node from where to start an algorithm.
Definition aystar.cpp:161
virtual int32_t CalculateG(const AyStarNode &current, const PathNode &parent) const =0
Calculate the G-value for the AyStar algorithm.
void InsertClosedNode(Titem &item)
close node
Definition nodelist.hpp:122
Titem * FindClosedNode(const Key &key)
return the closed node specified by a key or nullptr if not found
Definition nodelist.hpp:129
void InsertOpenNode(Titem &item)
insert given item as open node (into open_nodes and open_queue)
Definition nodelist.hpp:76
Titem * PopBestOpenNode()
remove and return the best open node
Definition nodelist.hpp:96
int ClosedCount()
return number of closed nodes
Definition nodelist.hpp:47
Titem & CreateNewNode()
allocate new data item from items
Definition nodelist.hpp:59
Titem & PopOpenNode(const Key &key)
remove and return the open node specified by a key
Definition nodelist.hpp:113
Titem * FindOpenNode(const Key &key)
return the open node specified by a key or nullptr if not found
Definition nodelist.hpp:107
#define Debug(category, level, format_string,...)
Output a line of debugging information.
Definition debug.h:37
static debug_inline uint TileY(TileIndex tile)
Get the Y component of a tile.
Definition map_func.h:424
static debug_inline uint TileX(TileIndex tile)
Get the X component of a tile.
Definition map_func.h:414