yapf_ship.cpp

Go to the documentation of this file.
00001 /* $Id: yapf_ship.cpp 12199 2008-02-20 17:49:50Z frosch $ */
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(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     // apply it
00113     n.m_cost = n.m_parent->m_cost + c;
00114     return true;
00115   }
00116 };
00117 
00121 template <class Tpf_, class Ttrack_follower, class Tnode_list>
00122 struct CYapfShip_TypesT
00123 {
00125   typedef CYapfShip_TypesT<Tpf_, Ttrack_follower, Tnode_list>  Types;
00126 
00128   typedef Tpf_                              Tpf;
00130   typedef Ttrack_follower                   TrackFollower;
00132   typedef Tnode_list                        NodeList;
00134   typedef CYapfBaseT<Types>                 PfBase;        // base pathfinder class
00135   typedef CYapfFollowShipT<Types>           PfFollow;      // node follower
00136   typedef CYapfOriginTileT<Types>           PfOrigin;      // origin provider
00137   typedef CYapfDestinationTileT<Types>      PfDestination; // destination/distance provider
00138   typedef CYapfSegmentCostCacheNoneT<Types> PfCache;       // segment cost cache provider
00139   typedef CYapfCostShipT<Types>             PfCost;        // cost provider
00140 };
00141 
00142 // YAPF type 1 - uses TileIndex/Trackdir as Node key, allows 90-deg turns
00143 struct CYapfShip1 : CYapfT<CYapfShip_TypesT<CYapfShip1, CFollowTrackWater    , CShipNodeListTrackDir> > {};
00144 // YAPF type 2 - uses TileIndex/DiagDirection as Node key, allows 90-deg turns
00145 struct CYapfShip2 : CYapfT<CYapfShip_TypesT<CYapfShip2, CFollowTrackWater    , CShipNodeListExitDir > > {};
00146 // YAPF type 3 - uses TileIndex/Trackdir as Node key, forbids 90-deg turns
00147 struct CYapfShip3 : CYapfT<CYapfShip_TypesT<CYapfShip3, CFollowTrackWaterNo90, CShipNodeListTrackDir> > {};
00148 
00150 Trackdir YapfChooseShipTrack(Vehicle *v, TileIndex tile, DiagDirection enterdir, TrackBits tracks)
00151 {
00152   // default is YAPF type 2
00153   typedef Trackdir (*PfnChooseShipTrack)(Vehicle*, TileIndex, DiagDirection, TrackBits);
00154   PfnChooseShipTrack pfnChooseShipTrack = CYapfShip2::ChooseShipTrack; // default: ExitDir, allow 90-deg
00155 
00156   // check if non-default YAPF type needed
00157   if (_patches.forbid_90_deg)
00158     pfnChooseShipTrack = &CYapfShip3::ChooseShipTrack; // Trackdir, forbid 90-deg
00159   else if (_patches.yapf.disable_node_optimization)
00160     pfnChooseShipTrack = &CYapfShip1::ChooseShipTrack; // Trackdir, allow 90-deg
00161 
00162   Trackdir td_ret = pfnChooseShipTrack(v, tile, enterdir, tracks);
00163   return td_ret;
00164 }
00165 
00167 void* NpfBeginInterval()
00168 {
00169   CPerformanceTimer& perf = *new CPerformanceTimer;
00170   perf.Start();
00171   return &perf;
00172 }
00173 
00175 int NpfEndInterval(void* vperf)
00176 {
00177   CPerformanceTimer& perf = *(CPerformanceTimer*)vperf;
00178   perf.Stop();
00179   int t = perf.Get(1000000);
00180   delete &perf;
00181   return t;
00182 }

Generated on Mon Sep 22 20:34:21 2008 for openttd by  doxygen 1.5.6