OpenTTD Source 20260621-master-g720d10536d
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 <https://www.gnu.org/licenses/old-licenses/gpl-2.0>.
6 */
7
9
10#ifndef YAPF_BASE_HPP
11#define YAPF_BASE_HPP
12
13#include "../../debug.h"
14#include "../../settings_type.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
65 using PfFollowNodeFunc = void(Node &old_node);
66
75 using PfCalcCostFunc = bool(Node &n, const TrackFollower *follower);
76
83 using PfCalcEstimateFunc = bool(Node &n);
84
90 using PfDetectDestinationFunc = bool(Node &n);
91
99
104 using TransportTypeCharFunc = char();
105
106protected:
107 Node *best_dest_node = nullptr;
111 const VehicleType *vehicle = nullptr;
112
115
116public:
117 int num_steps = 0;
118
119public:
122
125
126protected:
131 inline Tpf &Yapf()
132 {
133 return *static_cast<Tpf *>(this);
134 }
135
136public:
141 inline const YAPFSettings &PfGetSettings() const
142 {
143 return *this->settings;
144 }
145
156 inline bool FindPath(const VehicleType *v)
157 {
158 this->vehicle = v;
159
160 for (;;) {
161 this->num_steps++;
162 Node *best_open_node = this->nodes.GetBestOpenNode();
163 if (best_open_node == nullptr) break;
164
165 if (Yapf().PfDetectDestination(*best_open_node)) {
166 this->best_dest_node = best_open_node;
167 break;
168 }
169
170 Yapf().PfFollowNode(*best_open_node);
171 if (this->max_search_nodes != 0 && this->nodes.ClosedCount() >= this->max_search_nodes) break;
172
173 this->nodes.PopOpenNode(best_open_node->GetKey());
174 this->nodes.InsertClosedNode(*best_open_node);
175 }
176
177 const bool destination_found = (this->best_dest_node != nullptr);
178
179 if (_debug_yapf_level >= 3) {
180 const UnitID veh_idx = (this->vehicle != nullptr) ? this->vehicle->unitnumber : 0;
181 const char ttc = Yapf().TransportTypeChar();
182 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);
183 const int cost = destination_found ? this->best_dest_node->cost : -1;
184 const int dist = destination_found ? this->best_dest_node->estimate - this->best_dest_node->cost : -1;
185
186 Debug(yapf, 3, "[YAPF{}]{}{:4d} - {} rounds - {} open - {} closed - CHR {:4.1f}% - C {} D {}",
187 ttc, destination_found ? '-' : '!', veh_idx, this->num_steps, this->nodes.OpenCount(), this->nodes.ClosedCount(), cache_hit_ratio, cost, dist
188 );
189 }
190
191 return destination_found;
192 }
193
200 {
201 return (this->best_dest_node != nullptr) ? this->best_dest_node : this->best_intermediate_node;
202 }
203
210 {
211 Node &node = this->nodes.CreateNewNode();
212 return node;
213 }
214
219 inline void AddStartupNode(Node &n)
220 {
221 assert(n.parent == nullptr);
222 assert(this->num_steps == 0);
223
224 Yapf().PfNodeCacheFetch(n);
225 /* insert the new node only if it is not there */
226 if (this->nodes.FindOpenNode(n.key) == nullptr) {
227 this->nodes.InsertOpenNode(n);
228 }
229 }
230
236 inline void AddMultipleNodes(Node *parent, const TrackFollower &tf)
237 {
238 bool is_choice = tf.new_td_bits.Count() > 1;
239 for (Trackdir td : tf.new_td_bits) {
240 Node &n = Yapf().CreateNewNode();
241 n.Set(parent, tf.new_tile, td, is_choice);
242 Yapf().AddNewNode(n, tf);
243 }
244 }
245
252 void AddNewNode(Node &n, const TrackFollower &follower)
253 {
254 assert(n.parent != nullptr);
255
256 /* evaluate the node */
257 bool cached = Yapf().PfNodeCacheFetch(n);
258 if (!cached) {
259 this->stats_cost_calcs++;
260 } else {
261 this->stats_cache_hits++;
262 }
263
264 bool valid = Yapf().PfCalcCost(n, &follower);
265
266 if (valid) valid = Yapf().PfCalcEstimate(n);
267
268 /* have the cost or estimate callbacks marked this node as invalid? */
269 if (!valid) return;
270
271 /* The new node can be set as the best intermediate node only once we're
272 * certain it will be finalized by being inserted into the open list. */
273 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()));
274
275 /* check new node against open list */
276 Node *open_node = this->nodes.FindOpenNode(n.GetKey());
277 if (open_node != nullptr) {
278 /* another node exists with the same key in the open list
279 * is it better than new one? */
280 if (n.GetCostEstimate() < open_node->GetCostEstimate()) {
281 /* update the old node by value from new one */
282 this->nodes.PopOpenNode(n.GetKey());
283 *open_node = n;
284 /* add the updated old node back to open list */
285 this->nodes.InsertOpenNode(*open_node);
286 if (set_intermediate) this->best_intermediate_node = open_node;
287 }
288 return;
289 }
290
291 /* check new node against closed list */
292 Node *closed_node = this->nodes.FindClosedNode(n.GetKey());
293 if (closed_node != nullptr) {
294 /* another node exists with the same key in the closed list
295 * is it better than new one? */
296 int node_est = n.GetCostEstimate();
297 int closed_est = closed_node->GetCostEstimate();
298 if (node_est < closed_est) {
299 /* If this assert occurs, you have probably problem in
300 * your Tderived::PfCalcCost() or Tderived::PfCalcEstimate().
301 * The problem could be:
302 * - PfCalcEstimate() gives too large numbers
303 * - PfCalcCost() gives too small numbers
304 * - You have used negative cost penalty in some cases (cost bonus) */
305 NOT_REACHED();
306 }
307 return;
308 }
309 /* the new node is really new
310 * add it to the open list */
311 this->nodes.InsertOpenNode(n);
312 if (set_intermediate) this->best_intermediate_node = &n;
313 }
314
315 const VehicleType * GetVehicle() const
316 {
317 return this->vehicle;
318 }
319
320 void DumpBase(DumpTarget &dmp) const
321 {
322 dmp.WriteStructT("nodes", &this->nodes);
323 dmp.WriteValue("num_steps", this->num_steps);
324 }
325};
326
327#endif /* YAPF_BASE_HPP */
int num_steps
this is there for debugging purposes (hope it doesn't hurt)
void(Node &old_node) PfFollowNodeFunc
Called by YAPF to move from the given node to the next tile.
Definition yapf_base.hpp:65
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
const VehicleType * vehicle
vehicle that we are trying to drive
Node * best_intermediate_node
here should be node closest to the destination if path not found
char() TransportTypeCharFunc
Return debug report character to identify the transportation type.
const YAPFSettings * settings
current settings (_settings_game.yapf)
int stats_cache_hits
stats - how many node's costs were reused from cache
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
int max_search_nodes
maximum number of nodes we are allowed to visit before we give up
bool(TileIndex tile, Trackdir td) PfDetectDestinationTileFunc
Called by YAPF to detect if node ends in the desired destination.
Definition yapf_base.hpp:98
bool(Node &n) PfDetectDestinationFunc
Called by YAPF to detect if node ends in the desired destination.
Definition yapf_base.hpp:90
bool(Node &n, const TrackFollower *follower) PfCalcCostFunc
Called by YAPF to calculate the cost from the origin to the given node.
Definition yapf_base.hpp:75
Node * GetBestNode()
If path was found return the best node that has reached the destination.
~CYapfBaseT()
default destructor
bool FindPath(const VehicleType *v)
Main pathfinder routine:
bool(Node &n) PfCalcEstimateFunc
Called by YAPF to calculate cost estimate.
Definition yapf_base.hpp:83
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).
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
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()
Access the inherited path finder.
void InsertClosedNode(Titem &item)
Insert the given item into the closed nodes set.
Definition nodelist.hpp:157
Titem * FindClosedNode(const Key &key)
Find a closed node by its key.
Definition nodelist.hpp:168
void InsertOpenNode(Titem &item)
Insert given item as open node (into open_nodes and open_queue).
Definition nodelist.hpp:94
int OpenCount()
Get open node count.
Definition nodelist.hpp:44
int ClosedCount()
Get closed node count.
Definition nodelist.hpp:53
Titem & CreateNewNode()
Allocate new data item from items.
Definition nodelist.hpp:71
Titem * GetBestOpenNode()
Get the open node at the begin of the open queue.
Definition nodelist.hpp:108
Titem & PopOpenNode(const Key &key)
Find and remove an open node by key.
Definition nodelist.hpp:145
Titem * FindOpenNode(const Key &key)
Find an open node by key.
Definition nodelist.hpp:135
Functions to be used for debug printings.
Functions related to debugging.
#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
Types related to global configuration settings.
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.
StrongType::Typedef< uint32_t, struct TileIndexTag, StrongType::Compare, StrongType::Integer, StrongType::Compatible< int32_t >, StrongType::Compatible< int64_t > > TileIndex
The index/ID of a Tile.
Definition tile_type.h:92
Trackdir
Enumeration for tracks and directions.
Definition track_type.h:63
uint16_t UnitID
Type for the company global vehicle unit number.
VehicleType
Available vehicle types.
Types used by YAPF.