OpenTTD

yapf_ship.cpp
Go to the documentation of this file.
1 /* $Id: yapf_ship.cpp 27362 2015-08-08 10:06:24Z alberth $ */
2
3 /*
4 * This file is part of OpenTTD.
5 * 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.
6 * 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.
7 * 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 */
9
12 #include "../../stdafx.h"
13 #include "../../ship.h"
14
15 #include "yapf.hpp"
16 #include "yapf_node_ship.hpp"
17
18 #include "../../safeguards.h"
19
21 template <class Types>
22 class CYapfFollowShipT
23 {
24 public:
25 typedef typename Types::Tpf Tpf;
26 typedef typename Types::TrackFollower TrackFollower;
27 typedef typename Types::NodeList::Titem Node;
28 typedef typename Node::Key Key;
29
30 protected:
32 inline Tpf& Yapf()
33 {
34 return *static_cast<Tpf *>(this);
35 }
36
37 public:
43 inline void PfFollowNode(Node &old_node)
44 {
45 TrackFollower F(Yapf().GetVehicle());
46 if (F.Follow(old_node.m_key.m_tile, old_node.m_key.m_td)) {
47 Yapf().AddMultipleNodes(&old_node, F);
48 }
49 }
50
52 inline char TransportTypeChar() const
53 {
54 return 'w';
55 }
56
57 static Trackdir ChooseShipTrack(const Ship *v, TileIndex tile, DiagDirection enterdir, TrackBits tracks, bool &path_found)
58 {
59 /* handle special case - when next tile is destination tile */
60 if (tile == v->dest_tile) {
61 /* convert tracks to trackdirs */
62 TrackdirBits trackdirs = (TrackdirBits)(tracks | ((int)tracks << 8));
63 /* limit to trackdirs reachable from enterdir */
64 trackdirs &= DiagdirReachesTrackdirs(enterdir);
65
66 /* use vehicle's current direction if that's possible, otherwise use first usable one. */
67 Trackdir veh_dir = v->GetVehicleTrackdir();
68 return ((trackdirs & TrackdirToTrackdirBits(veh_dir)) != 0) ? veh_dir : (Trackdir)FindFirstBit2x64(trackdirs);
69 }
70
71 /* move back to the old tile/trackdir (where ship is coming from) */
72 TileIndex src_tile = TILE_ADD(tile, TileOffsByDiagDir(ReverseDiagDir(enterdir)));
73 Trackdir trackdir = v->GetVehicleTrackdir();
74 assert(IsValidTrackdir(trackdir));
75
76 /* convert origin trackdir to TrackdirBits */
77 TrackdirBits trackdirs = TrackdirToTrackdirBits(trackdir);
78 /* get available trackdirs on the destination tile */
79 TrackdirBits dest_trackdirs = TrackStatusToTrackdirBits(GetTileTrackStatus(v->dest_tile, TRANSPORT_WATER, 0));
80
81 /* create pathfinder instance */
82 Tpf pf;
83 /* set origin and destination nodes */
84 pf.SetOrigin(src_tile, trackdirs);
85 pf.SetDestination(v->dest_tile, dest_trackdirs);
86 /* find best path */
87 path_found = pf.FindPath(v);
88
89 Trackdir next_trackdir = INVALID_TRACKDIR; // this would mean "path not found"
90
91 Node *pNode = pf.GetBestNode();
92 if (pNode != NULL) {
93 /* walk through the path back to the origin */
94 Node *pPrevNode = NULL;
95 while (pNode->m_parent != NULL) {
96 pPrevNode = pNode;
97 pNode = pNode->m_parent;
98 }
99 /* return trackdir from the best next node (direct child of origin) */
100 Node &best_next_node = *pPrevNode;
101 assert(best_next_node.GetTile() == tile);
102 next_trackdir = best_next_node.GetTrackdir();
103 }
104 return next_trackdir;
105 }
106
116 static bool CheckShipReverse(const Ship *v, TileIndex tile, Trackdir td1, Trackdir td2)
117 {
118 /* get available trackdirs on the destination tile */
119 TrackdirBits dest_trackdirs = TrackStatusToTrackdirBits(GetTileTrackStatus(v->dest_tile, TRANSPORT_WATER, 0));
120
121 /* create pathfinder instance */
122 Tpf pf;
123 /* set origin and destination nodes */
124 pf.SetOrigin(tile, TrackdirToTrackdirBits(td1) | TrackdirToTrackdirBits(td2));
125 pf.SetDestination(v->dest_tile, dest_trackdirs);
126 /* find best path */
127 if (!pf.FindPath(v)) return false;
128
129 Node *pNode = pf.GetBestNode();
130 if (pNode == NULL) return false;
131
132 /* path was found
133 * walk through the path back to the origin */
134 while (pNode->m_parent != NULL) {
135 pNode = pNode->m_parent;
136 }
137
138 Trackdir best_trackdir = pNode->GetTrackdir();
139 assert(best_trackdir == td1 || best_trackdir == td2);
140 return best_trackdir == td2;
141 }
142 };
143
145 template <class Types>
146 class CYapfCostShipT
147 {
148 public:
149 typedef typename Types::Tpf Tpf;
150 typedef typename Types::TrackFollower TrackFollower;
151 typedef typename Types::NodeList::Titem Node;
152 typedef typename Node::Key Key;
153
154 protected:
156 Tpf& Yapf()
157 {
158 return *static_cast<Tpf *>(this);
159 }
160
161 public:
167 inline bool PfCalcCost(Node &n, const TrackFollower *tf)
168 {
169 /* base tile cost depending on distance */
170 int c = IsDiagonalTrackdir(n.GetTrackdir()) ? YAPF_TILE_LENGTH : YAPF_TILE_CORNER_LENGTH;
171 /* additional penalty for curves */
172 if (n.GetTrackdir() != NextTrackdir(n.m_parent->GetTrackdir())) {
173 /* new trackdir does not match the next one when going straight */
174 c += YAPF_TILE_LENGTH;
175 }
176
177 /* Skipped tile cost for aqueducts. */
178 c += YAPF_TILE_LENGTH * tf->m_tiles_skipped;
179
180 /* Ocean/canal speed penalty. */
181 const ShipVehicleInfo *svi = ShipVehInfo(Yapf().GetVehicle()->engine_type);
182 byte speed_frac = (GetEffectiveWaterClass(n.GetTile()) == WATER_CLASS_SEA) ? svi->ocean_speed_frac : svi->canal_speed_frac;
183 if (speed_frac > 0) c += YAPF_TILE_LENGTH * (1 + tf->m_tiles_skipped) * speed_frac / (256 - speed_frac);
184
185 /* apply it */
186 n.m_cost = n.m_parent->m_cost + c;
187 return true;
188 }
189 };
190
195 template <class Tpf_, class Ttrack_follower, class Tnode_list>
196 struct CYapfShip_TypesT
197 {
199 typedef CYapfShip_TypesT<Tpf_, Ttrack_follower, Tnode_list> Types;
200
202 typedef Tpf_ Tpf;
204 typedef Ttrack_follower TrackFollower;
206 typedef Tnode_list NodeList;
207 typedef Ship VehicleType;
209 typedef CYapfBaseT<Types> PfBase; // base pathfinder class
210 typedef CYapfFollowShipT<Types> PfFollow; // node follower
211 typedef CYapfOriginTileT<Types> PfOrigin; // origin provider
212 typedef CYapfDestinationTileT<Types> PfDestination; // destination/distance provider
213 typedef CYapfSegmentCostCacheNoneT<Types> PfCache; // segment cost cache provider
214 typedef CYapfCostShipT<Types> PfCost; // cost provider
215 };
216
217 /* YAPF type 1 - uses TileIndex/Trackdir as Node key, allows 90-deg turns */
218 struct CYapfShip1 : CYapfT<CYapfShip_TypesT<CYapfShip1, CFollowTrackWater , CShipNodeListTrackDir> > {};
219 /* YAPF type 2 - uses TileIndex/DiagDirection as Node key, allows 90-deg turns */
220 struct CYapfShip2 : CYapfT<CYapfShip_TypesT<CYapfShip2, CFollowTrackWater , CShipNodeListExitDir > > {};
221 /* YAPF type 3 - uses TileIndex/Trackdir as Node key, forbids 90-deg turns */
222 struct CYapfShip3 : CYapfT<CYapfShip_TypesT<CYapfShip3, CFollowTrackWaterNo90, CShipNodeListTrackDir> > {};
223
225 Track YapfShipChooseTrack(const Ship *v, TileIndex tile, DiagDirection enterdir, TrackBits tracks, bool &path_found)
226 {
227 /* default is YAPF type 2 */
228 typedef Trackdir (*PfnChooseShipTrack)(const Ship*, TileIndex, DiagDirection, TrackBits, bool &path_found);
229 PfnChooseShipTrack pfnChooseShipTrack = CYapfShip2::ChooseShipTrack; // default: ExitDir, allow 90-deg
230
231 /* check if non-default YAPF type needed */
232 if (_settings_game.pf.forbid_90_deg) {
233 pfnChooseShipTrack = &CYapfShip3::ChooseShipTrack; // Trackdir, forbid 90-deg
234 } else if (_settings_game.pf.yapf.disable_node_optimization) {
235 pfnChooseShipTrack = &CYapfShip1::ChooseShipTrack; // Trackdir, allow 90-deg
236 }
237
238 Trackdir td_ret = pfnChooseShipTrack(v, tile, enterdir, tracks, path_found);
239 return (td_ret != INVALID_TRACKDIR) ? TrackdirToTrack(td_ret) : INVALID_TRACK;
240 }
241
242 bool YapfShipCheckReverse(const Ship *v)
243 {
244 Trackdir td = v->GetVehicleTrackdir();
245 Trackdir td_rev = ReverseTrackdir(td);
246 TileIndex tile = v->tile;
247
248 typedef bool (*PfnCheckReverseShip)(const Ship*, TileIndex, Trackdir, Trackdir);
249 PfnCheckReverseShip pfnCheckReverseShip = CYapfShip2::CheckShipReverse; // default: ExitDir, allow 90-deg
250
251 /* check if non-default YAPF type needed */
252 if (_settings_game.pf.forbid_90_deg) {
253 pfnCheckReverseShip = &CYapfShip3::CheckShipReverse; // Trackdir, forbid 90-deg
254 } else if (_settings_game.pf.yapf.disable_node_optimization) {
255 pfnCheckReverseShip = &CYapfShip1::CheckShipReverse; // Trackdir, allow 90-deg
256 }
257
258 bool reverse = pfnCheckReverseShip(v, tile, td, td_rev);
259
260 return reverse;
261 }
ShipVehicleInfo
Information about a ship vehicle.
Definition: engine_type.h:66
_settings_game
GameSettings _settings_game
Game settings of a running game or the scenario editor.
Definition: settings.cpp:77
CYapfOriginTileT
YAPF origin provider base class - used when origin is one tile / multiple trackdirs.
Definition: yapf_common.hpp:17
CYapfShip_TypesT::Types
CYapfShip_TypesT< Tpf_, Ttrack_follower, Tnode_list > Types
Types - shortcut for this struct type.
Definition: yapf_ship.cpp:199
CYapfShip_TypesT::TrackFollower
Ttrack_follower TrackFollower
track follower helper class
Definition: yapf_ship.cpp:204
ShipVehicleInfo::ocean_speed_frac
byte ocean_speed_frac
Fraction of maximum speed for ocean tiles.
Definition: engine_type.h:75
TrackdirToTrack
static Track TrackdirToTrack(Trackdir trackdir)
Returns the Track that a given Trackdir represents.
Definition: track_func.h:272
CYapfFollowShipT::TransportTypeChar
char TransportTypeChar() const
return debug report character to identify the transportation type
Definition: yapf_ship.cpp:52
Track
Track
These are used to specify a single track.
Definition: track_type.h:21
Vehicle::dest_tile
TileIndex dest_tile
Heading for this tile.
Definition: vehicle_base.h:237
TRANSPORT_WATER
Transport over water.
Definition: transport_type.h:31
CYapfSegmentCostCacheNoneT
CYapfSegmentCostCacheNoneT - the formal only yapf cost cache provider that implements PfNodeCacheFetc...
Definition: yapf_costcache.hpp:23
CYapfShip_TypesT::NodeList
Tnode_list NodeList
node list type
Definition: yapf_ship.cpp:206
GameSettings::pf
PathfinderSettings pf
settings for all pathfinders
Definition: settings_type.h:550
CYapfCostShipT::Key
Node::Key Key
key to hash tables
Definition: yapf_ship.cpp:152
WATER_CLASS_SEA
Sea.
Definition: water_map.h:50
NextTrackdir
static Trackdir NextTrackdir(Trackdir trackdir)
Maps a trackdir to the trackdir that you will end up on if you go straight ahead. ...
Definition: track_func.h:391
PathfinderSettings::forbid_90_deg
bool forbid_90_deg
forbid trains to make 90 deg turns
Definition: settings_type.h:421
CYapfDestinationTileT
YAPF destination provider base class - used when destination is single tile / multiple trackdirs...
Definition: yapf_common.hpp:115
DiagdirReachesTrackdirs
static TrackdirBits DiagdirReachesTrackdirs(DiagDirection diagdir)
Returns all trackdirs that can be reached when entering a tile from a given (diagonal) direction...
Definition: track_func.h:543
CYapfCostShipT::Yapf
Tpf & Yapf()
to access inherited path finder
Definition: yapf_ship.cpp:156
CYapfShip_TypesT::PfBase
CYapfBaseT< Types > PfBase
pathfinder components (modules)
Definition: yapf_ship.cpp:209
CYapfCostShipT::Node
Types::NodeList::Titem Node
this will be our node type
Definition: yapf_ship.cpp:151
TrackBits
TrackBits
Bitfield corresponding to Track.
Definition: track_type.h:41
CYapfCostShipT
Cost Provider module of YAPF for ships.
Definition: yapf_ship.cpp:146
TileOffsByDiagDir
static TileIndexDiff TileOffsByDiagDir(DiagDirection dir)
Convert a DiagDirection to a TileIndexDiff.
Definition: map_func.h:343
IsValidTrackdir
static bool IsValidTrackdir(Trackdir trackdir)
Checks if a Trackdir is valid for non-road vehicles.
Definition: track_func.h:62
CYapfCostShipT::Tpf
Types::Tpf Tpf
the pathfinder class (derived from THIS class)
Definition: yapf_ship.cpp:149
CYapfBaseT
CYapfBaseT - A-star type path finder base class.
Definition: yapf_base.hpp:51
CYapfFollowShipT::Yapf
Tpf & Yapf()
to access inherited path finder
Definition: yapf_ship.cpp:32
YAPFSettings::disable_node_optimization
bool disable_node_optimization
whether to use exit-dir instead of trackdir in node key
Definition: settings_type.h:375
CYapfShip_TypesT
Config struct of YAPF for ships.
Definition: yapf_ship.cpp:196
PathfinderSettings::yapf
YAPFSettings yapf
pathfinder settings for the yet another pathfinder
Definition: settings_type.h:433
VehicleType
VehicleType
Available vehicle types.
Definition: vehicle_type.h:21
TrackdirToTrackdirBits
static TrackdirBits TrackdirToTrackdirBits(Trackdir trackdir)
Maps a Trackdir to the corresponding TrackdirBits value.
Definition: track_func.h:121
ReverseDiagDir
static DiagDirection ReverseDiagDir(DiagDirection d)
Returns the reverse direction of the given DiagDirection.
Definition: direction_func.h:120
CYapfFollowShipT
Node Follower module of YAPF for ships.
Definition: yapf_ship.cpp:22
YAPF_TILE_LENGTH
static const int YAPF_TILE_LENGTH
Length (penalty) of one tile with YAPF.
Definition: pathfinder_type.h:30
Trackdir
Trackdir
Enumeration for tracks and directions.
Definition: track_type.h:74
CYapfT
YAPF template that uses Ttypes template argument to determine all YAPF components (base classes) from...
Definition: yapf_common.hpp:186
Vehicle::tile
TileIndex tile
Current tile index.
Definition: vehicle_base.h:230
CYapfFollowShipT::CheckShipReverse
static bool CheckShipReverse(const Ship *v, TileIndex tile, Trackdir td1, Trackdir td2)
Check whether a ship should reverse to reach its destination.
Definition: yapf_ship.cpp:116
DiagDirection
DiagDirection
Enumeration for diagonal directions.
Definition: direction_type.h:80
CYapfShip1
Definition: yapf_ship.cpp:218
Ship
All ships have this type.
Definition: ship.h:24
ReverseTrackdir
static Trackdir ReverseTrackdir(Trackdir trackdir)
Maps a trackdir to the reverse trackdir.
Definition: track_func.h:257
GetTileTrackStatus
TrackStatus GetTileTrackStatus(TileIndex tile, TransportType mode, uint sub_mode, DiagDirection side)
Returns information about trackdirs and signal states.
Definition: landscape.cpp:509
INVALID_TRACK
Flag for an invalid track.
Definition: track_type.h:30
TileIndex
uint32 TileIndex
The index/ID of a Tile.
Definition: tile_type.h:80
yapf.hpp
Base includes/functions for YAPF.
CYapfFollowShipT::Node
Types::NodeList::Titem Node
this will be our node type
Definition: yapf_ship.cpp:27
IsDiagonalTrackdir
static bool IsDiagonalTrackdir(Trackdir trackdir)
Checks if a given Trackdir is diagonal.
Definition: track_func.h:619
Ship::GetVehicleTrackdir
Trackdir GetVehicleTrackdir() const
Returns the Trackdir on which the vehicle is currently located.
Definition: ship_cmd.cpp:250
FindFirstBit2x64
static uint8 FindFirstBit2x64(const int value)
Finds the position of the first non-zero bit in an integer.
Definition: bitmath_func.hpp:218
TrackdirBits
TrackdirBits
Enumeration of bitmasks for the TrackDirs.
Definition: track_type.h:106
CYapfShip2
Definition: yapf_ship.cpp:220
YapfShipChooseTrack
Track YapfShipChooseTrack(const Ship *v, TileIndex tile, DiagDirection enterdir, TrackBits tracks, bool &path_found)
Ship controller helper - path finder invoker.
Definition: yapf_ship.cpp:225
CYapfCostShipT::PfCalcCost
bool PfCalcCost(Node &n, const TrackFollower *tf)
Called by YAPF to calculate the cost from the origin to the given node.
Definition: yapf_ship.cpp:167
INVALID_TRACKDIR
Flag for an invalid trackdir.
Definition: track_type.h:93
CYapfShip_TypesT::Tpf
Tpf_ Tpf
Tpf - pathfinder type.
Definition: yapf_ship.cpp:202
CYapfShip3
Definition: yapf_ship.cpp:222
YAPF_TILE_CORNER_LENGTH
static const int YAPF_TILE_CORNER_LENGTH
Length (penalty) of a corner with YAPF.
Definition: pathfinder_type.h:33
TILE_ADD
#define TILE_ADD(x, y)
Adds to tiles together.
Definition: map_func.h:246
GetEffectiveWaterClass
WaterClass GetEffectiveWaterClass(TileIndex tile)
Determine the effective WaterClass for a ship travelling on a tile.
Definition: ship_cmd.cpp:47
CYapfFollowShipT::Key
Node::Key Key
key to hash tables
Definition: yapf_ship.cpp:28
ShipVehicleInfo::canal_speed_frac
byte canal_speed_frac
Fraction of maximum speed for canal/river tiles.
Definition: engine_type.h:76
TrackStatusToTrackdirBits
static TrackdirBits TrackStatusToTrackdirBits(TrackStatus ts)
Returns the present-trackdir-information of a TrackStatus.
Definition: track_func.h:340
CYapfFollowShipT::PfFollowNode
void PfFollowNode(Node &old_node)
Called by YAPF to move from the given node to the next tile.
Definition: yapf_ship.cpp:43
CYapfFollowShipT::Tpf
Types::Tpf Tpf
the pathfinder class (derived from THIS class)
Definition: yapf_ship.cpp:25
YapfShipCheckReverse
bool YapfShipCheckReverse(const Ship *v)
Returns true if it is better to reverse the ship before leaving depot using YAPF. ...
Definition: yapf_ship.cpp:242
yapf_node_ship.hpp
Node tailored for ship pathfinding.
ChooseShipTrack
static Track ChooseShipTrack(Ship *v, TileIndex tile, DiagDirection enterdir, TrackBits tracks)
Runs the pathfinder to choose a track to continue along.
Definition: ship_cmd.cpp:439