Update: Translations from eints
[openttd-github.git] / src / pathfinder / yapf / yapf_ship_regions.cpp
blobfa54c2ec0ef7c53ef9b492d4f002e5344f27c0ee
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 m_water_region_patch;
27 inline void Set(const WaterRegionPatchDesc &water_region_patch)
29 m_water_region_patch = water_region_patch;
32 inline int CalcHash() const { return CalculateWaterRegionPatchHash(m_water_region_patch); }
33 inline bool operator==(const CYapfRegionPatchNodeKey &other) const { return CalcHash() == other.CalcHash(); }
36 inline uint ManhattanDistance(const CYapfRegionPatchNodeKey &a, const CYapfRegionPatchNodeKey &b)
38 return (std::abs(a.m_water_region_patch.x - b.m_water_region_patch.x) + std::abs(a.m_water_region_patch.y - b.m_water_region_patch.y)) * DIRECT_NEIGHBOR_COST;
41 /** Yapf Node for water regions. */
42 template <class Tkey_>
43 struct CYapfRegionNodeT {
44 typedef Tkey_ Key;
45 typedef CYapfRegionNodeT<Tkey_> Node;
47 Tkey_ m_key;
48 Node *m_hash_next;
49 Node *m_parent;
50 int m_cost;
51 int m_estimate;
53 inline void Set(Node *parent, const WaterRegionPatchDesc &water_region_patch)
55 m_key.Set(water_region_patch);
56 m_hash_next = nullptr;
57 m_parent = parent;
58 m_cost = 0;
59 m_estimate = 0;
62 inline void Set(Node *parent, const Key &key)
64 Set(parent, key.m_water_region_patch);
67 DiagDirection GetDiagDirFromParent() const
69 if (!m_parent) return INVALID_DIAGDIR;
70 const int dx = m_key.m_water_region_patch.x - m_parent->m_key.m_water_region_patch.x;
71 const int dy = m_key.m_water_region_patch.y - m_parent->m_key.m_water_region_patch.y;
72 if (dx > 0 && dy == 0) return DIAGDIR_SW;
73 if (dx < 0 && dy == 0) return DIAGDIR_NE;
74 if (dx == 0 && dy > 0) return DIAGDIR_SE;
75 if (dx == 0 && dy < 0) return DIAGDIR_NW;
76 return INVALID_DIAGDIR;
79 inline Node *GetHashNext() { return m_hash_next; }
80 inline void SetHashNext(Node *pNext) { m_hash_next = pNext; }
81 inline const Tkey_ &GetKey() const { return m_key; }
82 inline int GetCost() { return m_cost; }
83 inline int GetCostEstimate() { return m_estimate; }
84 inline bool operator<(const Node &other) const { return m_estimate < other.m_estimate; }
87 /** YAPF origin for water regions. */
88 template <class Types>
89 class CYapfOriginRegionT
91 public:
92 typedef typename Types::Tpf Tpf; ///< The pathfinder class (derived from THIS class).
93 typedef typename Types::NodeList::Titem Node; ///< This will be our node type.
94 typedef typename Node::Key Key; ///< Key to hash tables.
96 protected:
97 inline Tpf &Yapf() { return *static_cast<Tpf*>(this); }
99 private:
100 std::vector<CYapfRegionPatchNodeKey> m_origin_keys;
102 public:
103 void AddOrigin(const WaterRegionPatchDesc &water_region_patch)
105 if (water_region_patch.label == INVALID_WATER_REGION_PATCH) return;
106 if (!HasOrigin(water_region_patch)) m_origin_keys.push_back(CYapfRegionPatchNodeKey{ water_region_patch });
109 bool HasOrigin(const WaterRegionPatchDesc &water_region_patch)
111 return std::find(m_origin_keys.begin(), m_origin_keys.end(), CYapfRegionPatchNodeKey{ water_region_patch }) != m_origin_keys.end();
114 void PfSetStartupNodes()
116 for (const CYapfRegionPatchNodeKey &origin_key : m_origin_keys) {
117 Node &node = Yapf().CreateNewNode();
118 node.Set(nullptr, origin_key);
119 Yapf().AddStartupNode(node);
124 /** YAPF destination provider for water regions. */
125 template <class Types>
126 class CYapfDestinationRegionT
128 public:
129 typedef typename Types::Tpf Tpf; ///< The pathfinder class (derived from THIS class).
130 typedef typename Types::NodeList::Titem Node; ///< This will be our node type.
131 typedef typename Node::Key Key; ///< Key to hash tables.
133 protected:
134 Key m_dest;
136 public:
137 void SetDestination(const WaterRegionPatchDesc &water_region_patch)
139 m_dest.Set(water_region_patch);
142 protected:
143 Tpf &Yapf() { return *static_cast<Tpf*>(this); }
145 public:
146 inline bool PfDetectDestination(Node &n) const
148 return n.m_key == m_dest;
151 inline bool PfCalcEstimate(Node &n)
153 if (PfDetectDestination(n)) {
154 n.m_estimate = n.m_cost;
155 return true;
158 n.m_estimate = n.m_cost + ManhattanDistance(n.m_key, m_dest);
160 return true;
164 /** YAPF node following for water region pathfinding. */
165 template <class Types>
166 class CYapfFollowRegionT
168 public:
169 typedef typename Types::Tpf Tpf; ///< The pathfinder class (derived from THIS class).
170 typedef typename Types::TrackFollower TrackFollower;
171 typedef typename Types::NodeList::Titem Node; ///< This will be our node type.
172 typedef typename Node::Key Key; ///< Key to hash tables.
174 protected:
175 inline Tpf &Yapf() { return *static_cast<Tpf*>(this); }
177 public:
178 inline void PfFollowNode(Node &old_node)
180 TVisitWaterRegionPatchCallBack visitFunc = [&](const WaterRegionPatchDesc &water_region_patch)
182 Node &node = Yapf().CreateNewNode();
183 node.Set(&old_node, water_region_patch);
184 Yapf().AddNewNode(node, TrackFollower{});
186 VisitWaterRegionPatchNeighbors(old_node.m_key.m_water_region_patch, visitFunc);
189 inline char TransportTypeChar() const { return '^'; }
191 static std::vector<WaterRegionPatchDesc> FindWaterRegionPath(const Ship *v, TileIndex start_tile, int max_returned_path_length)
193 const WaterRegionPatchDesc start_water_region_patch = GetWaterRegionPatchInfo(start_tile);
195 /* 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
196 * 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. */
197 Tpf pf(std::min(static_cast<int>(Map::Size() * NODES_PER_REGION) / WATER_REGION_NUMBER_OF_TILES, MAX_NUMBER_OF_NODES));
198 pf.SetDestination(start_water_region_patch);
200 if (v->current_order.IsType(OT_GOTO_STATION)) {
201 DestinationID station_id = v->current_order.GetDestination();
202 const BaseStation *station = BaseStation::Get(station_id);
203 TileArea tile_area;
204 station->GetTileArea(&tile_area, STATION_DOCK);
205 for (const auto &tile : tile_area) {
206 if (IsDockingTile(tile) && IsShipDestinationTile(tile, station_id)) {
207 pf.AddOrigin(GetWaterRegionPatchInfo(tile));
210 } else {
211 TileIndex tile = v->dest_tile;
212 pf.AddOrigin(GetWaterRegionPatchInfo(tile));
215 /* If origin and destination are the same we simply return that water patch. */
216 std::vector<WaterRegionPatchDesc> path = { start_water_region_patch };
217 path.reserve(max_returned_path_length);
218 if (pf.HasOrigin(start_water_region_patch)) return path;
220 /* Find best path. */
221 if (!pf.FindPath(v)) return {}; // Path not found.
223 Node *node = pf.GetBestNode();
224 for (int i = 0; i < max_returned_path_length - 1; ++i) {
225 if (node != nullptr) {
226 node = node->m_parent;
227 if (node != nullptr) path.push_back(node->m_key.m_water_region_patch);
231 assert(!path.empty());
232 return path;
236 /** Cost Provider of YAPF for water regions. */
237 template <class Types>
238 class CYapfCostRegionT
240 public:
241 typedef typename Types::Tpf Tpf; ///< The pathfinder class (derived from THIS class).
242 typedef typename Types::TrackFollower TrackFollower;
243 typedef typename Types::NodeList::Titem Node; ///< This will be our node type.
244 typedef typename Node::Key Key; ///< Key to hash tables.
246 protected:
247 /** To access inherited path finder. */
248 Tpf &Yapf() { return *static_cast<Tpf*>(this); }
250 public:
252 * Called by YAPF to calculate the cost from the origin to the given node.
253 * Calculates only the cost of given node, adds it to the parent node cost
254 * and stores the result into Node::m_cost member.
256 inline bool PfCalcCost(Node &n, const TrackFollower *)
258 n.m_cost = n.m_parent->m_cost + ManhattanDistance(n.m_key, n.m_parent->m_key);
260 /* Incentivise zigzagging by adding a slight penalty when the search continues in the same direction. */
261 Node *grandparent = n.m_parent->m_parent;
262 if (grandparent != nullptr) {
263 const DiagDirDiff dir_diff = DiagDirDifference(n.m_parent->GetDiagDirFromParent(), n.GetDiagDirFromParent());
264 if (dir_diff != DIAGDIRDIFF_90LEFT && dir_diff != DIAGDIRDIFF_90RIGHT) n.m_cost += 1;
267 return true;
271 /* We don't need a follower but YAPF requires one. */
272 struct DummyFollower : public CFollowTrackWater {};
275 * Config struct of YAPF for route planning.
276 * Defines all 6 base YAPF modules as classes providing services for CYapfBaseT.
278 template <class Tpf_, class Tnode_list>
279 struct CYapfRegion_TypesT
281 typedef CYapfRegion_TypesT<Tpf_, Tnode_list> Types; ///< Shortcut for this struct type.
282 typedef Tpf_ Tpf; ///< Pathfinder type.
283 typedef DummyFollower TrackFollower; ///< Track follower helper class
284 typedef Tnode_list NodeList;
285 typedef Ship VehicleType;
287 /** Pathfinder components (modules). */
288 typedef CYapfBaseT<Types> PfBase; ///< Base pathfinder class.
289 typedef CYapfFollowRegionT<Types> PfFollow; ///< Node follower.
290 typedef CYapfOriginRegionT<Types> PfOrigin; ///< Origin provider.
291 typedef CYapfDestinationRegionT<Types> PfDestination; ///< Destination/distance provider.
292 typedef CYapfSegmentCostCacheNoneT<Types> PfCache; ///< Segment cost cache provider.
293 typedef CYapfCostRegionT<Types> PfCost; ///< Cost provider.
296 typedef CNodeList_HashTableT<CYapfRegionNodeT<CYapfRegionPatchNodeKey>, 12, 12> CRegionNodeListWater;
298 struct CYapfRegionWater : CYapfT<CYapfRegion_TypesT<CYapfRegionWater, CRegionNodeListWater>>
300 explicit CYapfRegionWater(int max_nodes) { m_max_search_nodes = max_nodes; }
304 * Finds a path at the water region level. Note that the starting region is always included if the path was found.
305 * @param v The ship to find a path for.
306 * @param start_tile The tile to start searching from.
307 * @param max_returned_path_length The maximum length of the path that will be returned.
308 * @returns A path of water region patches, or an empty vector if no path was found.
310 std::vector<WaterRegionPatchDesc> YapfShipFindWaterRegionPath(const Ship *v, TileIndex start_tile, int max_returned_path_length)
312 return CYapfRegionWater::FindWaterRegionPath(v, start_tile, max_returned_path_length);