00001
00002
00003
00004
00005
00006
00007
00008
00009
00012 #include "../../stdafx.h"
00013 #include "../../cargodest_base.h"
00014 #include "../../station_base.h"
00015 #include "../../town.h"
00016 #include "yapf.hpp"
00017
00018
00020 struct CYapfRouteLinkNodeKeyT {
00021 RouteLink *m_link;
00022
00024 FORCEINLINE void Set(RouteLink *link)
00025 {
00026 this->m_link = link;
00027 }
00028
00030 FORCEINLINE int CalcHash() const
00031 {
00032 return (int)(size_t)this->m_link >> 4;
00033 }
00034
00035 FORCEINLINE bool operator == (const CYapfRouteLinkNodeKeyT& other) const
00036 {
00037 return this->m_link == other.m_link;
00038 }
00039
00040 void Dump(DumpTarget &dmp) const
00041 {
00042 dmp.WriteLine("m_link = %u", this->m_link->GetDestination());
00043 }
00044 };
00045
00047 struct CYapfRouteLinkNodeT : public CYapfNodeT<CYapfRouteLinkNodeKeyT, CYapfRouteLinkNodeT> {
00048 typedef CYapfNodeT<CYapfRouteLinkNodeKeyT, CYapfRouteLinkNodeT> Base;
00049
00050 uint m_num_transfers;
00051
00053 FORCEINLINE void Set(CYapfRouteLinkNodeT *parent, RouteLink *link)
00054 {
00055 Base::Set(parent, false);
00056 this->m_key.Set(link);
00057 this->m_num_transfers = (parent != NULL) ? parent->m_num_transfers : 0;
00058 }
00059
00061 FORCEINLINE RouteLink *GetRouteLink() const { return this->m_key.m_link; }
00062
00064 FORCEINLINE int GetNumberOfTransfers() const { return this->m_num_transfers; }
00065 };
00066
00067 typedef CNodeList_HashTableT<CYapfRouteLinkNodeT, 8, 10, 2048> CRouteLinkNodeList;
00068
00070 struct CFollowRouteLinkT {
00071 CargoID m_cid;
00072 RouteLink *m_old_link;
00073 RouteLinkList *m_new_links;
00074
00075 CFollowRouteLinkT(CargoID cid) : m_cid(cid) {}
00076
00078 inline bool Follow(RouteLink *from)
00079 {
00080 this->m_old_link = from;
00081
00082 Station *st = Station::Get(from->GetDestination());
00083 m_new_links = &st->goods[this->m_cid].routes;
00084 return !this->m_new_links->empty();
00085 }
00086 };
00087
00089 template <class Types>
00090 class CYapfCostRouteLinkT {
00091 typedef typename Types::Tpf Tpf;
00092 typedef typename Types::TrackFollower Follower;
00093 typedef typename Types::NodeList::Titem Node;
00094
00095 static const int PENALTY_DIVISOR = 16;
00096 static const int LOCAL_PENALTY_FACTOR = 16;
00097 static const int RF_DISTANCE_FACTOR = 2;
00098 static const int RF_TIME_FACTOR = 3;
00099
00101 FORCEINLINE Tpf& Yapf() { return *static_cast<Tpf*>(this); }
00102 FORCEINLINE const Tpf& Yapf() const { return *static_cast<const Tpf*>(this); }
00103
00105 FORCEINLINE bool ValidLink(Node &n, const RouteLink *link, const RouteLink *parent) const
00106 {
00107
00108
00109
00110 if (parent->GetOwner() != INVALID_OWNER && link->GetOwner() != parent->GetOwner()) return false;
00111
00112
00113 if (link->GetOriginOrderId() != parent->GetDestOrderId() || (Order::Get(link->GetOriginOrderId())->GetUnloadType() & OUFB_UNLOAD) != 0) {
00114
00115 if ((Order::Get(link->GetOriginOrderId())->GetLoadType() & OLFB_NO_LOAD) != 0) return false;
00116
00117
00118 if (parent->GetDestOrderId() != INVALID_ORDER && (Order::Get(parent->GetDestOrderId())->GetUnloadType() & OUFB_NO_UNLOAD) != 0) return false;
00119
00120
00121 if (++n.m_num_transfers > Yapf().PfGetSettings().route_max_transfers) return false;
00122 }
00123
00124 return true;
00125 }
00126
00128 FORCEINLINE int RouteLinkCost(const RouteLink *link, const RouteLink *parent) const
00129 {
00130 int cost = 0;
00131
00132
00133 const Station *from = Station::Get(parent->GetDestination());
00134 const Station *to = Station::Get(link->GetDestination());
00135 cost = DistanceManhattan(from->xy, to->xy) * this->Yapf().PfGetSettings().route_distance_factor;
00136
00137
00138
00139
00140 assert_compile(lengthof(_settings_game.pf.yapf.route_mode_cost_factor) == VEH_AIRCRAFT + 1);
00141 byte dfactor = this->Yapf().PfGetSettings().route_mode_cost_factor[link->GetVehicleType()];
00142 if (HasBit(this->Yapf().GetFlags(), RF_WANT_CHEAP)) dfactor *= RF_DISTANCE_FACTOR;
00143 cost *= dfactor;
00144
00145
00146 uint time_factor = HasBit(this->Yapf().GetFlags(), RF_WANT_FAST) ? RF_TIME_FACTOR : 1;
00147
00148
00149 if (link->GetOriginOrderId() != parent->GetDestOrderId() || (Order::Get(link->GetOriginOrderId())->GetUnloadType() & OUFB_UNLOAD) != 0) {
00150 cost += this->Yapf().PfGetSettings().route_transfer_cost;
00151
00152
00153 cost += link->GetWaitTime() * this->Yapf().PfGetSettings().route_station_last_veh_factor * time_factor / PENALTY_DIVISOR;
00154
00155
00156 cost += (from->goods[this->Yapf().GetCargoID()].cargo.CountForNextHop(link->GetOriginOrderId()) * this->Yapf().PfGetSettings().route_station_waiting_factor) / PENALTY_DIVISOR;
00157 }
00158
00159
00160 cost += (link->GetTravelTime() * this->Yapf().PfGetSettings().route_travel_time_factor * time_factor) / PENALTY_DIVISOR;
00161
00162 return cost;
00163 }
00164
00165 public:
00167 inline bool PfCalcCost(Node& n, const Follower *follow)
00168 {
00169 int segment_cost = 0;
00170
00171 if (this->Yapf().PfDetectDestination(n)) {
00172 Station *st = Station::Get(n.m_parent->GetRouteLink()->GetDestination());
00173
00174 if (!HasBit(st->goods[follow->m_cid].acceptance_pickup, GoodsEntry::ACCEPTANCE)) return false;
00175
00176 segment_cost += this->Yapf().DeliveryCost(st);
00177
00178
00179 if (n.m_parent->GetRouteLink()->GetDestOrderId() == INVALID_ORDER) segment_cost *= LOCAL_PENALTY_FACTOR;
00180 } else {
00181 RouteLink *link = n.GetRouteLink();
00182 RouteLink *parent = n.m_parent->GetRouteLink();
00183
00184
00185 if (!this->ValidLink(n, link, parent)) return false;
00186
00187
00188 segment_cost += this->RouteLinkCost(link, parent);
00189 }
00190
00191
00192 n.m_cost = n.m_parent->m_cost + segment_cost;
00193 return n.m_cost <= this->Yapf().GetMaxCost();
00194 }
00195 };
00196
00198 template <class Types>
00199 class CYapfOriginRouteLinkT {
00200 typedef typename Types::Tpf Tpf;
00201 typedef typename Types::NodeList::Titem Node;
00202
00203 CargoID m_cid;
00204 TileIndex m_src;
00205 OrderID m_order;
00206 byte m_flags;
00207 SmallVector<RouteLink, 2> m_origin;
00208
00210 FORCEINLINE Tpf& Yapf() { return *static_cast<Tpf*>(this); }
00211
00212 public:
00214 FORCEINLINE CargoID GetCargoID() const
00215 {
00216 return this->m_cid;
00217 }
00218
00220 FORCEINLINE byte GetFlags() const
00221 {
00222 return this->m_flags;
00223 }
00224
00226 void SetOrigin(CargoID cid, TileIndex src, const StationList *stations, bool cargo_creation, OrderID order, byte flags)
00227 {
00228 this->m_cid = cid;
00229 this->m_src = src;
00230 this->m_order = order;
00231 this->m_flags = flags;
00232
00233 for (const Station * const *st = stations->Begin(); st != stations->End(); st++) {
00234 if (cargo_creation) {
00235
00236 if ((*st)->town->exclusive_counter > 0 && (*st)->town->exclusivity != (*st)->owner) continue;
00237
00238 if (_settings_game.order.selectgoods && (*st)->goods[cid].last_speed == 0) continue;
00239 }
00240
00241 *this->m_origin.Append() = RouteLink((*st)->index, INVALID_ORDER, this->m_order);
00242 }
00243 }
00244
00246 void PfSetStartupNodes()
00247 {
00248 for (RouteLink *link = this->m_origin.Begin(); link != this->m_origin.End(); link++) {
00249 Node &n = this->Yapf().CreateNewNode();
00250 n.Set(NULL, link);
00251
00252 n.m_cost = DistanceSquare(this->m_src, Station::Get(link->GetDestination())->xy) * this->Yapf().PfGetSettings().route_distance_factor;
00253 this->Yapf().AddStartupNode(n);
00254 }
00255 }
00256 };
00257
00259 template <class Types>
00260 class CYapfDestinationRouteLinkT {
00261 typedef typename Types::Tpf Tpf;
00262 typedef typename Types::NodeList::Titem Node;
00263
00264 TileArea m_dest;
00265 int m_max_cost;
00266
00268 FORCEINLINE Tpf& Yapf() { return *static_cast<Tpf*>(this); }
00269
00270 public:
00272 FORCEINLINE int GetMaxCost() const
00273 {
00274 return this->m_max_cost;
00275 }
00276
00278 void SetDestination(const TileArea &dest, uint max_cost)
00279 {
00280 this->m_dest = dest;
00281 this->m_max_cost = max_cost;
00282 }
00283
00285 FORCEINLINE int DeliveryCost(Station *st)
00286 {
00287 int x = TileX(this->m_dest.tile);
00288 int y = TileY(this->m_dest.tile);
00289
00290
00291 if (st->rect.PtInExtendedRect(x, y)) return 0;
00292
00293 int dist_x = x < st->rect.left ? x - st->rect.left : x - st->rect.right;
00294 int dist_y = y < st->rect.top ? y - st->rect.top : y - st->rect.bottom;
00295
00296 return (dist_x * dist_x + dist_y * dist_y) * this->Yapf().PfGetSettings().route_distance_factor;
00297 }
00298
00300 FORCEINLINE bool PfDetectDestination(StationID st_id) const
00301 {
00302 const Station *st = Station::Get(st_id);
00303 return st->rect.AreaInExtendedRect(this->m_dest, st->GetCatchmentRadius());
00304 }
00305
00307 FORCEINLINE bool PfDetectDestination(const Node& n) const
00308 {
00309 return n.GetRouteLink() == NULL;
00310 }
00311
00313 FORCEINLINE bool PfCalcEstimate(Node& n)
00314 {
00315 if (this->PfDetectDestination(n)) {
00316 n.m_estimate = n.m_cost;
00317 return true;
00318 }
00319
00320
00321 Station *from = Station::Get(n.GetRouteLink()->GetDestination());
00322 int d = DistanceManhattan(from->xy, this->m_dest.tile) * this->Yapf().PfGetSettings().route_distance_factor;
00323
00324 n.m_estimate = n.m_cost + d;
00325 assert(n.m_estimate >= n.m_parent->m_estimate);
00326 return true;
00327 }
00328 };
00329
00331 template <class Types>
00332 class CYapfFollowRouteLinkT {
00333 typedef typename Types::Tpf Tpf;
00334 typedef typename Types::TrackFollower Follower;
00335 typedef typename Types::NodeList::Titem Node;
00336
00338 FORCEINLINE Tpf& Yapf() { return *static_cast<Tpf*>(this); }
00339
00340 public:
00342 inline void PfFollowNode(Node& old_node)
00343 {
00344 Follower f(this->Yapf().GetCargoID());
00345
00346 if (this->Yapf().PfDetectDestination(old_node.GetRouteLink()->GetDestination()) && (old_node.GetRouteLink()->GetDestOrderId() == INVALID_ORDER || (Order::Get(old_node.GetRouteLink()->GetDestOrderId())->GetUnloadType() & OUFB_NO_UNLOAD) == 0)) {
00347
00348 Node &n = this->Yapf().CreateNewNode();
00349 n.Set(&old_node, NULL);
00350 this->Yapf().AddNewNode(n, f);
00351 }
00352
00353 if (f.Follow(old_node.GetRouteLink())) {
00354 for (RouteLinkList::iterator link = f.m_new_links->begin(); link != f.m_new_links->end(); ++link) {
00355
00356 Node &n = this->Yapf().CreateNewNode();
00357 n.Set(&old_node, *link);
00358 this->Yapf().AddNewNode(n, f);
00359 }
00360 }
00361 }
00362
00364 FORCEINLINE char TransportTypeChar() const
00365 {
00366 return 'c';
00367 }
00368
00370 static RouteLink *ChooseRouteLink(CargoID cid, const StationList *stations, TileIndex src, const TileArea &dest, StationID *start_station, StationID *next_unload, byte flags, bool *found, OrderID order, int max_cost)
00371 {
00372
00373 Tpf pf;
00374 pf.SetOrigin(cid, src, stations, start_station != NULL, order, flags);
00375 pf.SetDestination(dest, max_cost);
00376
00377 *next_unload = INVALID_STATION;
00378
00379
00380 bool res = pf.FindPath(NULL);
00381 if (found != NULL) *found = res;
00382 if (!res) return NULL;
00383
00384
00385 Node *node = pf.GetBestNode();
00386 while (node->m_parent->m_parent != NULL) {
00387
00388 if (node->GetRouteLink() == NULL || (node->GetRouteLink()->GetOriginOrderId() != node->m_parent->GetRouteLink()->GetDestOrderId())) {
00389 *next_unload = node->m_parent->GetRouteLink()->GetDestination();
00390 }
00391
00392 node = node->m_parent;
00393 }
00394
00395
00396 if (start_station != NULL) {
00397 *start_station = node->m_parent->GetRouteLink()->GetDestination();
00398
00399 if (*start_station == pf.GetBestNode()->m_parent->GetRouteLink()->GetDestination()) return NULL;
00400 }
00401 return node->GetRouteLink();
00402 }
00403 };
00404
00406 template <class Tpf_>
00407 struct CYapfRouteLink_TypesT {
00408 typedef CYapfRouteLink_TypesT<Tpf_> Types;
00409
00410 typedef Tpf_ Tpf;
00411 typedef CFollowRouteLinkT TrackFollower;
00412 typedef CRouteLinkNodeList NodeList;
00413 typedef Vehicle VehicleType;
00414
00415 typedef CYapfBaseT<Types> PfBase;
00416 typedef CYapfFollowRouteLinkT<Types> PfFollow;
00417 typedef CYapfOriginRouteLinkT<Types> PfOrigin;
00418 typedef CYapfDestinationRouteLinkT<Types> PfDestination;
00419 typedef CYapfSegmentCostCacheNoneT<Types> PfCache;
00420 typedef CYapfCostRouteLinkT<Types> PfCost;
00421 };
00422
00423 struct CYapfRouteLink : CYapfT<CYapfRouteLink_TypesT<CYapfRouteLink> > {};
00424
00425
00439 RouteLink *YapfChooseRouteLink(CargoID cid, const StationList *stations, TileIndex src, const TileArea &dest, StationID *start_station, StationID *next_unload, byte flags, bool *found, OrderID order, int max_cost)
00440 {
00441 return CYapfRouteLink::ChooseRouteLink(cid, stations, src, dest, start_station, next_unload, flags, found, order, max_cost);
00442 }