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 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
{
45 typedef CYapfRegionNodeT
<Tkey_
> Node
;
53 inline void Set(Node
*parent
, const WaterRegionPatchDesc
&water_region_patch
)
55 m_key
.Set(water_region_patch
);
56 m_hash_next
= nullptr;
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
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.
97 inline Tpf
&Yapf() { return *static_cast<Tpf
*>(this); }
100 std::vector
<CYapfRegionPatchNodeKey
> m_origin_keys
;
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
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.
137 void SetDestination(const WaterRegionPatchDesc
&water_region_patch
)
139 m_dest
.Set(water_region_patch
);
143 Tpf
&Yapf() { return *static_cast<Tpf
*>(this); }
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
;
158 n
.m_estimate
= n
.m_cost
+ ManhattanDistance(n
.m_key
, m_dest
);
164 /** YAPF node following for water region pathfinding. */
165 template <class Types
>
166 class CYapfFollowRegionT
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.
175 inline Tpf
&Yapf() { return *static_cast<Tpf
*>(this); }
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
);
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
));
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());
236 /** Cost Provider of YAPF for water regions. */
237 template <class Types
>
238 class CYapfCostRegionT
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.
247 /** To access inherited path finder. */
248 Tpf
&Yapf() { return *static_cast<Tpf
*>(this); }
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;
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
);