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 = 20;
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 return DistanceSquare(st->xy, this->m_dest.tile) * this->Yapf().PfGetSettings().route_distance_factor;
00288 }
00289
00291 FORCEINLINE bool PfDetectDestination(StationID st_id) const
00292 {
00293 const Station *st = Station::Get(st_id);
00294 return st->rect.AreaInExtendedRect(this->m_dest, st->GetCatchmentRadius());
00295 }
00296
00298 FORCEINLINE bool PfDetectDestination(const Node& n) const
00299 {
00300 return n.GetRouteLink() == NULL;
00301 }
00302
00304 FORCEINLINE bool PfCalcEstimate(Node& n)
00305 {
00306 if (this->PfDetectDestination(n)) {
00307 n.m_estimate = n.m_cost;
00308 return true;
00309 }
00310
00311
00312 Station *from = Station::Get(n.GetRouteLink()->GetDestination());
00313 int d = DistanceManhattan(from->xy, this->m_dest.tile) * this->Yapf().PfGetSettings().route_distance_factor;
00314
00315 n.m_estimate = n.m_cost + d;
00316 assert(n.m_estimate >= n.m_parent->m_estimate);
00317 return true;
00318 }
00319 };
00320
00322 template <class Types>
00323 class CYapfFollowRouteLinkT {
00324 typedef typename Types::Tpf Tpf;
00325 typedef typename Types::TrackFollower Follower;
00326 typedef typename Types::NodeList::Titem Node;
00327
00329 FORCEINLINE Tpf& Yapf() { return *static_cast<Tpf*>(this); }
00330
00331 public:
00333 inline void PfFollowNode(Node& old_node)
00334 {
00335 Follower f(this->Yapf().GetCargoID());
00336
00337 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) {
00338
00339 Node &n = this->Yapf().CreateNewNode();
00340 n.Set(&old_node, NULL);
00341 this->Yapf().AddNewNode(n, f);
00342 }
00343
00344 if (f.Follow(old_node.GetRouteLink())) {
00345 for (RouteLinkList::iterator link = f.m_new_links->begin(); link != f.m_new_links->end(); ++link) {
00346
00347 Node &n = this->Yapf().CreateNewNode();
00348 n.Set(&old_node, *link);
00349 this->Yapf().AddNewNode(n, f);
00350 }
00351 }
00352 }
00353
00355 FORCEINLINE char TransportTypeChar() const
00356 {
00357 return 'c';
00358 }
00359
00361 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)
00362 {
00363
00364 Tpf pf;
00365 pf.SetOrigin(cid, src, stations, start_station != NULL, order, flags);
00366 pf.SetDestination(dest, max_cost);
00367
00368 *next_unload = INVALID_STATION;
00369
00370
00371 bool res = pf.FindPath(NULL);
00372 if (found != NULL) *found = res;
00373 if (!res) return NULL;
00374
00375
00376 Node *node = pf.GetBestNode();
00377 while (node->m_parent->m_parent != NULL) {
00378
00379 if (node->GetRouteLink() == NULL || (node->GetRouteLink()->GetOriginOrderId() != node->m_parent->GetRouteLink()->GetDestOrderId())) {
00380 *next_unload = node->m_parent->GetRouteLink()->GetDestination();
00381 }
00382
00383 node = node->m_parent;
00384 }
00385
00386
00387 if (start_station != NULL) *start_station = node->m_parent->GetRouteLink()->GetDestination();
00388 return node->GetRouteLink();
00389 }
00390 };
00391
00393 template <class Tpf_>
00394 struct CYapfRouteLink_TypesT {
00395 typedef CYapfRouteLink_TypesT<Tpf_> Types;
00396
00397 typedef Tpf_ Tpf;
00398 typedef CFollowRouteLinkT TrackFollower;
00399 typedef CRouteLinkNodeList NodeList;
00400 typedef Vehicle VehicleType;
00401
00402 typedef CYapfBaseT<Types> PfBase;
00403 typedef CYapfFollowRouteLinkT<Types> PfFollow;
00404 typedef CYapfOriginRouteLinkT<Types> PfOrigin;
00405 typedef CYapfDestinationRouteLinkT<Types> PfDestination;
00406 typedef CYapfSegmentCostCacheNoneT<Types> PfCache;
00407 typedef CYapfCostRouteLinkT<Types> PfCost;
00408 };
00409
00410 struct CYapfRouteLink : CYapfT<CYapfRouteLink_TypesT<CYapfRouteLink> > {};
00411
00412
00426 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)
00427 {
00428 return CYapfRouteLink::ChooseRouteLink(cid, stations, src, dest, start_station, next_unload, flags, found, order, max_cost);
00429 }