2006-05-27 16:12:16 +00:00
|
|
|
/* $Id$ */
|
|
|
|
|
2008-05-06 15:11:33 +00:00
|
|
|
/** @file yapf_ship.cpp Implementation of YAPF for ships. */
|
2007-02-23 08:37:33 +00:00
|
|
|
|
2006-05-27 16:12:16 +00:00
|
|
|
#include "../stdafx.h"
|
|
|
|
|
|
|
|
#include "yapf.hpp"
|
|
|
|
|
|
|
|
/** Node Follower module of YAPF for ships */
|
|
|
|
template <class Types>
|
|
|
|
class CYapfFollowShipT
|
|
|
|
{
|
|
|
|
public:
|
2006-05-29 18:39:42 +00:00
|
|
|
typedef typename Types::Tpf Tpf; ///< the pathfinder class (derived from THIS class)
|
2006-05-27 16:12:16 +00:00
|
|
|
typedef typename Types::TrackFollower TrackFollower;
|
2006-05-29 18:39:42 +00:00
|
|
|
typedef typename Types::NodeList::Titem Node; ///< this will be our node type
|
|
|
|
typedef typename Node::Key Key; ///< key to hash tables
|
2006-05-27 16:12:16 +00:00
|
|
|
|
|
|
|
protected:
|
2009-03-15 00:32:18 +00:00
|
|
|
/** to access inherited path finder */
|
2009-03-04 08:02:16 +00:00
|
|
|
FORCEINLINE Tpf& Yapf()
|
|
|
|
{
|
|
|
|
return *static_cast<Tpf*>(this);
|
|
|
|
}
|
2006-05-27 16:12:16 +00:00
|
|
|
|
|
|
|
public:
|
2006-05-29 18:39:42 +00:00
|
|
|
/** Called by YAPF to move from the given node to the next tile. For each
|
2006-09-04 20:40:33 +00:00
|
|
|
* reachable trackdir on the new tile creates new node, initializes it
|
|
|
|
* and adds it to the open list by calling Yapf().AddNewNode(n) */
|
2006-05-27 16:12:16 +00:00
|
|
|
inline void PfFollowNode(Node& old_node)
|
|
|
|
{
|
2007-05-25 15:49:14 +00:00
|
|
|
TrackFollower F(Yapf().GetVehicle());
|
2009-03-04 08:02:16 +00:00
|
|
|
if (F.Follow(old_node.m_key.m_tile, old_node.m_key.m_td)) {
|
2007-02-24 00:17:46 +00:00
|
|
|
Yapf().AddMultipleNodes(&old_node, F);
|
2009-03-04 08:02:16 +00:00
|
|
|
}
|
2006-05-27 16:12:16 +00:00
|
|
|
}
|
|
|
|
|
2009-03-15 00:32:18 +00:00
|
|
|
/** return debug report character to identify the transportation type */
|
2009-03-04 08:02:16 +00:00
|
|
|
FORCEINLINE char TransportTypeChar() const
|
|
|
|
{
|
|
|
|
return 'w';
|
|
|
|
}
|
2006-05-27 16:12:16 +00:00
|
|
|
|
2008-06-02 06:44:06 +00:00
|
|
|
static Trackdir ChooseShipTrack(const Vehicle *v, TileIndex tile, DiagDirection enterdir, TrackBits tracks)
|
2006-05-27 16:12:16 +00:00
|
|
|
{
|
2009-03-15 00:32:18 +00:00
|
|
|
/* handle special case - when next tile is destination tile */
|
2006-05-27 16:12:16 +00:00
|
|
|
if (tile == v->dest_tile) {
|
2009-03-15 00:32:18 +00:00
|
|
|
/* convert tracks to trackdirs */
|
2006-05-27 16:12:16 +00:00
|
|
|
TrackdirBits trackdirs = (TrackdirBits)(tracks | ((int)tracks << 8));
|
2009-03-15 00:32:18 +00:00
|
|
|
/* choose any trackdir reachable from enterdir */
|
2006-05-27 16:12:16 +00:00
|
|
|
trackdirs &= DiagdirReachesTrackdirs(enterdir);
|
|
|
|
return (Trackdir)FindFirstBit2x64(trackdirs);
|
|
|
|
}
|
|
|
|
|
2009-03-15 00:32:18 +00:00
|
|
|
/* move back to the old tile/trackdir (where ship is coming from) */
|
2006-09-05 23:21:41 +00:00
|
|
|
TileIndex src_tile = TILE_ADD(tile, TileOffsByDiagDir(ReverseDiagDir(enterdir)));
|
2009-05-22 18:17:20 +00:00
|
|
|
Trackdir trackdir = v->GetVehicleTrackdir();
|
2006-05-27 16:12:16 +00:00
|
|
|
assert(IsValidTrackdir(trackdir));
|
|
|
|
|
2009-03-15 00:32:18 +00:00
|
|
|
/* convert origin trackdir to TrackdirBits */
|
2006-05-27 16:12:16 +00:00
|
|
|
TrackdirBits trackdirs = TrackdirToTrackdirBits(trackdir);
|
2009-03-15 00:32:18 +00:00
|
|
|
/* get available trackdirs on the destination tile */
|
2008-02-20 17:49:50 +00:00
|
|
|
TrackdirBits dest_trackdirs = TrackStatusToTrackdirBits(GetTileTrackStatus(v->dest_tile, TRANSPORT_WATER, 0));
|
2006-05-27 16:12:16 +00:00
|
|
|
|
2009-03-15 00:32:18 +00:00
|
|
|
/* create pathfinder instance */
|
2006-05-27 16:12:16 +00:00
|
|
|
Tpf pf;
|
2009-03-15 00:32:18 +00:00
|
|
|
/* set origin and destination nodes */
|
2006-05-27 16:12:16 +00:00
|
|
|
pf.SetOrigin(src_tile, trackdirs);
|
|
|
|
pf.SetDestination(v->dest_tile, dest_trackdirs);
|
2009-03-15 00:32:18 +00:00
|
|
|
/* find best path */
|
2007-04-20 19:43:06 +00:00
|
|
|
pf.FindPath(v);
|
2006-05-27 16:12:16 +00:00
|
|
|
|
|
|
|
Trackdir next_trackdir = INVALID_TRACKDIR; // this would mean "path not found"
|
2007-04-20 19:19:23 +00:00
|
|
|
|
2009-01-10 00:31:47 +00:00
|
|
|
Node *pNode = pf.GetBestNode();
|
2007-04-20 19:19:23 +00:00
|
|
|
if (pNode != NULL) {
|
2009-03-15 00:32:18 +00:00
|
|
|
/* walk through the path back to the origin */
|
2009-01-10 00:31:47 +00:00
|
|
|
Node *pPrevNode = NULL;
|
2006-05-27 16:12:16 +00:00
|
|
|
while (pNode->m_parent != NULL) {
|
|
|
|
pPrevNode = pNode;
|
|
|
|
pNode = pNode->m_parent;
|
|
|
|
}
|
2009-03-15 00:32:18 +00:00
|
|
|
/* return trackdir from the best next node (direct child of origin) */
|
2006-05-27 16:12:16 +00:00
|
|
|
Node& best_next_node = *pPrevNode;
|
|
|
|
assert(best_next_node.GetTile() == tile);
|
|
|
|
next_trackdir = best_next_node.GetTrackdir();
|
|
|
|
}
|
|
|
|
return next_trackdir;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
/** Cost Provider module of YAPF for ships */
|
|
|
|
template <class Types>
|
|
|
|
class CYapfCostShipT
|
|
|
|
{
|
|
|
|
public:
|
2006-05-29 18:39:42 +00:00
|
|
|
typedef typename Types::Tpf Tpf; ///< the pathfinder class (derived from THIS class)
|
2007-02-24 00:17:46 +00:00
|
|
|
typedef typename Types::TrackFollower TrackFollower;
|
2006-05-27 16:12:16 +00:00
|
|
|
typedef typename Types::NodeList::Titem Node; ///< this will be our node type
|
2006-05-29 18:39:42 +00:00
|
|
|
typedef typename Node::Key Key; ///< key to hash tables
|
2006-05-27 16:12:16 +00:00
|
|
|
|
|
|
|
protected:
|
2009-03-15 00:32:18 +00:00
|
|
|
/** to access inherited path finder */
|
2009-03-04 08:02:16 +00:00
|
|
|
Tpf& Yapf()
|
|
|
|
{
|
|
|
|
return *static_cast<Tpf*>(this);
|
|
|
|
}
|
2006-05-27 16:12:16 +00:00
|
|
|
|
|
|
|
public:
|
2006-05-29 18:39:42 +00:00
|
|
|
/** Called by YAPF to calculate the cost from the origin to the given node.
|
2006-09-04 20:40:33 +00:00
|
|
|
* Calculates only the cost of given node, adds it to the parent node cost
|
|
|
|
* and stores the result into Node::m_cost member */
|
2007-06-24 13:18:54 +00:00
|
|
|
FORCEINLINE bool PfCalcCost(Node& n, const TrackFollower *tf)
|
2006-05-27 16:12:16 +00:00
|
|
|
{
|
2009-03-15 00:32:18 +00:00
|
|
|
/* base tile cost depending on distance */
|
2009-03-29 18:20:02 +00:00
|
|
|
int c = IsDiagonalTrackdir(n.GetTrackdir()) ? YAPF_TILE_LENGTH : YAPF_TILE_CORNER_LENGTH;
|
2009-03-15 00:32:18 +00:00
|
|
|
/* additional penalty for curves */
|
2007-07-15 11:45:38 +00:00
|
|
|
if (n.m_parent != NULL && n.GetTrackdir() != NextTrackdir(n.m_parent->GetTrackdir())) {
|
|
|
|
/* new trackdir does not match the next one when going straight */
|
2009-03-29 18:20:02 +00:00
|
|
|
c += YAPF_TILE_LENGTH;
|
2007-07-15 11:45:38 +00:00
|
|
|
}
|
2008-06-11 13:54:01 +00:00
|
|
|
|
|
|
|
c += YAPF_TILE_LENGTH * tf->m_tiles_skipped;
|
|
|
|
|
2009-03-15 00:32:18 +00:00
|
|
|
/* apply it */
|
2006-05-27 16:12:16 +00:00
|
|
|
n.m_cost = n.m_parent->m_cost + c;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
/** Config struct of YAPF for ships.
|
2006-09-04 20:40:33 +00:00
|
|
|
* Defines all 6 base YAPF modules as classes providing services for CYapfBaseT.
|
|
|
|
*/
|
2006-05-27 16:12:16 +00:00
|
|
|
template <class Tpf_, class Ttrack_follower, class Tnode_list>
|
|
|
|
struct CYapfShip_TypesT
|
|
|
|
{
|
|
|
|
/** Types - shortcut for this struct type */
|
|
|
|
typedef CYapfShip_TypesT<Tpf_, Ttrack_follower, Tnode_list> Types;
|
|
|
|
|
|
|
|
/** Tpf - pathfinder type */
|
|
|
|
typedef Tpf_ Tpf;
|
|
|
|
/** track follower helper class */
|
|
|
|
typedef Ttrack_follower TrackFollower;
|
|
|
|
/** node list type */
|
|
|
|
typedef Tnode_list NodeList;
|
|
|
|
/** pathfinder components (modules) */
|
|
|
|
typedef CYapfBaseT<Types> PfBase; // base pathfinder class
|
|
|
|
typedef CYapfFollowShipT<Types> PfFollow; // node follower
|
|
|
|
typedef CYapfOriginTileT<Types> PfOrigin; // origin provider
|
|
|
|
typedef CYapfDestinationTileT<Types> PfDestination; // destination/distance provider
|
|
|
|
typedef CYapfSegmentCostCacheNoneT<Types> PfCache; // segment cost cache provider
|
|
|
|
typedef CYapfCostShipT<Types> PfCost; // cost provider
|
|
|
|
};
|
|
|
|
|
2009-03-15 00:32:18 +00:00
|
|
|
/* YAPF type 1 - uses TileIndex/Trackdir as Node key, allows 90-deg turns */
|
2006-05-27 16:12:16 +00:00
|
|
|
struct CYapfShip1 : CYapfT<CYapfShip_TypesT<CYapfShip1, CFollowTrackWater , CShipNodeListTrackDir> > {};
|
2009-03-15 00:32:18 +00:00
|
|
|
/* YAPF type 2 - uses TileIndex/DiagDirection as Node key, allows 90-deg turns */
|
2006-05-27 16:12:16 +00:00
|
|
|
struct CYapfShip2 : CYapfT<CYapfShip_TypesT<CYapfShip2, CFollowTrackWater , CShipNodeListExitDir > > {};
|
2009-03-15 00:32:18 +00:00
|
|
|
/* YAPF type 3 - uses TileIndex/Trackdir as Node key, forbids 90-deg turns */
|
2006-05-27 16:12:16 +00:00
|
|
|
struct CYapfShip3 : CYapfT<CYapfShip_TypesT<CYapfShip3, CFollowTrackWaterNo90, CShipNodeListTrackDir> > {};
|
|
|
|
|
|
|
|
/** Ship controller helper - path finder invoker */
|
2008-06-02 06:44:06 +00:00
|
|
|
Trackdir YapfChooseShipTrack(const Vehicle *v, TileIndex tile, DiagDirection enterdir, TrackBits tracks)
|
2006-05-27 16:12:16 +00:00
|
|
|
{
|
2009-03-15 00:32:18 +00:00
|
|
|
/* default is YAPF type 2 */
|
2008-06-02 06:44:06 +00:00
|
|
|
typedef Trackdir (*PfnChooseShipTrack)(const Vehicle*, TileIndex, DiagDirection, TrackBits);
|
2006-05-27 16:12:16 +00:00
|
|
|
PfnChooseShipTrack pfnChooseShipTrack = CYapfShip2::ChooseShipTrack; // default: ExitDir, allow 90-deg
|
|
|
|
|
2009-03-15 00:32:18 +00:00
|
|
|
/* check if non-default YAPF type needed */
|
2008-06-02 06:44:06 +00:00
|
|
|
if (_settings_game.pf.forbid_90_deg) {
|
2006-05-27 16:12:16 +00:00
|
|
|
pfnChooseShipTrack = &CYapfShip3::ChooseShipTrack; // Trackdir, forbid 90-deg
|
2008-06-02 06:44:06 +00:00
|
|
|
} else if (_settings_game.pf.yapf.disable_node_optimization) {
|
2006-05-27 16:12:16 +00:00
|
|
|
pfnChooseShipTrack = &CYapfShip1::ChooseShipTrack; // Trackdir, allow 90-deg
|
2008-06-02 06:44:06 +00:00
|
|
|
}
|
2006-05-27 16:12:16 +00:00
|
|
|
|
|
|
|
Trackdir td_ret = pfnChooseShipTrack(v, tile, enterdir, tracks);
|
|
|
|
return td_ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** performance measurement helper */
|
2009-03-04 08:02:16 +00:00
|
|
|
void *NpfBeginInterval()
|
2006-05-27 16:12:16 +00:00
|
|
|
{
|
|
|
|
CPerformanceTimer& perf = *new CPerformanceTimer;
|
|
|
|
perf.Start();
|
|
|
|
return &perf;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** performance measurement helper */
|
2008-06-02 06:44:06 +00:00
|
|
|
int NpfEndInterval(void *vperf)
|
2006-05-27 16:12:16 +00:00
|
|
|
{
|
|
|
|
CPerformanceTimer& perf = *(CPerformanceTimer*)vperf;
|
|
|
|
perf.Stop();
|
|
|
|
int t = perf.Get(1000000);
|
|
|
|
delete &perf;
|
|
|
|
return t;
|
|
|
|
}
|