00001
00002
00005 #include "../stdafx.h"
00006
00007 #include "yapf.hpp"
00008 #include "yapf_node_rail.hpp"
00009 #include "yapf_costrail.hpp"
00010 #include "yapf_destrail.hpp"
00011 #include "../vehicle_func.h"
00012
00013 #define DEBUG_YAPF_CACHE 0
00014
00015 int _total_pf_time_us = 0;
00016
00017
00018
00019
00020
00021 template <class Types>
00022 class CYapfFollowAnyDepotRailT
00023 {
00024 public:
00025 typedef typename Types::Tpf Tpf;
00026 typedef typename Types::TrackFollower TrackFollower;
00027 typedef typename Types::NodeList::Titem Node;
00028 typedef typename Node::Key Key;
00029
00030 protected:
00032 FORCEINLINE Tpf& Yapf() {return *static_cast<Tpf*>(this);}
00033
00034 public:
00038 inline void PfFollowNode(Node& old_node)
00039 {
00040 TrackFollower F(Yapf().GetVehicle());
00041 if (F.Follow(old_node.GetLastTile(), old_node.GetLastTrackdir()))
00042 Yapf().AddMultipleNodes(&old_node, F);
00043 }
00044
00046 FORCEINLINE char TransportTypeChar() const {return 't';}
00047
00048 static bool stFindNearestDepotTwoWay(Vehicle *v, TileIndex t1, Trackdir td1, TileIndex t2, Trackdir td2, int max_distance, int reverse_penalty, TileIndex* depot_tile, bool* reversed)
00049 {
00050 Tpf pf1;
00051 bool result1 = pf1.FindNearestDepotTwoWay(v, t1, td1, t2, td2, max_distance, reverse_penalty, depot_tile, reversed);
00052
00053 #if DEBUG_YAPF_CACHE
00054 Tpf pf2;
00055 TileIndex depot_tile2 = INVALID_TILE;
00056 bool reversed2 = false;
00057 pf2.DisableCache(true);
00058 bool result2 = pf2.FindNearestDepotTwoWay(v, t1, td1, t2, td2, max_distance, reverse_penalty, &depot_tile2, &reversed2);
00059 if (result1 != result2 || (result1 && (*depot_tile != depot_tile2 || *reversed != reversed2))) {
00060 DEBUG(yapf, 0, "CACHE ERROR: FindNearestDepotTwoWay() = [%s, %s]", result1 ? "T" : "F", result2 ? "T" : "F");
00061 }
00062 #endif
00063
00064 return result1;
00065 }
00066
00067 FORCEINLINE bool FindNearestDepotTwoWay(Vehicle *v, TileIndex t1, Trackdir td1, TileIndex t2, Trackdir td2, int max_distance, int reverse_penalty, TileIndex* depot_tile, bool* reversed)
00068 {
00069
00070 Yapf().SetOrigin(t1, td1, t2, td2, reverse_penalty, true);
00071 Yapf().SetDestination(v);
00072 Yapf().SetMaxCost(YAPF_TILE_LENGTH * max_distance);
00073
00074
00075 bool bFound = Yapf().FindPath(v);
00076 if (!bFound) return false;
00077
00078
00079
00080 Node *n = Yapf().GetBestNode();
00081 *depot_tile = n->GetLastTile();
00082
00083
00084 Node *pNode = n;
00085 while (pNode->m_parent != NULL) {
00086 pNode = pNode->m_parent;
00087 }
00088
00089
00090
00091 *reversed = (pNode->m_cost != 0);
00092
00093 return true;
00094 }
00095 };
00096
00097 template <class Types>
00098 class CYapfFollowRailT
00099 {
00100 public:
00101 typedef typename Types::Tpf Tpf;
00102 typedef typename Types::TrackFollower TrackFollower;
00103 typedef typename Types::NodeList::Titem Node;
00104 typedef typename Node::Key Key;
00105
00106 protected:
00108 FORCEINLINE Tpf& Yapf() {return *static_cast<Tpf*>(this);}
00109
00110 public:
00114 inline void PfFollowNode(Node& old_node)
00115 {
00116 TrackFollower F(Yapf().GetVehicle());
00117 if (F.Follow(old_node.GetLastTile(), old_node.GetLastTrackdir()))
00118 Yapf().AddMultipleNodes(&old_node, F);
00119 }
00120
00122 FORCEINLINE char TransportTypeChar() const {return 't';}
00123
00124 static Trackdir stChooseRailTrack(Vehicle *v, TileIndex tile, DiagDirection enterdir, TrackBits tracks, bool *path_not_found)
00125 {
00126
00127 Tpf pf1;
00128 Trackdir result1 = pf1.ChooseRailTrack(v, tile, enterdir, tracks, path_not_found);
00129
00130 #if DEBUG_YAPF_CACHE
00131 Tpf pf2;
00132 pf2.DisableCache(true);
00133 Trackdir result2 = pf2.ChooseRailTrack(v, tile, enterdir, tracks, path_not_found);
00134 if (result1 != result2) {
00135 DEBUG(yapf, 0, "CACHE ERROR: ChooseRailTrack() = [%d, %d]", result1, result2);
00136 DumpTarget dmp1, dmp2;
00137 pf1.DumpBase(dmp1);
00138 pf2.DumpBase(dmp2);
00139 FILE *f1 = fopen("C:\\yapf1.txt", "wt");
00140 FILE *f2 = fopen("C:\\yapf2.txt", "wt");
00141 fwrite(dmp1.m_out.Data(), 1, dmp1.m_out.Size(), f1);
00142 fwrite(dmp2.m_out.Data(), 1, dmp2.m_out.Size(), f2);
00143 fclose(f1);
00144 fclose(f2);
00145 }
00146 #endif
00147
00148 return result1;
00149 }
00150
00151 FORCEINLINE Trackdir ChooseRailTrack(Vehicle *v, TileIndex tile, DiagDirection enterdir, TrackBits tracks, bool *path_not_found)
00152 {
00153
00154 Yapf().SetOrigin(v->tile, GetVehicleTrackdir(v), INVALID_TILE, INVALID_TRACKDIR, 1, true);
00155 Yapf().SetDestination(v);
00156
00157
00158 bool path_found = Yapf().FindPath(v);
00159 if (path_not_found != NULL) {
00160
00161
00162 *path_not_found = !(path_found || Yapf().m_stopped_on_first_two_way_signal);
00163 }
00164
00165
00166 Trackdir next_trackdir = INVALID_TRACKDIR;
00167 Node *pNode = Yapf().GetBestNode();
00168 if (pNode != NULL) {
00169
00170
00171 Node* pPrev = NULL;
00172 while (pNode->m_parent != NULL) {
00173 pPrev = pNode;
00174 pNode = pNode->m_parent;
00175 }
00176
00177 Node& best_next_node = *pPrev;
00178 assert(best_next_node.GetTile() == tile);
00179 next_trackdir = best_next_node.GetTrackdir();
00180 }
00181 return next_trackdir;
00182 }
00183
00184 static bool stCheckReverseTrain(Vehicle* v, TileIndex t1, Trackdir td1, TileIndex t2, Trackdir td2, int reverse_penalty)
00185 {
00186 Tpf pf1;
00187 bool result1 = pf1.CheckReverseTrain(v, t1, td1, t2, td2, reverse_penalty);
00188
00189 #if DEBUG_YAPF_CACHE
00190 Tpf pf2;
00191 pf2.DisableCache(true);
00192 bool result2 = pf2.CheckReverseTrain(v, t1, td1, t2, td2, reverse_penalty);
00193 if (result1 != result2) {
00194 DEBUG(yapf, 0, "CACHE ERROR: CheckReverseTrain() = [%s, %s]", result1 ? "T" : "F", result2 ? "T" : "F");
00195 }
00196 #endif
00197
00198 return result1;
00199 }
00200
00201 FORCEINLINE bool CheckReverseTrain(Vehicle* v, TileIndex t1, Trackdir td1, TileIndex t2, Trackdir td2, int reverse_penalty)
00202 {
00203
00204
00205 Yapf().SetOrigin(t1, td1, t2, td2, reverse_penalty, false);
00206 Yapf().SetDestination(v);
00207
00208
00209 bool bFound = Yapf().FindPath(v);
00210
00211 if (!bFound) return false;
00212
00213
00214
00215 Node *pNode = Yapf().GetBestNode();
00216 while (pNode->m_parent != NULL) {
00217 pNode = pNode->m_parent;
00218 }
00219
00220
00221 Node& best_org_node = *pNode;
00222 bool reversed = (best_org_node.m_cost != 0);
00223 return reversed;
00224 }
00225 };
00226
00227 template <class Tpf_, class Ttrack_follower, class Tnode_list, template <class Types> class TdestinationT, template <class Types> class TfollowT>
00228 struct CYapfRail_TypesT
00229 {
00230 typedef CYapfRail_TypesT<Tpf_, Ttrack_follower, Tnode_list, TdestinationT, TfollowT> Types;
00231
00232 typedef Tpf_ Tpf;
00233 typedef Ttrack_follower TrackFollower;
00234 typedef Tnode_list NodeList;
00235 typedef CYapfBaseT<Types> PfBase;
00236 typedef TfollowT<Types> PfFollow;
00237 typedef CYapfOriginTileTwoWayT<Types> PfOrigin;
00238 typedef TdestinationT<Types> PfDestination;
00239 typedef CYapfSegmentCostCacheGlobalT<Types> PfCache;
00240 typedef CYapfCostRailT<Types> PfCost;
00241 };
00242
00243 struct CYapfRail1 : CYapfT<CYapfRail_TypesT<CYapfRail1 , CFollowTrackRail , CRailNodeListTrackDir, CYapfDestinationTileOrStationRailT, CYapfFollowRailT> > {};
00244 struct CYapfRail2 : CYapfT<CYapfRail_TypesT<CYapfRail2 , CFollowTrackRailNo90, CRailNodeListTrackDir, CYapfDestinationTileOrStationRailT, CYapfFollowRailT> > {};
00245
00246 struct CYapfAnyDepotRail1 : CYapfT<CYapfRail_TypesT<CYapfAnyDepotRail1, CFollowTrackRail , CRailNodeListTrackDir, CYapfDestinationAnyDepotRailT , CYapfFollowAnyDepotRailT> > {};
00247 struct CYapfAnyDepotRail2 : CYapfT<CYapfRail_TypesT<CYapfAnyDepotRail2, CFollowTrackRailNo90, CRailNodeListTrackDir, CYapfDestinationAnyDepotRailT , CYapfFollowAnyDepotRailT> > {};
00248
00249
00250 Trackdir YapfChooseRailTrack(Vehicle *v, TileIndex tile, DiagDirection enterdir, TrackBits tracks, bool *path_not_found)
00251 {
00252
00253 typedef Trackdir (*PfnChooseRailTrack)(Vehicle*, TileIndex, DiagDirection, TrackBits, bool*);
00254 PfnChooseRailTrack pfnChooseRailTrack = &CYapfRail1::stChooseRailTrack;
00255
00256
00257 if (_patches.forbid_90_deg) {
00258 pfnChooseRailTrack = &CYapfRail2::stChooseRailTrack;
00259 }
00260
00261 Trackdir td_ret = pfnChooseRailTrack(v, tile, enterdir, tracks, path_not_found);
00262
00263 return td_ret;
00264 }
00265
00266 bool YapfCheckReverseTrain(Vehicle* v)
00267 {
00268
00269 Vehicle* last_veh = GetLastVehicleInChain(v);
00270
00271
00272 Trackdir td = GetVehicleTrackdir(v);
00273 Trackdir td_rev = ReverseTrackdir(GetVehicleTrackdir(last_veh));
00274
00275
00276 TileIndex tile = v->tile;
00277 TileIndex tile_rev = last_veh->tile;
00278
00279 int reverse_penalty = 0;
00280
00281 if (v->u.rail.track == TRACK_BIT_WORMHOLE) {
00282
00283 DiagDirection dir_into_wormhole = GetTunnelBridgeDirection(tile);
00284
00285 if (TrackdirToExitdir(td) == dir_into_wormhole) tile = GetOtherTunnelBridgeEnd(tile);
00286
00287
00288
00289 TileIndex cur_tile = TileVirtXY(v->x_pos, v->y_pos);
00290
00291
00292
00293 reverse_penalty -= DistanceManhattan(cur_tile, tile) * YAPF_TILE_LENGTH;
00294 }
00295
00296 if (last_veh->u.rail.track == TRACK_BIT_WORMHOLE) {
00297
00298 DiagDirection dir_into_wormhole = GetTunnelBridgeDirection(tile_rev);
00299
00300 if (TrackdirToExitdir(td_rev) == dir_into_wormhole) tile_rev = GetOtherTunnelBridgeEnd(tile_rev);
00301
00302
00303
00304 TileIndex cur_tile = TileVirtXY(last_veh->x_pos, last_veh->y_pos);
00305
00306
00307 reverse_penalty += DistanceManhattan(cur_tile, tile_rev) * YAPF_TILE_LENGTH;
00308 }
00309
00310 typedef bool (*PfnCheckReverseTrain)(Vehicle*, TileIndex, Trackdir, TileIndex, Trackdir, int);
00311 PfnCheckReverseTrain pfnCheckReverseTrain = CYapfRail1::stCheckReverseTrain;
00312
00313
00314 if (_patches.forbid_90_deg) {
00315 pfnCheckReverseTrain = &CYapfRail2::stCheckReverseTrain;
00316 }
00317
00318
00319 if (reverse_penalty == 0) reverse_penalty = 1;
00320
00321 bool reverse = pfnCheckReverseTrain(v, tile, td, tile_rev, td_rev, reverse_penalty);
00322
00323 return reverse;
00324 }
00325
00326 bool YapfFindNearestRailDepotTwoWay(Vehicle *v, int max_distance, int reverse_penalty, TileIndex* depot_tile, bool* reversed)
00327 {
00328 *depot_tile = INVALID_TILE;
00329 *reversed = false;
00330
00331 Vehicle* last_veh = GetLastVehicleInChain(v);
00332
00333 TileIndex tile = v->tile;
00334 TileIndex last_tile = last_veh->tile;
00335
00336
00337 Trackdir td = GetVehicleTrackdir(v);
00338 Trackdir td_rev = ReverseTrackdir(GetVehicleTrackdir(last_veh));
00339
00340 typedef bool (*PfnFindNearestDepotTwoWay)(Vehicle*, TileIndex, Trackdir, TileIndex, Trackdir, int, int, TileIndex*, bool*);
00341 PfnFindNearestDepotTwoWay pfnFindNearestDepotTwoWay = &CYapfAnyDepotRail1::stFindNearestDepotTwoWay;
00342
00343
00344 if (_patches.forbid_90_deg) {
00345 pfnFindNearestDepotTwoWay = &CYapfAnyDepotRail2::stFindNearestDepotTwoWay;
00346 }
00347
00348 bool ret = pfnFindNearestDepotTwoWay(v, tile, td, last_tile, td_rev, max_distance, reverse_penalty, depot_tile, reversed);
00349 return ret;
00350 }
00351
00353 int CSegmentCostCacheBase::s_rail_change_counter = 0;
00354
00355 void YapfNotifyTrackLayoutChange(TileIndex tile, Track track) {CSegmentCostCacheBase::NotifyTrackLayoutChange(tile, track);}