Codechange: allow mapping enums as parameter and return type from scripts
[openttd-github.git] / src / pathfinder / yapf / yapf_ship_regions.cpp
blob36a939ea74c41b1f4d893e93446515505ca3f585
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 */
8 /** @file yapf_ship_regions.cpp Implementation of YAPF for water regions, which are used for finding intermediate ship destinations. */
10 #include "../../stdafx.h"
11 #include "../../ship.h"
13 #include "yapf.hpp"
14 #include "yapf_ship_regions.h"
15 #include "../water_regions.h"
17 #include "../../safeguards.h"
19 constexpr int DIRECT_NEIGHBOR_COST = 100;
20 constexpr int NODES_PER_REGION = 4;
21 constexpr int MAX_NUMBER_OF_NODES = 65536;
23 /** Yapf Node Key that represents a single patch of interconnected water within a water region. */
24 struct CYapfRegionPatchNodeKey {
25 WaterRegionPatchDesc water_region_patch;
27 inline void Set(const WaterRegionPatchDesc &water_region_patch)
29 this->water_region_patch = water_region_patch;
32 inline int CalcHash() const { return CalculateWaterRegionPatchHash(this->water_region_patch); }
33 inline bool operator==(const CYapfRegionPatchNodeKey &other) const { return this->CalcHash() == other.CalcHash(); }
36 inline uint ManhattanDistance(const CYapfRegionPatchNodeKey &a, const CYapfRegionPatchNodeKey &b)
38 return (std::abs(a.water_region_patch.x - b.water_region_patch.x) + std::abs(a.water_region_patch.y - b.water_region_patch.y)) * DIRECT_NEIGHBOR_COST;
41 /** Yapf Node for water regions. */
42 template <class Tkey_>
43 struct CYapfRegionNodeT : CYapfNodeT<Tkey_, CYapfRegionNodeT<Tkey_> > {
44 typedef Tkey_ Key;
45 typedef CYapfRegionNodeT<Tkey_> Node;
47 inline void Set(Node *parent, const WaterRegionPatchDesc &water_region_patch)
49 this->key.Set(water_region_patch);
50 this->hash_next = nullptr;
51 this->parent = parent;
52 this->cost = 0;
53 this->estimate = 0;
56 inline void Set(Node *parent, const Key &key)
58 this->Set(parent, key.water_region_patch);
61 DiagDirection GetDiagDirFromParent() const
63 if (this->parent == nullptr) return INVALID_DIAGDIR;
64 const int dx = this->key.water_region_patch.x - this->parent->key.water_region_patch.x;
65 const int dy = this->key.water_region_patch.y - this->parent->key.water_region_patch.y;
66 if (dx > 0 && dy == 0) return DIAGDIR_SW;
67 if (dx < 0 && dy == 0) return DIAGDIR_NE;
68 if (dx == 0 && dy > 0) return DIAGDIR_SE;
69 if (dx == 0 && dy < 0) return DIAGDIR_NW;
70 return INVALID_DIAGDIR;
74 /** YAPF origin for water regions. */
75 template <class Types>
76 class CYapfOriginRegionT
78 public:
79 typedef typename Types::Tpf Tpf; ///< The pathfinder class (derived from THIS class).
80 typedef typename Types::NodeList::Item Node; ///< This will be our node type.
81 typedef typename Node::Key Key; ///< Key to hash tables.
83 protected:
84 inline Tpf &Yapf() { return *static_cast<Tpf*>(this); }
86 private:
87 std::vector<CYapfRegionPatchNodeKey> origin_keys;
89 public:
90 void AddOrigin(const WaterRegionPatchDesc &water_region_patch)
92 if (water_region_patch.label == INVALID_WATER_REGION_PATCH) return;
93 if (!HasOrigin(water_region_patch)) this->origin_keys.push_back(CYapfRegionPatchNodeKey{ water_region_patch });
96 bool HasOrigin(const WaterRegionPatchDesc &water_region_patch)
98 return std::ranges::find(this->origin_keys, CYapfRegionPatchNodeKey{ water_region_patch }) != this->origin_keys.end();
101 void PfSetStartupNodes()
103 for (const CYapfRegionPatchNodeKey &origin_key : this->origin_keys) {
104 Node &node = Yapf().CreateNewNode();
105 node.Set(nullptr, origin_key);
106 Yapf().AddStartupNode(node);
111 /** YAPF destination provider for water regions. */
112 template <class Types>
113 class CYapfDestinationRegionT
115 public:
116 typedef typename Types::Tpf Tpf; ///< The pathfinder class (derived from THIS class).
117 typedef typename Types::NodeList::Item Node; ///< This will be our node type.
118 typedef typename Node::Key Key; ///< Key to hash tables.
120 protected:
121 Key dest;
123 public:
124 void SetDestination(const WaterRegionPatchDesc &water_region_patch)
126 this->dest.Set(water_region_patch);
129 protected:
130 Tpf &Yapf() { return *static_cast<Tpf*>(this); }
132 public:
133 inline bool PfDetectDestination(Node &n) const
135 return n.key == this->dest;
138 inline bool PfCalcEstimate(Node &n)
140 if (this->PfDetectDestination(n)) {
141 n.estimate = n.cost;
142 return true;
145 n.estimate = n.cost + ManhattanDistance(n.key, this->dest);
147 return true;
151 /** YAPF node following for water region pathfinding. */
152 template <class Types>
153 class CYapfFollowRegionT
155 public:
156 typedef typename Types::Tpf Tpf; ///< The pathfinder class (derived from THIS class).
157 typedef typename Types::TrackFollower TrackFollower;
158 typedef typename Types::NodeList::Item Node; ///< This will be our node type.
159 typedef typename Node::Key Key; ///< Key to hash tables.
161 protected:
162 inline Tpf &Yapf() { return *static_cast<Tpf*>(this); }
164 public:
165 inline void PfFollowNode(Node &old_node)
167 TVisitWaterRegionPatchCallBack visitFunc = [&](const WaterRegionPatchDesc &water_region_patch)
169 Node &node = Yapf().CreateNewNode();
170 node.Set(&old_node, water_region_patch);
171 Yapf().AddNewNode(node, TrackFollower{});
173 VisitWaterRegionPatchNeighbors(old_node.key.water_region_patch, visitFunc);
176 inline char TransportTypeChar() const { return '^'; }
178 static std::vector<WaterRegionPatchDesc> FindWaterRegionPath(const Ship *v, TileIndex start_tile, int max_returned_path_length)
180 const WaterRegionPatchDesc start_water_region_patch = GetWaterRegionPatchInfo(start_tile);
182 /* We reserve 4 nodes (patches) per water region. The vast majority of water regions have 1 or 2 regions so this should be a pretty
183 * safe limit. We cap the limit at 65536 which is at a region size of 16x16 is equivalent to one node per region for a 4096x4096 map. */
184 Tpf pf(std::min(static_cast<int>(Map::Size() * NODES_PER_REGION) / WATER_REGION_NUMBER_OF_TILES, MAX_NUMBER_OF_NODES));
185 pf.SetDestination(start_water_region_patch);
187 if (v->current_order.IsType(OT_GOTO_STATION)) {
188 DestinationID station_id = v->current_order.GetDestination();
189 const BaseStation *station = BaseStation::Get(station_id);
190 TileArea tile_area;
191 station->GetTileArea(&tile_area, StationType::Dock);
192 for (const auto &tile : tile_area) {
193 if (IsDockingTile(tile) && IsShipDestinationTile(tile, station_id)) {
194 pf.AddOrigin(GetWaterRegionPatchInfo(tile));
197 } else {
198 TileIndex tile = v->dest_tile;
199 pf.AddOrigin(GetWaterRegionPatchInfo(tile));
202 /* If origin and destination are the same we simply return that water patch. */
203 std::vector<WaterRegionPatchDesc> path = { start_water_region_patch };
204 path.reserve(max_returned_path_length);
205 if (pf.HasOrigin(start_water_region_patch)) return path;
207 /* Find best path. */
208 if (!pf.FindPath(v)) return {}; // Path not found.
210 Node *node = pf.GetBestNode();
211 for (int i = 0; i < max_returned_path_length - 1; ++i) {
212 if (node != nullptr) {
213 node = node->parent;
214 if (node != nullptr) path.push_back(node->key.water_region_patch);
218 assert(!path.empty());
219 return path;
223 /** Cost Provider of YAPF for water regions. */
224 template <class Types>
225 class CYapfCostRegionT
227 public:
228 typedef typename Types::Tpf Tpf; ///< The pathfinder class (derived from THIS class).
229 typedef typename Types::TrackFollower TrackFollower;
230 typedef typename Types::NodeList::Item Node; ///< This will be our node type.
231 typedef typename Node::Key Key; ///< Key to hash tables.
233 protected:
234 /** To access inherited path finder. */
235 Tpf &Yapf() { return *static_cast<Tpf*>(this); }
237 public:
239 * Called by YAPF to calculate the cost from the origin to the given node.
240 * Calculates only the cost of given node, adds it to the parent node cost
241 * and stores the result into Node::cost member.
243 inline bool PfCalcCost(Node &n, const TrackFollower *)
245 n.cost = n.parent->cost + ManhattanDistance(n.key, n.parent->key);
247 /* Incentivise zigzagging by adding a slight penalty when the search continues in the same direction. */
248 Node *grandparent = n.parent->parent;
249 if (grandparent != nullptr) {
250 const DiagDirDiff dir_diff = DiagDirDifference(n.parent->GetDiagDirFromParent(), n.GetDiagDirFromParent());
251 if (dir_diff != DIAGDIRDIFF_90LEFT && dir_diff != DIAGDIRDIFF_90RIGHT) n.cost += 1;
254 return true;
258 /* We don't need a follower but YAPF requires one. */
259 struct DummyFollower : public CFollowTrackWater {};
262 * Config struct of YAPF for route planning.
263 * Defines all 6 base YAPF modules as classes providing services for CYapfBaseT.
265 template <class Tpf_, class Tnode_list>
266 struct CYapfRegion_TypesT
268 typedef CYapfRegion_TypesT<Tpf_, Tnode_list> Types; ///< Shortcut for this struct type.
269 typedef Tpf_ Tpf; ///< Pathfinder type.
270 typedef DummyFollower TrackFollower; ///< Track follower helper class
271 typedef Tnode_list NodeList;
272 typedef Ship VehicleType;
274 /** Pathfinder components (modules). */
275 typedef CYapfBaseT<Types> PfBase; ///< Base pathfinder class.
276 typedef CYapfFollowRegionT<Types> PfFollow; ///< Node follower.
277 typedef CYapfOriginRegionT<Types> PfOrigin; ///< Origin provider.
278 typedef CYapfDestinationRegionT<Types> PfDestination; ///< Destination/distance provider.
279 typedef CYapfSegmentCostCacheNoneT<Types> PfCache; ///< Segment cost cache provider.
280 typedef CYapfCostRegionT<Types> PfCost; ///< Cost provider.
283 typedef NodeList<CYapfRegionNodeT<CYapfRegionPatchNodeKey>, 12, 12> CRegionNodeListWater;
285 struct CYapfRegionWater : CYapfT<CYapfRegion_TypesT<CYapfRegionWater, CRegionNodeListWater>>
287 explicit CYapfRegionWater(int max_nodes) { this->max_search_nodes = max_nodes; }
291 * Finds a path at the water region level. Note that the starting region is always included if the path was found.
292 * @param v The ship to find a path for.
293 * @param start_tile The tile to start searching from.
294 * @param max_returned_path_length The maximum length of the path that will be returned.
295 * @returns A path of water region patches, or an empty vector if no path was found.
297 std::vector<WaterRegionPatchDesc> YapfShipFindWaterRegionPath(const Ship *v, TileIndex start_tile, int max_returned_path_length)
299 return CYapfRegionWater::FindWaterRegionPath(v, start_tile, max_returned_path_length);