# yapf_ship.cpp

Go to the documentation of this file.

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