 aada042d57
			
		
	
	aada042d57
	
	
	
		
			
			- Trailing whitespace - Trailing empty lines - Missing newline at EOF - Missing svn:eol-style native
		
			
				
	
	
		
			177 lines
		
	
	
		
			6.5 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			177 lines
		
	
	
		
			6.5 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /* $Id$ */
 | |
| 
 | |
| #include "../stdafx.h"
 | |
| 
 | |
| #include "yapf.hpp"
 | |
| 
 | |
| /** Node Follower module of YAPF for ships */
 | |
| template <class Types>
 | |
| class CYapfFollowShipT
 | |
| {
 | |
| public:
 | |
| 	typedef typename Types::Tpf Tpf;                     ///< the pathfinder class (derived from THIS class)
 | |
| 	typedef typename Types::TrackFollower TrackFollower;
 | |
| 	typedef typename Types::NodeList::Titem Node;        ///< this will be our node type
 | |
| 	typedef typename Node::Key Key;                      ///< key to hash tables
 | |
| 
 | |
| protected:
 | |
| 	/// to access inherited path finder
 | |
| 	FORCEINLINE Tpf& Yapf() {return *static_cast<Tpf*>(this);}
 | |
| 
 | |
| public:
 | |
| 	/** Called by YAPF to move from the given node to the next tile. For each
 | |
| 	*   reachable trackdir on the new tile creates new node, initializes it
 | |
| 	*   and adds it to the open list by calling Yapf().AddNewNode(n) */
 | |
| 	inline void PfFollowNode(Node& old_node)
 | |
| 	{
 | |
| 		TrackFollower F;
 | |
| 		if (F.Follow(old_node.m_key.m_tile, old_node.m_key.m_td))
 | |
| 			Yapf().AddMultipleNodes(&old_node, F.m_new_tile, F.m_new_td_bits);
 | |
| 	}
 | |
| 
 | |
| 	/// return debug report character to identify the transportation type
 | |
| 	FORCEINLINE char TransportTypeChar() const {return 'w';}
 | |
| 
 | |
| 	static Trackdir ChooseShipTrack(Vehicle *v, TileIndex tile, DiagDirection enterdir, TrackBits tracks)
 | |
| 	{
 | |
| 		// handle special case - when next tile is destination tile
 | |
| 		if (tile == v->dest_tile) {
 | |
| 			// convert tracks to trackdirs
 | |
| 			TrackdirBits trackdirs = (TrackdirBits)(tracks | ((int)tracks << 8));
 | |
| 			// choose any trackdir reachable from enterdir
 | |
| 			trackdirs &= DiagdirReachesTrackdirs(enterdir);
 | |
| 			return (Trackdir)FindFirstBit2x64(trackdirs);
 | |
| 		}
 | |
| 
 | |
| 		// move back to the old tile/trackdir (where ship is coming from)
 | |
| 		TileIndex src_tile = TILE_ADD(tile, TileOffsByDir(ReverseDiagDir(enterdir)));
 | |
| 		Trackdir trackdir = GetVehicleTrackdir(v);
 | |
| 		assert(IsValidTrackdir(trackdir));
 | |
| 
 | |
| 		// convert origin trackdir to TrackdirBits
 | |
| 		TrackdirBits trackdirs = TrackdirToTrackdirBits(trackdir);
 | |
| 		// get available trackdirs on the destination tile
 | |
| 		TrackdirBits dest_trackdirs = (TrackdirBits)(GetTileTrackStatus(v->dest_tile, TRANSPORT_WATER) & TRACKDIR_BIT_MASK);
 | |
| 
 | |
| 		// create pathfinder instance
 | |
| 		Tpf pf;
 | |
| 		// set origin and destination nodes
 | |
| 		pf.SetOrigin(src_tile, trackdirs);
 | |
| 		pf.SetDestination(v->dest_tile, dest_trackdirs);
 | |
| 		// find best path
 | |
| 		bool bFound = pf.FindPath(v);
 | |
| 
 | |
| 		Trackdir next_trackdir = INVALID_TRACKDIR; // this would mean "path not found"
 | |
| 		if (bFound) {
 | |
| 			// path was found
 | |
| 			// walk through the path back to the origin
 | |
| 			Node* pNode = &pf.GetBestNode();
 | |
| 			Node* pPrevNode = NULL;
 | |
| 			while (pNode->m_parent != NULL) {
 | |
| 				pPrevNode = pNode;
 | |
| 				pNode = pNode->m_parent;
 | |
| 			}
 | |
| 			// return trackdir from the best next node (direct child of origin)
 | |
| 			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:
 | |
| 	typedef typename Types::Tpf Tpf;              ///< the pathfinder class (derived from THIS class)
 | |
| 	typedef typename Types::NodeList::Titem Node; ///< this will be our node type
 | |
| 	typedef typename Node::Key Key;               ///< key to hash tables
 | |
| 
 | |
| protected:
 | |
| 	/// to access inherited path finder
 | |
| 	Tpf& Yapf() {return *static_cast<Tpf*>(this);}
 | |
| 
 | |
| public:
 | |
| 	/** Called by YAPF to calculate the cost from the origin to the given node.
 | |
| 	*   Calculates only the cost of given node, adds it to the parent node cost
 | |
| 	*   and stores the result into Node::m_cost member */
 | |
| 	FORCEINLINE bool PfCalcCost(Node& n)
 | |
| 	{
 | |
| 		// base tile cost depending on distance
 | |
| 		int c = IsDiagonalTrackdir(n.GetTrackdir()) ? 10 : 7;
 | |
| 		// additional penalty for curves
 | |
| 		if (n.m_parent != NULL && n.GetTrackdir() != n.m_parent->GetTrackdir()) c += 3;
 | |
| 		// apply it
 | |
| 		n.m_cost = n.m_parent->m_cost + c;
 | |
| 		return true;
 | |
| 	}
 | |
| };
 | |
| 
 | |
| /** Config struct of YAPF for ships.
 | |
| 		Defines all 6 base YAPF modules as classes providing services for CYapfBaseT.
 | |
| */
 | |
| 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
 | |
| };
 | |
| 
 | |
| // YAPF type 1 - uses TileIndex/Trackdir as Node key, allows 90-deg turns
 | |
| struct CYapfShip1 : CYapfT<CYapfShip_TypesT<CYapfShip1, CFollowTrackWater    , CShipNodeListTrackDir> > {};
 | |
| // YAPF type 2 - uses TileIndex/DiagDirection as Node key, allows 90-deg turns
 | |
| struct CYapfShip2 : CYapfT<CYapfShip_TypesT<CYapfShip2, CFollowTrackWater    , CShipNodeListExitDir > > {};
 | |
| // YAPF type 3 - uses TileIndex/Trackdir as Node key, forbids 90-deg turns
 | |
| struct CYapfShip3 : CYapfT<CYapfShip_TypesT<CYapfShip3, CFollowTrackWaterNo90, CShipNodeListTrackDir> > {};
 | |
| 
 | |
| /** Ship controller helper - path finder invoker */
 | |
| Trackdir YapfChooseShipTrack(Vehicle *v, TileIndex tile, DiagDirection enterdir, TrackBits tracks)
 | |
| {
 | |
| 	// default is YAPF type 2
 | |
| 	typedef Trackdir (*PfnChooseShipTrack)(Vehicle*, TileIndex, DiagDirection, TrackBits);
 | |
| 	PfnChooseShipTrack pfnChooseShipTrack = CYapfShip2::ChooseShipTrack; // default: ExitDir, allow 90-deg
 | |
| 
 | |
| 	// check if non-default YAPF type needed
 | |
| 	if (_patches.forbid_90_deg)
 | |
| 		pfnChooseShipTrack = &CYapfShip3::ChooseShipTrack; // Trackdir, forbid 90-deg
 | |
| 	else if (_patches.yapf.disable_node_optimization)
 | |
| 		pfnChooseShipTrack = &CYapfShip1::ChooseShipTrack; // Trackdir, allow 90-deg
 | |
| 
 | |
| 	Trackdir td_ret = pfnChooseShipTrack(v, tile, enterdir, tracks);
 | |
| 	return td_ret;
 | |
| }
 | |
| 
 | |
| /** performance measurement helper */
 | |
| void* NpfBeginInterval()
 | |
| {
 | |
| 	CPerformanceTimer& perf = *new CPerformanceTimer;
 | |
| 	perf.Start();
 | |
| 	return &perf;
 | |
| }
 | |
| 
 | |
| /** performance measurement helper */
 | |
| int NpfEndInterval(void* vperf)
 | |
| {
 | |
| 	CPerformanceTimer& perf = *(CPerformanceTimer*)vperf;
 | |
| 	perf.Stop();
 | |
| 	int t = perf.Get(1000000);
 | |
| 	delete &perf;
 | |
| 	return t;
 | |
| }
 |