# yapf_ship.cpp

Go to the documentation of this file.

    00001 /* $Id: yapf_ship.cpp 14949 2009-01-10 00:31:47Z rubidium $ */
    00002
    00005 #include "../stdafx.h"
    00006
    00007 #include "yapf.hpp"
    00008
    00010 template <class Types>
    00011 class CYapfFollowShipT
    00012 {
    00013 public:
    00014   typedef typename Types::Tpf Tpf;
    00015   typedef typename Types::TrackFollower TrackFollower;
    00016   typedef typename Types::NodeList::Titem Node;
    00017   typedef typename Node::Key Key;
    00018
    00019 protected:
    00021   FORCEINLINE Tpf& Yapf() {return *static_cast<Tpf*>(this);}
    00022
    00023 public:
    00027   inline void PfFollowNode(Node& old_node)
    00028   {
    00029     TrackFollower F(Yapf().GetVehicle());
    00030     if (F.Follow(old_node.m_key.m_tile, old_node.m_key.m_td))
    00031       Yapf().AddMultipleNodes(&old_node, F);
    00032   }
    00033
    00035   FORCEINLINE char TransportTypeChar() const {return 'w';}
    00036
    00037   static Trackdir ChooseShipTrack(const Vehicle *v, TileIndex tile, DiagDirection enterdir, TrackBits tracks)
    00038   {
    00039     // handle special case - when next tile is destination tile
    00040     if (tile == v->dest_tile) {
    00041       // convert tracks to trackdirs
    00042       TrackdirBits trackdirs = (TrackdirBits)(tracks | ((int)tracks << 8));
    00043       // choose any trackdir reachable from enterdir
    00044       trackdirs &= DiagdirReachesTrackdirs(enterdir);
    00045       return (Trackdir)FindFirstBit2x64(trackdirs);
    00046     }
    00047
    00048     // move back to the old tile/trackdir (where ship is coming from)
    00049     TileIndex src_tile = TILE_ADD(tile, TileOffsByDiagDir(ReverseDiagDir(enterdir)));
    00050     Trackdir trackdir = GetVehicleTrackdir(v);
    00051     assert(IsValidTrackdir(trackdir));
    00052
    00053     // convert origin trackdir to TrackdirBits
    00054     TrackdirBits trackdirs = TrackdirToTrackdirBits(trackdir);
    00055     // get available trackdirs on the destination tile
    00056     TrackdirBits dest_trackdirs = TrackStatusToTrackdirBits(GetTileTrackStatus(v->dest_tile, TRANSPORT_WATER, 0));
    00057
    00058     // create pathfinder instance
    00059     Tpf pf;
    00060     // set origin and destination nodes
    00061     pf.SetOrigin(src_tile, trackdirs);
    00062     pf.SetDestination(v->dest_tile, dest_trackdirs);
    00063     // find best path
    00064     pf.FindPath(v);
    00065
    00066     Trackdir next_trackdir = INVALID_TRACKDIR; // this would mean "path not found"
    00067
    00068     Node *pNode = pf.GetBestNode();
    00069     if (pNode != NULL) {
    00070       // walk through the path back to the origin
    00071       Node *pPrevNode = NULL;
    00072       while (pNode->m_parent != NULL) {
    00073         pPrevNode = pNode;
    00074         pNode = pNode->m_parent;
    00075       }
    00076       // return trackdir from the best next node (direct child of origin)
    00077       Node& best_next_node = *pPrevNode;
    00078       assert(best_next_node.GetTile() == tile);
    00079       next_trackdir = best_next_node.GetTrackdir();
    00080     }
    00081     return next_trackdir;
    00082   }
    00083 };
    00084
    00086 template <class Types>
    00087 class CYapfCostShipT
    00088 {
    00089 public:
    00090   typedef typename Types::Tpf Tpf;
    00091   typedef typename Types::TrackFollower TrackFollower;
    00092   typedef typename Types::NodeList::Titem Node;
    00093   typedef typename Node::Key Key;
    00094
    00095 protected:
    00097   Tpf& Yapf() {return *static_cast<Tpf*>(this);}
    00098
    00099 public:
    00103   FORCEINLINE bool PfCalcCost(Node& n, const TrackFollower *tf)
    00104   {
    00105     // base tile cost depending on distance
    00106     int c = IsDiagonalTrackdir(n.GetTrackdir()) ? 10 : 7;
    00107     // additional penalty for curves
    00108     if (n.m_parent != NULL && n.GetTrackdir() != NextTrackdir(n.m_parent->GetTrackdir())) {
    00109       /* new trackdir does not match the next one when going straight */
    00110       c += 10;
    00111     }
    00112
    00113     c += YAPF_TILE_LENGTH * tf->m_tiles_skipped;
    00114
    00115     // apply it
    00116     n.m_cost = n.m_parent->m_cost + c;
    00117     return true;
    00118   }
    00119 };
    00120
    00124 template <class Tpf_, class Ttrack_follower, class Tnode_list>
    00125 struct CYapfShip_TypesT
    00126 {
    00128   typedef CYapfShip_TypesT<Tpf_, Ttrack_follower, Tnode_list>  Types;
    00129
    00131   typedef Tpf_                              Tpf;
    00133   typedef Ttrack_follower                   TrackFollower;
    00135   typedef Tnode_list                        NodeList;
    00137   typedef CYapfBaseT<Types>                 PfBase;        // base pathfinder class
    00138   typedef CYapfFollowShipT<Types>           PfFollow;      // node follower
    00139   typedef CYapfOriginTileT<Types>           PfOrigin;      // origin provider
    00140   typedef CYapfDestinationTileT<Types>      PfDestination; // destination/distance provider
    00141   typedef CYapfSegmentCostCacheNoneT<Types> PfCache;       // segment cost cache provider
    00142   typedef CYapfCostShipT<Types>             PfCost;        // cost provider
    00143 };
    00144
    00145 // YAPF type 1 - uses TileIndex/Trackdir as Node key, allows 90-deg turns
    00146 struct CYapfShip1 : CYapfT<CYapfShip_TypesT<CYapfShip1, CFollowTrackWater    , CShipNodeListTrackDir> > {};
    00147 // YAPF type 2 - uses TileIndex/DiagDirection as Node key, allows 90-deg turns
    00148 struct CYapfShip2 : CYapfT<CYapfShip_TypesT<CYapfShip2, CFollowTrackWater    , CShipNodeListExitDir > > {};
    00149 // YAPF type 3 - uses TileIndex/Trackdir as Node key, forbids 90-deg turns
    00150 struct CYapfShip3 : CYapfT<CYapfShip_TypesT<CYapfShip3, CFollowTrackWaterNo90, CShipNodeListTrackDir> > {};
    00151
    00153 Trackdir YapfChooseShipTrack(const Vehicle *v, TileIndex tile, DiagDirection enterdir, TrackBits tracks)
    00154 {
    00155   // default is YAPF type 2
    00156   typedef Trackdir (*PfnChooseShipTrack)(const Vehicle*, TileIndex, DiagDirection, TrackBits);
    00157   PfnChooseShipTrack pfnChooseShipTrack = CYapfShip2::ChooseShipTrack; // default: ExitDir, allow 90-deg
    00158
    00159   // check if non-default YAPF type needed
    00160   if (_settings_game.pf.forbid_90_deg) {
    00161     pfnChooseShipTrack = &CYapfShip3::ChooseShipTrack; // Trackdir, forbid 90-deg
    00162   } else if (_settings_game.pf.yapf.disable_node_optimization) {
    00163     pfnChooseShipTrack = &CYapfShip1::ChooseShipTrack; // Trackdir, allow 90-deg
    00164   }
    00165
    00166   Trackdir td_ret = pfnChooseShipTrack(v, tile, enterdir, tracks);
    00167   return td_ret;
    00168 }
    00169
    00171 void * NpfBeginInterval()
    00172 {
    00173   CPerformanceTimer& perf = *new CPerformanceTimer;
    00174   perf.Start();
    00175   return &perf;
    00176 }
    00177
    00179 int NpfEndInterval(void *vperf)
    00180 {
    00181   CPerformanceTimer& perf = *(CPerformanceTimer*)vperf;
    00182   perf.Stop();
    00183   int t = perf.Get(1000000);
    00184   delete &perf;
    00185   return t;
    00186 }