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/>.
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"
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_
> > {
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
;
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
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.
84 inline Tpf
&Yapf() { return *static_cast<Tpf
*>(this); }
87 std::vector
<CYapfRegionPatchNodeKey
> origin_keys
;
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
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.
124 void SetDestination(const WaterRegionPatchDesc
&water_region_patch
)
126 this->dest
.Set(water_region_patch
);
130 Tpf
&Yapf() { return *static_cast<Tpf
*>(this); }
133 inline bool PfDetectDestination(Node
&n
) const
135 return n
.key
== this->dest
;
138 inline bool PfCalcEstimate(Node
&n
)
140 if (this->PfDetectDestination(n
)) {
145 n
.estimate
= n
.cost
+ ManhattanDistance(n
.key
, this->dest
);
151 /** YAPF node following for water region pathfinding. */
152 template <class Types
>
153 class CYapfFollowRegionT
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.
162 inline Tpf
&Yapf() { return *static_cast<Tpf
*>(this); }
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
);
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
));
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) {
214 if (node
!= nullptr) path
.push_back(node
->key
.water_region_patch
);
218 assert(!path
.empty());
223 /** Cost Provider of YAPF for water regions. */
224 template <class Types
>
225 class CYapfCostRegionT
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.
234 /** To access inherited path finder. */
235 Tpf
&Yapf() { return *static_cast<Tpf
*>(this); }
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;
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
);