OpenTTD Source 20251019-master-g9f7f314f81
yapf_base.hpp
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
10#ifndef YAPF_BASE_HPP
11#define YAPF_BASE_HPP
12
13#include "../../debug.h"
14#include "../../settings_type.h"
15#include "../../misc/dbg_helpers.h"
16#include "yapf_type.hpp"
17
47template <class Types>
49public:
50 typedef typename Types::Tpf Tpf;
51 typedef typename Types::TrackFollower TrackFollower;
52 typedef typename Types::NodeList NodeList;
53 typedef typename Types::VehicleType VehicleType;
54 typedef typename NodeList::Item Node;
55 typedef typename Node::Key Key;
56
58
59protected:
60 Node *best_dest_node = nullptr;
64 const VehicleType *vehicle = nullptr;
65
68
69public:
70 int num_steps = 0;
71
72public:
75
78
79protected:
81 inline Tpf &Yapf()
82 {
83 return *static_cast<Tpf *>(this);
84 }
85
86public:
88 inline const YAPFSettings &PfGetSettings() const
89 {
90 return *this->settings;
91 }
92
102 inline bool FindPath(const VehicleType *v)
103 {
104 this->vehicle = v;
105
106 for (;;) {
107 this->num_steps++;
108 Node *best_open_node = this->nodes.GetBestOpenNode();
109 if (best_open_node == nullptr) break;
110
111 if (Yapf().PfDetectDestination(*best_open_node)) {
112 this->best_dest_node = best_open_node;
113 break;
114 }
115
116 Yapf().PfFollowNode(*best_open_node);
117 if (this->max_search_nodes != 0 && this->nodes.ClosedCount() >= this->max_search_nodes) break;
118
119 this->nodes.PopOpenNode(best_open_node->GetKey());
120 this->nodes.InsertClosedNode(*best_open_node);
121 }
122
123 const bool destination_found = (this->best_dest_node != nullptr);
124
125 if (_debug_yapf_level >= 3) {
126 const UnitID veh_idx = (this->vehicle != nullptr) ? this->vehicle->unitnumber : 0;
127 const char ttc = Yapf().TransportTypeChar();
128 const float cache_hit_ratio = (this->stats_cache_hits == 0) ? 0.0f : ((float)this->stats_cache_hits / (float)(this->stats_cache_hits + this->stats_cost_calcs) * 100.0f);
129 const int cost = destination_found ? this->best_dest_node->cost : -1;
130 const int dist = destination_found ? this->best_dest_node->estimate - this->best_dest_node->cost : -1;
131
132 Debug(yapf, 3, "[YAPF{}]{}{:4d} - {} rounds - {} open - {} closed - CHR {:4.1f}% - C {} D {}",
133 ttc, destination_found ? '-' : '!', veh_idx, this->num_steps, this->nodes.OpenCount(), this->nodes.ClosedCount(), cache_hit_ratio, cost, dist
134 );
135 }
136
137 return destination_found;
138 }
139
145 {
146 return (this->best_dest_node != nullptr) ? this->best_dest_node : this->best_intermediate_node;
147 }
148
153 inline Node &CreateNewNode()
154 {
155 Node &node = this->nodes.CreateNewNode();
156 return node;
157 }
158
160 inline void AddStartupNode(Node &n)
161 {
162 assert(n.parent == nullptr);
163 assert(this->num_steps == 0);
164
165 Yapf().PfNodeCacheFetch(n);
166 /* insert the new node only if it is not there */
167 if (this->nodes.FindOpenNode(n.key) == nullptr) {
168 this->nodes.InsertOpenNode(n);
169 }
170 }
171
173 inline void AddMultipleNodes(Node *parent, const TrackFollower &tf)
174 {
175 bool is_choice = (KillFirstBit(tf.new_td_bits) != TRACKDIR_BIT_NONE);
176 for (TrackdirBits rtds = tf.new_td_bits; rtds != TRACKDIR_BIT_NONE; rtds = KillFirstBit(rtds)) {
177 Trackdir td = (Trackdir)FindFirstBit(rtds);
178 Node &n = Yapf().CreateNewNode();
179 n.Set(parent, tf.new_tile, td, is_choice);
180 Yapf().AddNewNode(n, tf);
181 }
182 }
183
188 void AddNewNode(Node &n, const TrackFollower &follower)
189 {
190 assert(n.parent != nullptr);
191
192 /* evaluate the node */
193 bool cached = Yapf().PfNodeCacheFetch(n);
194 if (!cached) {
195 this->stats_cost_calcs++;
196 } else {
197 this->stats_cache_hits++;
198 }
199
200 bool valid = Yapf().PfCalcCost(n, &follower);
201
202 if (valid) valid = Yapf().PfCalcEstimate(n);
203
204 /* have the cost or estimate callbacks marked this node as invalid? */
205 if (!valid) return;
206
207 /* The new node can be set as the best intermediate node only once we're
208 * certain it will be finalized by being inserted into the open list. */
209 bool set_intermediate = this->max_search_nodes > 0 && (this->best_intermediate_node == nullptr || (this->best_intermediate_node->GetCostEstimate() - this->best_intermediate_node->GetCost()) > (n.GetCostEstimate() - n.GetCost()));
210
211 /* check new node against open list */
212 Node *open_node = this->nodes.FindOpenNode(n.GetKey());
213 if (open_node != nullptr) {
214 /* another node exists with the same key in the open list
215 * is it better than new one? */
216 if (n.GetCostEstimate() < open_node->GetCostEstimate()) {
217 /* update the old node by value from new one */
218 this->nodes.PopOpenNode(n.GetKey());
219 *open_node = n;
220 /* add the updated old node back to open list */
221 this->nodes.InsertOpenNode(*open_node);
222 if (set_intermediate) this->best_intermediate_node = open_node;
223 }
224 return;
225 }
226
227 /* check new node against closed list */
228 Node *closed_node = this->nodes.FindClosedNode(n.GetKey());
229 if (closed_node != nullptr) {
230 /* another node exists with the same key in the closed list
231 * is it better than new one? */
232 int node_est = n.GetCostEstimate();
233 int closed_est = closed_node->GetCostEstimate();
234 if (node_est < closed_est) {
235 /* If this assert occurs, you have probably problem in
236 * your Tderived::PfCalcCost() or Tderived::PfCalcEstimate().
237 * The problem could be:
238 * - PfCalcEstimate() gives too large numbers
239 * - PfCalcCost() gives too small numbers
240 * - You have used negative cost penalty in some cases (cost bonus) */
241 NOT_REACHED();
242 }
243 return;
244 }
245 /* the new node is really new
246 * add it to the open list */
247 this->nodes.InsertOpenNode(n);
248 if (set_intermediate) this->best_intermediate_node = &n;
249 }
250
251 const VehicleType * GetVehicle() const
252 {
253 return this->vehicle;
254 }
255
256 void DumpBase(DumpTarget &dmp) const
257 {
258 dmp.WriteStructT("nodes", &this->nodes);
259 dmp.WriteValue("num_steps", this->num_steps);
260 }
261};
262
263#endif /* YAPF_BASE_HPP */
constexpr uint8_t FindFirstBit(T x)
Search the first set bit in a value.
constexpr T KillFirstBit(T value)
Clear the first bit in an integer.
CYapfBaseT - A-star type path finder base class.
Definition yapf_base.hpp:48
int num_steps
this is there for debugging purposes (hope it doesn't hurt)
Definition yapf_base.hpp:70
Node::Key Key
key to hash tables
Definition yapf_base.hpp:55
void AddNewNode(Node &n, const TrackFollower &follower)
AddNewNode() - called by Tderived::PfFollowNode() for each child node.
CYapfBaseT()
default constructor
Definition yapf_base.hpp:74
const VehicleType * vehicle
vehicle that we are trying to drive
Definition yapf_base.hpp:64
Node * best_intermediate_node
here should be node closest to the destination if path not found
Definition yapf_base.hpp:61
const YAPFSettings * settings
current settings (_settings_game.yapf)
Definition yapf_base.hpp:62
int stats_cache_hits
stats - how many node's costs were reused from cache
Definition yapf_base.hpp:67
void AddMultipleNodes(Node *parent, const TrackFollower &tf)
add multiple nodes - direct children of the given node
int stats_cost_calcs
stats - how many node's costs were calculated
Definition yapf_base.hpp:66
int max_search_nodes
maximum number of nodes we are allowed to visit before we give up
Definition yapf_base.hpp:63
Node * GetBestNode()
If path was found return the best node that has reached the destination.
~CYapfBaseT()
default destructor
Definition yapf_base.hpp:77
bool FindPath(const VehicleType *v)
Main pathfinder routine:
Node & CreateNewNode()
Calls NodeList::CreateNewNode() - allocates new node that can be filled and used as argument for AddS...
NodeList nodes
node list multi-container
Definition yapf_base.hpp:57
Types::Tpf Tpf
the pathfinder class (derived from THIS class)
Definition yapf_base.hpp:50
const YAPFSettings & PfGetSettings() const
return current settings (can be custom - company based - but later)
Definition yapf_base.hpp:88
Types::VehicleType VehicleType
the type of vehicle
Definition yapf_base.hpp:53
void AddStartupNode(Node &n)
Add new node (created by CreateNewNode and filled with data) into open list.
Node * best_dest_node
pointer to the destination node found at last round
Definition yapf_base.hpp:60
NodeList::Item Node
this will be our node type
Definition yapf_base.hpp:54
Types::NodeList NodeList
our node list
Definition yapf_base.hpp:52
Tpf & Yapf()
to access inherited path finder
Definition yapf_base.hpp:81
Hash table based node list multi-container class.
Definition nodelist.hpp:21
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
int OpenCount()
return number of open nodes
Definition nodelist.hpp:41
int ClosedCount()
return number of closed nodes
Definition nodelist.hpp:47
Titem & CreateNewNode()
allocate new data item from items
Definition nodelist.hpp:59
Titem * GetBestOpenNode()
return the best open node
Definition nodelist.hpp:87
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
GameSettings _settings_game
Game settings of a running game or the scenario editor.
Definition settings.cpp:61
Class that represents the dump-into-string target.
void WriteStructT(std::string_view name, const S *s)
Dump nested object (or only its name if this instance is already known).
void WriteValue(std::string_view name, const auto &value)
Write 'name = value' with indent and new-line.
Settings related to the yet another pathfinder.
Trackdir
Enumeration for tracks and directions.
Definition track_type.h:66
TrackdirBits
Allow incrementing of Trackdir variables.
Definition track_type.h:97
@ TRACKDIR_BIT_NONE
No track build.
Definition track_type.h:98
uint16_t UnitID
Type for the company global vehicle unit number.
VehicleType
Available vehicle types.
Types used by YAPF.