(svn r25891) -Feature: Use smallstack to allow for multiple next hops when loading and unloading.

pull/155/head
fonsinchen 11 years ago
parent b908128ffb
commit fff00b6460

@ -421,7 +421,7 @@ void VehicleCargoList::SetTransferLoadPlace(TileIndex xy)
* @param payment Payment object for registering transfers. * @param payment Payment object for registering transfers.
* return If any cargo will be unloaded. * return If any cargo will be unloaded.
*/ */
bool VehicleCargoList::Stage(bool accepted, StationID current_station, StationID next_station, uint8 order_flags, const GoodsEntry *ge, CargoPayment *payment) bool VehicleCargoList::Stage(bool accepted, StationID current_station, StationIDStack next_station, uint8 order_flags, const GoodsEntry *ge, CargoPayment *payment)
{ {
this->AssertCountConsistency(); this->AssertCountConsistency();
assert(this->action_counts[MTA_LOAD] == 0); assert(this->action_counts[MTA_LOAD] == 0);
@ -446,9 +446,24 @@ bool VehicleCargoList::Stage(bool accepted, StationID current_station, StationID
action = MTA_DELIVER; action = MTA_DELIVER;
} else if (force_transfer) { } else if (force_transfer) {
action = MTA_TRANSFER; action = MTA_TRANSFER;
cargo_next = ge->GetVia(cp->source, current_station, next_station); /* We cannot send the cargo to any of the possible next hops and
assert((cargo_next != next_station || cargo_next == INVALID_STATION) && * also not to the current station. */
cargo_next != current_station); FlowStatMap::const_iterator flow_it(ge->flows.find(cp->source));
if (flow_it == ge->flows.end()) {
cargo_next = INVALID_STATION;
} else {
FlowStat new_shares = flow_it->second;
new_shares.ChangeShare(current_station, INT_MIN);
StationIDStack excluded = next_station;
while (!excluded.IsEmpty()) {
new_shares.ChangeShare(excluded.Pop(), INT_MIN);
}
if (new_shares.GetShares()->empty()) {
cargo_next = INVALID_STATION;
} else {
cargo_next = new_shares.GetVia();
}
}
} else { } else {
/* Rewrite an invalid source station to some random other one to /* Rewrite an invalid source station to some random other one to
* avoid keeping the cargo in the vehicle forever. */ * avoid keeping the cargo in the vehicle forever. */
@ -460,7 +475,7 @@ bool VehicleCargoList::Stage(bool accepted, StationID current_station, StationID
action = (accepted && cp->source != current_station) ? MTA_DELIVER : MTA_KEEP; action = (accepted && cp->source != current_station) ? MTA_DELIVER : MTA_KEEP;
} else if (cargo_next == current_station) { } else if (cargo_next == current_station) {
action = MTA_DELIVER; action = MTA_DELIVER;
} else if (cargo_next == next_station) { } else if (next_station.Contains(cargo_next)) {
action = MTA_KEEP; action = MTA_KEEP;
} else { } else {
action = MTA_TRANSFER; action = MTA_TRANSFER;
@ -667,10 +682,14 @@ bool StationCargoList::ShiftCargo(Taction &action, StationID next)
* @return Amount of cargo actually moved. * @return Amount of cargo actually moved.
*/ */
template <class Taction> template <class Taction>
uint StationCargoList::ShiftCargo(Taction action, StationID next, bool include_invalid) uint StationCargoList::ShiftCargo(Taction action, StationIDStack next, bool include_invalid)
{ {
uint max_move = action.MaxMove(); uint max_move = action.MaxMove();
if (this->ShiftCargo(action, next) && include_invalid && action.MaxMove() > 0) { while (!next.IsEmpty()) {
this->ShiftCargo(action, next.Pop());
if (action.MaxMove() == 0) break;
}
if (include_invalid && action.MaxMove() > 0) {
this->ShiftCargo(action, INVALID_STATION); this->ShiftCargo(action, INVALID_STATION);
} }
return max_move - action.MaxMove(); return max_move - action.MaxMove();
@ -735,10 +754,10 @@ uint StationCargoList::Truncate(uint max_move, StationCargoAmountMap *cargo_per_
* @param max_move Maximum amount of cargo to reserve. * @param max_move Maximum amount of cargo to reserve.
* @param dest VehicleCargoList to reserve for. * @param dest VehicleCargoList to reserve for.
* @param load_place Tile index of the current station. * @param load_place Tile index of the current station.
* @param next_station Next station the loading vehicle will visit. * @param next_station Next station(s) the loading vehicle will visit.
* @return Amount of cargo actually reserved. * @return Amount of cargo actually reserved.
*/ */
uint StationCargoList::Reserve(uint max_move, VehicleCargoList *dest, TileIndex load_place, StationID next_station) uint StationCargoList::Reserve(uint max_move, VehicleCargoList *dest, TileIndex load_place, StationIDStack next_station)
{ {
return this->ShiftCargo(CargoReservation(this, dest, max_move, load_place), next_station, true); return this->ShiftCargo(CargoReservation(this, dest, max_move, load_place), next_station, true);
} }
@ -749,13 +768,13 @@ uint StationCargoList::Reserve(uint max_move, VehicleCargoList *dest, TileIndex
* @param max_move Amount of cargo to load. * @param max_move Amount of cargo to load.
* @param dest Vehicle cargo list where the cargo resides. * @param dest Vehicle cargo list where the cargo resides.
* @param load_place The new loaded_at_xy to be assigned to packets being moved. * @param load_place The new loaded_at_xy to be assigned to packets being moved.
* @param next_station Next station the loading vehicle will visit. * @param next_station Next station(s) the loading vehicle will visit.
* @return Amount of cargo actually loaded. * @return Amount of cargo actually loaded.
* @note Vehicles may or may not reserve, depending on their orders. The two * @note Vehicles may or may not reserve, depending on their orders. The two
* modes of loading are exclusive, though. If cargo is reserved we don't * modes of loading are exclusive, though. If cargo is reserved we don't
* need to load unreserved cargo. * need to load unreserved cargo.
*/ */
uint StationCargoList::Load(uint max_move, VehicleCargoList *dest, TileIndex load_place, StationID next_station) uint StationCargoList::Load(uint max_move, VehicleCargoList *dest, TileIndex load_place, StationIDStack next_station)
{ {
uint move = min(dest->ActionCount(VehicleCargoList::MTA_LOAD), max_move); uint move = min(dest->ActionCount(VehicleCargoList::MTA_LOAD), max_move);
if (move > 0) { if (move > 0) {

@ -409,7 +409,7 @@ public:
void SetTransferLoadPlace(TileIndex xy); void SetTransferLoadPlace(TileIndex xy);
bool Stage(bool accepted, StationID current_station, StationID next_station, uint8 order_flags, const GoodsEntry *ge, CargoPayment *payment); bool Stage(bool accepted, StationID current_station, StationIDStack next_station, uint8 order_flags, const GoodsEntry *ge, CargoPayment *payment);
/** /**
* Marks all cargo in the vehicle as to be kept. This is mostly useful for * Marks all cargo in the vehicle as to be kept. This is mostly useful for
@ -483,7 +483,7 @@ public:
bool ShiftCargo(Taction &action, StationID next); bool ShiftCargo(Taction &action, StationID next);
template<class Taction> template<class Taction>
uint ShiftCargo(Taction action, StationID next, bool include_invalid); uint ShiftCargo(Taction action, StationIDStack next, bool include_invalid);
void Append(CargoPacket *cp, StationID next); void Append(CargoPacket *cp, StationID next);
@ -492,9 +492,13 @@ public:
* @param next Station the cargo is headed for. * @param next Station the cargo is headed for.
* @return If there is any cargo for that station. * @return If there is any cargo for that station.
*/ */
inline bool HasCargoFor(StationID next) const inline bool HasCargoFor(StationIDStack next) const
{ {
return this->packets.find(next) != this->packets.end(); while (!next.IsEmpty()) {
if (this->packets.find(next.Pop()) != this->packets.end()) return true;
}
/* Packets for INVALID_STTION can go anywhere. */
return this->packets.find(INVALID_STATION) != this->packets.end();
} }
/** /**
@ -539,8 +543,8 @@ public:
* amount of cargo to be moved. Second parameter is destination (if * amount of cargo to be moved. Second parameter is destination (if
* applicable), return value is amount of cargo actually moved. */ * applicable), return value is amount of cargo actually moved. */
uint Reserve(uint max_move, VehicleCargoList *dest, TileIndex load_place, StationID next); uint Reserve(uint max_move, VehicleCargoList *dest, TileIndex load_place, StationIDStack next);
uint Load(uint max_move, VehicleCargoList *dest, TileIndex load_place, StationID next); uint Load(uint max_move, VehicleCargoList *dest, TileIndex load_place, StationIDStack next);
uint Truncate(uint max_move = UINT_MAX, StationCargoAmountMap *cargo_per_source = NULL); uint Truncate(uint max_move = UINT_MAX, StationCargoAmountMap *cargo_per_source = NULL);
uint Reroute(uint max_move, StationCargoList *dest, StationID avoid, StationID avoid2, const GoodsEntry *ge); uint Reroute(uint max_move, StationCargoList *dest, StationID avoid, StationID avoid2, const GoodsEntry *ge);

@ -1232,7 +1232,7 @@ void PrepareUnload(Vehicle *front_v)
assert(CargoPayment::CanAllocateItem()); assert(CargoPayment::CanAllocateItem());
front_v->cargo_payment = new CargoPayment(front_v); front_v->cargo_payment = new CargoPayment(front_v);
StationID next_station = front_v->GetNextStoppingStation(); StationIDStack next_station = front_v->GetNextStoppingStation();
if (front_v->orders.list == NULL || (front_v->current_order.GetUnloadType() & OUFB_NO_UNLOAD) == 0) { if (front_v->orders.list == NULL || (front_v->current_order.GetUnloadType() & OUFB_NO_UNLOAD) == 0) {
Station *st = Station::Get(front_v->last_station_visited); Station *st = Station::Get(front_v->last_station_visited);
for (Vehicle *v = front_v; v != NULL; v = v->Next()) { for (Vehicle *v = front_v; v != NULL; v = v->Next()) {
@ -1295,9 +1295,9 @@ static uint GetLoadAmount(Vehicle *v)
* @param st Station where the consist is loading at the moment. * @param st Station where the consist is loading at the moment.
* @param u Front of the loading vehicle consist. * @param u Front of the loading vehicle consist.
* @param consist_capleft If given, save free capacities after reserving there. * @param consist_capleft If given, save free capacities after reserving there.
* @param next_station Station the vehicle will stop at next. * @param next_station Station(s) the vehicle will stop at next.
*/ */
static void ReserveConsist(Station *st, Vehicle *u, CargoArray *consist_capleft, StationID next_station) static void ReserveConsist(Station *st, Vehicle *u, CargoArray *consist_capleft, StationIDStack next_station)
{ {
Vehicle *next_cargo = u; Vehicle *next_cargo = u;
uint32 seen_cargos = 0; uint32 seen_cargos = 0;
@ -1363,7 +1363,7 @@ static void LoadUnloadVehicle(Vehicle *front)
StationID last_visited = front->last_station_visited; StationID last_visited = front->last_station_visited;
Station *st = Station::Get(last_visited); Station *st = Station::Get(last_visited);
StationID next_station = front->GetNextStoppingStation(); StationIDStack next_station = front->GetNextStoppingStation();
bool use_autorefit = front->current_order.IsRefit() && front->current_order.GetRefitCargo() == CT_AUTO_REFIT; bool use_autorefit = front->current_order.IsRefit() && front->current_order.GetRefitCargo() == CT_AUTO_REFIT;
CargoArray consist_capleft; CargoArray consist_capleft;
if (_settings_game.order.improved_load && if (_settings_game.order.improved_load &&
@ -1497,8 +1497,7 @@ static void LoadUnloadVehicle(Vehicle *front)
CargoID cid; CargoID cid;
new_cid = v_start->cargo_type; new_cid = v_start->cargo_type;
FOR_EACH_SET_CARGO_ID(cid, refit_mask) { FOR_EACH_SET_CARGO_ID(cid, refit_mask) {
if (st->goods[cid].cargo.HasCargoFor(next_station) || if (st->goods[cid].cargo.HasCargoFor(next_station)) {
st->goods[cid].cargo.HasCargoFor(INVALID_STATION)) {
/* Try to find out if auto-refitting would succeed. In case the refit is allowed, /* Try to find out if auto-refitting would succeed. In case the refit is allowed,
* the returned refit capacity will be greater than zero. */ * the returned refit capacity will be greater than zero. */
DoCommand(v_start->tile, v_start->index, cid | 1U << 6 | 0xFF << 8 | 1U << 16, DC_QUERY_COST, GetCmdRefitVeh(v_start)); // Auto-refit and only this vehicle including artic parts. DoCommand(v_start->tile, v_start->index, cid | 1U << 6 | 0xFF << 8 | 1U << 16, DC_QUERY_COST, GetCmdRefitVeh(v_start)); // Auto-refit and only this vehicle including artic parts.

@ -263,7 +263,7 @@ public:
*/ */
inline VehicleOrderID GetNumManualOrders() const { return this->num_manual_orders; } inline VehicleOrderID GetNumManualOrders() const { return this->num_manual_orders; }
StationID GetNextStoppingStation(const Vehicle *v, const Order *first = NULL) const; StationIDStack GetNextStoppingStation(const Vehicle *v, const Order *first = NULL) const;
const Order *GetNextDecisionNode(const Order *next, uint hops) const; const Order *GetNextDecisionNode(const Order *next, uint hops) const;
void InsertOrderAt(Order *new_order, int index); void InsertOrderAt(Order *new_order, int index);

@ -350,44 +350,6 @@ Order *OrderList::GetOrderAt(int index) const
return order; return order;
} }
/**
* Choose between the two possible next orders so that the given consist can
* load most cargo.
* @param v Head of the consist.
* @param o1 First order to choose from.
* @param o2 Second order to choose from.
* @return The best option of o1 and o2 and (recursively) possibly other conditionals.
*/
StationID OrderList::GetBestLoadableNext(const Vehicle *v, const Order *o2, const Order *o1) const
{
SmallMap<CargoID, uint> capacities;
v->GetConsistFreeCapacities(capacities);
uint loadable1 = 0;
uint loadable2 = 0;
StationID st1 = this->GetNextStoppingStation(v, o1);
StationID st2 = this->GetNextStoppingStation(v, o2);
const Station *cur_station = Station::Get(v->last_station_visited);
for (SmallPair<CargoID, uint> *i = capacities.Begin(); i != capacities.End(); ++i) {
const StationCargoPacketMap *loadable_packets = cur_station->goods[i->first].cargo.Packets();
uint loadable_cargo = 0;
std::pair<StationCargoPacketMap::const_iterator, StationCargoPacketMap::const_iterator> p =
loadable_packets->equal_range(st1);
for (StationCargoPacketMap::const_iterator j = p.first; j != p.second; ++j) {
loadable_cargo = (*j)->Count();
}
loadable1 += min(i->second, loadable_cargo);
loadable_cargo = 0;
p = loadable_packets->equal_range(st2);
for (StationCargoPacketMap::const_iterator j = p.first; j != p.second; ++j) {
loadable_cargo = (*j)->Count();
}
loadable2 += min(i->second, loadable_cargo);
}
if (loadable1 == loadable2) return RandomRange(2) == 0 ? st1 : st2;
return loadable1 > loadable2 ? st1 : st2;
}
/** /**
* Get the next order which will make the given vehicle stop at a station * Get the next order which will make the given vehicle stop at a station
* or refit at a depot or evaluate a non-trivial condition. * or refit at a depot or evaluate a non-trivial condition.
@ -432,9 +394,8 @@ const Order *OrderList::GetNextDecisionNode(const Order *next, uint hops) const
* @return Next stoppping station or INVALID_STATION. * @return Next stoppping station or INVALID_STATION.
* @pre The vehicle is currently loading and v->last_station_visited is meaningful. * @pre The vehicle is currently loading and v->last_station_visited is meaningful.
* @note This function may draw a random number. Don't use it from the GUI. * @note This function may draw a random number. Don't use it from the GUI.
* @see OrderList::GetBestLoadableNext
*/ */
StationID OrderList::GetNextStoppingStation(const Vehicle *v, const Order *first) const StationIDStack OrderList::GetNextStoppingStation(const Vehicle *v, const Order *first) const
{ {
const Order *next = first; const Order *next = first;
@ -472,7 +433,10 @@ StationID OrderList::GetNextStoppingStation(const Vehicle *v, const Order *first
} else if (skip_to == NULL) { } else if (skip_to == NULL) {
next = advance; next = advance;
} else { } else {
return this->GetBestLoadableNext(v, skip_to, advance); StationIDStack st1 = this->GetNextStoppingStation(v, skip_to);
StationIDStack st2 = this->GetNextStoppingStation(v, advance);
while (!st2.IsEmpty()) st1.Push(st2.Pop());
return st1;
} }
} else { } else {
/* Otherwise we're optimistic and expect that the /* Otherwise we're optimistic and expect that the

@ -4057,8 +4057,9 @@ uint FlowStat::GetShare(StationID st) const
} }
/** /**
* Get a station a package can be routed to, but exclude the given one. * Get a station a package can be routed to, but exclude the given ones.
* @param excluded StationID not to be selected. * @param excluded StationID not to be selected.
* @param excluded2 Another StationID not to be selected.
* @return A station ID from the shares map. * @return A station ID from the shares map.
*/ */
StationID FlowStat::GetVia(StationID excluded, StationID excluded2) const StationID FlowStat::GetVia(StationID excluded, StationID excluded2) const

@ -628,7 +628,7 @@ public:
* Get the next station the vehicle will stop at. * Get the next station the vehicle will stop at.
* @return ID of the next station the vehicle will stop at or INVALID_STATION. * @return ID of the next station the vehicle will stop at or INVALID_STATION.
*/ */
inline StationID GetNextStoppingStation() const inline StationIDStack GetNextStoppingStation() const
{ {
return (this->orders.list == NULL) ? INVALID_STATION : this->orders.list->GetNextStoppingStation(this); return (this->orders.list == NULL) ? INVALID_STATION : this->orders.list->GetNextStoppingStation(this);
} }

Loading…
Cancel
Save