Skip to content

Commit

Permalink
Fix Issue alkurbatov#48: "Build Supply by estimating Consumption Rate"
Browse files Browse the repository at this point in the history
Tested with all 3 races and works smoothly, except when affected by Issue 37 (fast queue starves the slow queue).
  • Loading branch information
ImpulseCloud authored and alkurbatov committed Mar 3, 2021
1 parent 292d4c9 commit edae1f5
Show file tree
Hide file tree
Showing 5 changed files with 77 additions and 58 deletions.
8 changes: 8 additions & 0 deletions src/Hub.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,20 +37,24 @@ bool SortByDistance::operator()(const Expansion& lhs_, const Expansion& rhs_) co

Hub::Hub(sc2::Race current_race_, const Expansions& expansions_):
m_current_race(current_race_), m_expansions(expansions_),
m_current_supply_type(sc2::UNIT_TYPEID::INVALID),
m_current_worker_type(sc2::UNIT_TYPEID::INVALID) {
std::sort(m_expansions.begin(), m_expansions.end(),
SortByDistance(gAPI->observer().StartingLocation()));

switch (m_current_race) {
case sc2::Race::Protoss:
m_current_supply_type = sc2::UNIT_TYPEID::PROTOSS_PYLON;
m_current_worker_type = sc2::UNIT_TYPEID::PROTOSS_PROBE;
return;

case sc2::Race::Terran:
m_current_supply_type = sc2::UNIT_TYPEID::TERRAN_SUPPLYDEPOT;
m_current_worker_type = sc2::UNIT_TYPEID::TERRAN_SCV;
return;

case sc2::Race::Zerg:
m_current_supply_type = sc2::UNIT_TYPEID::ZERG_OVERLORD;
m_current_worker_type = sc2::UNIT_TYPEID::ZERG_DRONE;
return;

Expand Down Expand Up @@ -221,6 +225,10 @@ Worker* Hub::GetClosestFreeWorker(const sc2::Point2D& location_) {
return &m_busy_workers.Back();
}

sc2::UNIT_TYPEID Hub::GetCurrentSupplyType() const {
return m_current_supply_type;
}

sc2::UNIT_TYPEID Hub::GetCurrentWorkerType() const {
return m_current_worker_type;
}
Expand Down
3 changes: 3 additions & 0 deletions src/Hub.h
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,8 @@ struct Hub {

Worker* GetClosestFreeWorker(const sc2::Point2D& location_);

sc2::UNIT_TYPEID GetCurrentSupplyType() const;

sc2::UNIT_TYPEID GetCurrentWorkerType() const;

bool AssignRefineryConstruction(Order* order_, const sc2::Unit* geyser_);
Expand All @@ -152,6 +154,7 @@ struct Hub {
private:
sc2::Race m_current_race;
Expansions m_expansions;
sc2::UNIT_TYPEID m_current_supply_type;
sc2::UNIT_TYPEID m_current_worker_type;

Cache<Geyser> m_captured_geysers;
Expand Down
116 changes: 64 additions & 52 deletions src/plugins/QuarterMaster.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@ Historican gHistory("plugin.quarter_master");

struct CalcSupplies {
float operator()(float sum, const sc2::Unit* unit_) const;

float operator()(float sum, const Order& order_) const;
};

float CalcSupplies::operator()(float sum, const sc2::Unit* unit_) const {
Expand All @@ -26,6 +24,8 @@ float CalcSupplies::operator()(float sum, const sc2::Unit* unit_) const {
case sc2::UNIT_TYPEID::TERRAN_ORBITALCOMMAND:
case sc2::UNIT_TYPEID::TERRAN_ORBITALCOMMANDFLYING:
case sc2::UNIT_TYPEID::TERRAN_PLANETARYFORTRESS:
if (unit_->build_progress < 1.0f)
return sum;
return sum + 15.0f;

case sc2::UNIT_TYPEID::ZERG_HATCHERY:
Expand Down Expand Up @@ -53,87 +53,99 @@ float CalcSupplies::operator()(float sum, const sc2::Unit* unit_) const {
}
}

float CalcSupplies::operator()(float sum, const Order& order_) const {
switch (order_.ability_id.ToType()) {
case sc2::ABILITY_ID::BUILD_NEXUS:
case sc2::ABILITY_ID::BUILD_COMMANDCENTER:
return sum + 15.0f;
struct CalcConsumptionRate {
float operator()(float sum, const sc2::Unit* unit_) const;
};

case sc2::ABILITY_ID::BUILD_PYLON:
case sc2::ABILITY_ID::BUILD_SUPPLYDEPOT:
case sc2::ABILITY_ID::TRAIN_OVERLORD:
return sum + 8.0f;
float CalcConsumptionRate::operator()(float sum, const sc2::Unit* unit_) const {
if (unit_->build_progress != 1.0f)
return sum;

switch (unit_->unit_type.ToType()) {
case sc2::UNIT_TYPEID::PROTOSS_NEXUS:
case sc2::UNIT_TYPEID::ZERG_HATCHERY:
case sc2::UNIT_TYPEID::TERRAN_COMMANDCENTER:
case sc2::UNIT_TYPEID::TERRAN_ORBITALCOMMAND:
case sc2::UNIT_TYPEID::TERRAN_PLANETARYFORTRESS:
return sum + 1.75f;
// SCV = 272 framesToTrain (exactly), TrainRate=1/272
// SupplyDepot = 480 framesToTrain, TrainRate = 1/480
// SCV's trained while Depot builds = 480/272 = 1.765

case sc2::UNIT_TYPEID::TERRAN_BARRACKS:
return sum + 1.2f;
// MarineTrainTime = 18*22.4 = 403.2 (roughly), TrainRate = 1/403
// SupplyDepot = 480 framesToTrain, TrainRate = 1/480
// Marines trained while Depot builds = 480/403 = 1.191

case sc2::UNIT_TYPEID::TERRAN_BARRACKSREACTOR:
return sum + 2.4f;
// Double the rounded 1.2 rate of single Barracks = 2.4

case sc2::UNIT_TYPEID::TERRAN_BARRACKSTECHLAB:
return sum + 2.0f;
// MarauderTrainTime = 21*22.4 = 470.4 (roughly), TrainRate = 1/470
// SupplyDepot = 480 framesToTrain, TrainRate = 1/480
// Marauders trained while Depot builds = 480/470 = 1.02
// Marauder is 2 supply, so round to 2.0 overall

case sc2::UNIT_TYPEID::TERRAN_FACTORY:
case sc2::UNIT_TYPEID::TERRAN_FACTORYTECHLAB:
case sc2::UNIT_TYPEID::TERRAN_FACTORYREACTOR:
case sc2::UNIT_TYPEID::TERRAN_STARPORT:
case sc2::UNIT_TYPEID::TERRAN_STARPORTTECHLAB:
case sc2::UNIT_TYPEID::TERRAN_STARPORTREACTOR:
case sc2::UNIT_TYPEID::ZERG_LAIR:
case sc2::UNIT_TYPEID::ZERG_HIVE:
case sc2::UNIT_TYPEID::PROTOSS_GATEWAY:
case sc2::UNIT_TYPEID::PROTOSS_ROBOTICSFACILITY:
case sc2::UNIT_TYPEID::PROTOSS_STARGATE:
return sum + 2.0f; // just add 2.0 for all others for now

default:
return sum;
}
}

struct CalcConsumption {
float operator()(float sum, const Order& order_) const;
};

float CalcConsumption::operator()(float sum, const Order& order_) const {
return sum + order_.food_required;
}

} // namespace

QuarterMaster::QuarterMaster():
Plugin(), m_skip_turn(false) {
Plugin(), m_skip_until_frame(0) {
}

void QuarterMaster::OnStep(Builder* builder_) {
if (m_skip_turn)
if (m_skip_until_frame > gAPI->observer().GetGameLoop())
return;

auto units = gAPI->observer().GetUnits();
std::list<Order> orders = builder_->GetOrders();

float expected_consumption =
gAPI->observer().GetFoodUsed()
+ 8.0f // NOTE (alkurbatov): Plan ahead.
+ std::accumulate(
orders.begin(),
orders.end(),
0.0f,
CalcConsumption());
if (!orders.empty()
&& orders.begin()->unit_type_id == gHub->GetCurrentSupplyType()) {
m_skip_until_frame = gAPI->observer().GetGameLoop() + m_frames_to_skip;
return; // wait 10 seconds if already scheduled Supply
}

float expected_consumption = gAPI->observer().GetFoodUsed()
+ std::accumulate(units().begin(), units().end(), 0.0f, CalcConsumptionRate());

float expected_supply =
std::accumulate(units().begin(), units().end(), 0.0f, CalcSupplies())
+ std::accumulate(
orders.begin(),
orders.end(),
0.0f,
CalcSupplies());
std::accumulate(units().begin(), units().end(), 0.0f, CalcSupplies());

if (expected_supply > expected_consumption || expected_supply >= 200.0f)
return;

gHistory.info() << "Request additional supplies: " <<
expected_consumption << " >= " << expected_supply << std::endl;

m_skip_turn = true;

switch (gHub->GetCurrentRace()) {
case sc2::Race::Terran:
builder_->ScheduleObligatoryOrder(sc2::UNIT_TYPEID::TERRAN_SUPPLYDEPOT, true);
return;

case sc2::Race::Zerg:
builder_->ScheduleObligatoryOrder(sc2::UNIT_TYPEID::ZERG_OVERLORD, true);
return;
m_skip_until_frame = gAPI->observer().GetGameLoop() + m_frames_to_skip;

default:
builder_->ScheduleObligatoryOrder(sc2::UNIT_TYPEID::PROTOSS_PYLON, true);
return;
}
builder_->ScheduleObligatoryOrder(gHub->GetCurrentSupplyType(), true);
}

void QuarterMaster::OnUnitCreated(const sc2::Unit* unit_, Builder*) {
if (unit_->unit_type == sc2::UNIT_TYPEID::TERRAN_SUPPLYDEPOT ||
unit_->unit_type == sc2::UNIT_TYPEID::ZERG_OVERLORD ||
unit_->unit_type == sc2::UNIT_TYPEID::PROTOSS_PYLON) {
m_skip_turn = false;
if (unit_->unit_type == gHub->GetCurrentSupplyType()) {
m_skip_until_frame = 0;
}
}
3 changes: 2 additions & 1 deletion src/plugins/QuarterMaster.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,6 @@ struct QuarterMaster : Plugin {
void OnUnitCreated(const sc2::Unit* unit_, Builder*) final;

private:
bool m_skip_turn;
const size_t m_frames_to_skip = 10 * 22; // 10 Seconds * 22 Frames Per Second (~22.4)
size_t m_skip_until_frame;
};
5 changes: 0 additions & 5 deletions src/strategies/terran/MarinePush.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,22 +15,17 @@ MarinePush::MarinePush(): Strategy(16.0f) {
void MarinePush::OnGameStart(Builder* builder_) {
builder_->ScheduleObligatoryOrder(sc2::UNIT_TYPEID::TERRAN_SUPPLYDEPOT);
builder_->ScheduleObligatoryOrder(sc2::UNIT_TYPEID::TERRAN_BARRACKS);
builder_->ScheduleObligatoryOrder(sc2::UNIT_TYPEID::TERRAN_SUPPLYDEPOT);
builder_->ScheduleObligatoryOrder(sc2::UNIT_TYPEID::TERRAN_BARRACKS);
builder_->ScheduleObligatoryOrder(sc2::UNIT_TYPEID::TERRAN_REFINERY);
builder_->ScheduleObligatoryOrder(sc2::UNIT_TYPEID::TERRAN_ORBITALCOMMAND);
builder_->ScheduleObligatoryOrder(sc2::UNIT_TYPEID::TERRAN_BARRACKS);
builder_->ScheduleObligatoryOrder(sc2::UNIT_TYPEID::TERRAN_BARRACKSTECHLAB);
builder_->ScheduleObligatoryOrder(sc2::UNIT_TYPEID::TERRAN_BARRACKS);
builder_->ScheduleObligatoryOrder(sc2::UNIT_TYPEID::TERRAN_SUPPLYDEPOT);
builder_->ScheduleObligatoryOrder(sc2::UPGRADE_ID::SHIELDWALL);
builder_->ScheduleObligatoryOrder(sc2::UNIT_TYPEID::TERRAN_BARRACKS);
builder_->ScheduleObligatoryOrder(sc2::UNIT_TYPEID::TERRAN_SUPPLYDEPOT);
builder_->ScheduleOptionalOrder(sc2::UPGRADE_ID::STIMPACK);
builder_->ScheduleObligatoryOrder(sc2::UNIT_TYPEID::TERRAN_BARRACKSREACTOR);
builder_->ScheduleObligatoryOrder(sc2::UNIT_TYPEID::TERRAN_BARRACKSREACTOR);
builder_->ScheduleObligatoryOrder(sc2::UNIT_TYPEID::TERRAN_SUPPLYDEPOT);
builder_->ScheduleObligatoryOrder(sc2::UNIT_TYPEID::TERRAN_SUPPLYDEPOT);
builder_->ScheduleObligatoryOrder(sc2::UNIT_TYPEID::TERRAN_BARRACKSREACTOR);
builder_->ScheduleObligatoryOrder(sc2::UNIT_TYPEID::TERRAN_BARRACKSREACTOR);
}
Expand Down

0 comments on commit edae1f5

Please sign in to comment.