From edae1f5ead4b934d1f6c0436753e8c70bab40c8b Mon Sep 17 00:00:00 2001 From: Michael Holtan Date: Mon, 1 Mar 2021 19:57:16 -0600 Subject: [PATCH] Fix Issue #48: "Build Supply by estimating Consumption Rate" Tested with all 3 races and works smoothly, except when affected by Issue 37 (fast queue starves the slow queue). --- src/Hub.cpp | 8 ++ src/Hub.h | 3 + src/plugins/QuarterMaster.cpp | 116 +++++++++++++++------------ src/plugins/QuarterMaster.h | 3 +- src/strategies/terran/MarinePush.cpp | 5 -- 5 files changed, 77 insertions(+), 58 deletions(-) diff --git a/src/Hub.cpp b/src/Hub.cpp index 8c62628..f8e5d1d 100644 --- a/src/Hub.cpp +++ b/src/Hub.cpp @@ -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; @@ -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; } diff --git a/src/Hub.h b/src/Hub.h index 854bb33..97a4838 100644 --- a/src/Hub.h +++ b/src/Hub.h @@ -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_); @@ -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 m_captured_geysers; diff --git a/src/plugins/QuarterMaster.cpp b/src/plugins/QuarterMaster.cpp index fe83085..0c38045 100644 --- a/src/plugins/QuarterMaster.cpp +++ b/src/plugins/QuarterMaster.cpp @@ -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 { @@ -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: @@ -53,59 +53,85 @@ 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 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; @@ -113,27 +139,13 @@ void QuarterMaster::OnStep(Builder* builder_) { 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; } } diff --git a/src/plugins/QuarterMaster.h b/src/plugins/QuarterMaster.h index 400c18c..23a95c3 100644 --- a/src/plugins/QuarterMaster.h +++ b/src/plugins/QuarterMaster.h @@ -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; }; diff --git a/src/strategies/terran/MarinePush.cpp b/src/strategies/terran/MarinePush.cpp index 78c78df..4eeb64b 100644 --- a/src/strategies/terran/MarinePush.cpp +++ b/src/strategies/terran/MarinePush.cpp @@ -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); }