Skip to content

Commit

Permalink
Merge pull request #163 from AresSC2/fix/teching-up-prod-controller
Browse files Browse the repository at this point in the history
fix: teching up prod controller
  • Loading branch information
raspersc2 authored Jul 24, 2024
2 parents 4dc066a + 5525d0f commit 5b0f0bb
Show file tree
Hide file tree
Showing 6 changed files with 103 additions and 51 deletions.
44 changes: 29 additions & 15 deletions src/ares/behaviors/macro/production_controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from sc2.dicts.unit_unit_alias import UNIT_UNIT_ALIAS
from sc2.ids.unit_typeid import UnitTypeId as UnitID
from sc2.position import Point2
from sc2.unit import Unit
from sc2.units import Units

from ares.consts import ADD_ONS, GATEWAY_UNITS, ID, TARGET, TECHLAB_TYPES
Expand Down Expand Up @@ -72,7 +73,7 @@ class ProductionController(MacroBehavior):

army_composition_dict: dict[UnitID, dict[str, float, str, int]]
base_location: Point2
unit_pending_progress: float = 0.8
unit_pending_progress: float = 0.75
ignore_below_unit_count: int = 0
ignore_below_proportion: float = 0.05
should_repower_structures: bool = True
Expand All @@ -81,7 +82,6 @@ def execute(self, ai: "AresBot", config: dict, mediator: ManagerMediator) -> boo
assert (
ai.race != Race.Zerg
), "ProductionController behavior is for Protoss and Terran only"

if ai.race == Race.Protoss and self.should_repower_structures:
if RestorePower().execute(ai, config, mediator):
return True
Expand All @@ -106,6 +106,10 @@ def execute(self, ai: "AresBot", config: dict, mediator: ManagerMediator) -> boo
structure_dict: dict[UnitID, Units] = mediator.get_own_structures_dict

flying_structures: dict[int, dict] = mediator.get_flying_structure_tracker
collection_rate: int = (
ai.state.score.collection_rate_minerals
+ ai.state.score.collection_rate_vespene
)

# iterate through desired army comp starting with the highest priority unit
for unit_type_id, army_comp_info in sorted(
Expand Down Expand Up @@ -179,9 +183,23 @@ def execute(self, ai: "AresBot", config: dict, mediator: ManagerMediator) -> boo
if prod_flying:
continue

# income might not support more production
existing_structures: list[Unit] = []
for structure_type in train_from:
existing_structures.extend(structure_dict[structure_type])
divide_by: int = 420 if unit_type_id in GATEWAY_UNITS else 760
if len(existing_structures) >= int(collection_rate / divide_by):
continue

# might have production almost ready
almost_ready: bool = False
for structure_type in train_from:
if structure_type == UnitID.WARPGATE and [
s for s in structure_dict[structure_type] if not s.is_ready
]:
almost_ready = True
break

for s in structure_dict[structure_type]:
if s.orders:
if s.orders[0].progress >= self.unit_pending_progress:
Expand All @@ -202,7 +220,8 @@ def execute(self, ai: "AresBot", config: dict, mediator: ManagerMediator) -> boo
f"Where 0 has highest priority."
)

max_pending = int(target_proportion * 10)
# add max depending on income
max_pending = int(collection_rate / 1000)

if ai.structure_pending(trained_from) >= max_pending:
continue
Expand All @@ -213,7 +232,8 @@ def execute(self, ai: "AresBot", config: dict, mediator: ManagerMediator) -> boo
if built:
logger.info(
f"Adding {trained_from} so that we can build "
f"more {unit_type_id}, Current proportion: {current_proportion}"
f"more {unit_type_id}. Current proportion: {current_proportion}"
f" Target proportion: {target_proportion}"
)
return built

Expand Down Expand Up @@ -260,6 +280,9 @@ def _teching_up(
structures_dict: dict = ai.mediator.get_own_structures_dict
tech_required: list[UnitID] = UNIT_TECH_REQUIREMENT[unit_type_id]
without_techlabs: list[UnitID] = [s for s in tech_required if s not in ADD_ONS]
_trained_from: list[Unit] = structures_dict[trained_from].copy()
if unit_type_id in GATEWAY_UNITS:
_trained_from.extend(structures_dict[UnitID.WARPGATE])

for structure_type in UNIT_TECH_REQUIREMENT[unit_type_id]:
if ai.structure_pending(structure_type):
Expand All @@ -271,16 +294,7 @@ def _teching_up(
can_add_tech_lab: bool = True
# there might be idle structure with tech lab anyway
# can't be used since tech structures not present
if (
len(
[
s
for s in structures_dict[trained_from]
if s.has_techlab and s.is_idle
]
)
> 0
):
if len([s for s in _trained_from if s.has_techlab and s.is_idle]) > 0:
can_add_tech_lab = False
else:
for type_id in without_techlabs:
Expand All @@ -292,7 +306,7 @@ def _teching_up(

if base_structures := [
s
for s in structures_dict[trained_from]
for s in _trained_from
if s.is_ready and s.is_idle and not s.has_add_on
]:
base_structures[0].build(structure_type)
Expand Down
1 change: 1 addition & 0 deletions src/ares/build_runner/build_order_runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ def __init__(
self._chosen_opening: str = chosen_opening
if BUILDS in self.config:
build: list[str] = config[BUILDS][chosen_opening][OPENING_BUILD_ORDER]
logger.info(f"Running build from yml file: {chosen_opening}")
if self.AUTO_SUPPLY_AT_SUPPLY in config[BUILDS][chosen_opening]:
try:
self.auto_supply_at_supply = int(
Expand Down
65 changes: 54 additions & 11 deletions src/ares/dicts/unit_tech_requirement.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,32 +14,66 @@
],
UnitID.BROODLORD: [UnitID.GREATERSPIRE],
UnitID.CARRIER: [UnitID.STARGATE, UnitID.FLEETBEACON],
UnitID.COLOSSUS: [UnitID.ROBOTICSFACILITY, UnitID.ROBOTICSBAY],
UnitID.COLOSSUS: [
UnitID.GATEWAY,
UnitID.CYBERNETICSCORE,
UnitID.ROBOTICSFACILITY,
UnitID.ROBOTICSBAY,
],
UnitID.CORRUPTOR: [UnitID.SPIRE],
UnitID.CYCLONE: [UnitID.FACTORY],
UnitID.DARKTEMPLAR: [UnitID.GATEWAY, UnitID.DARKSHRINE],
UnitID.DISRUPTOR: [UnitID.ROBOTICSFACILITY, UnitID.ROBOTICSBAY],
UnitID.DARKTEMPLAR: [
UnitID.GATEWAY,
UnitID.CYBERNETICSCORE,
UnitID.TWILIGHTCOUNCIL,
UnitID.DARKSHRINE,
],
UnitID.DISRUPTOR: [
UnitID.GATEWAY,
UnitID.CYBERNETICSCORE,
UnitID.ROBOTICSFACILITY,
UnitID.ROBOTICSBAY,
],
UnitID.DRONE: [UnitID.HATCHERY],
UnitID.GHOST: [UnitID.BARRACKS, UnitID.BARRACKSTECHLAB, UnitID.GHOSTACADEMY],
UnitID.HELLION: [UnitID.FACTORY],
UnitID.HELLIONTANK: [UnitID.FACTORY, UnitID.ARMORY],
UnitID.HIGHTEMPLAR: [UnitID.GATEWAY, UnitID.TEMPLARARCHIVE],
UnitID.HIGHTEMPLAR: [
UnitID.GATEWAY,
UnitID.CYBERNETICSCORE,
UnitID.TWILIGHTCOUNCIL,
UnitID.TEMPLARARCHIVE,
],
UnitID.HYDRALISK: [UnitID.HYDRALISKDEN],
UnitID.IMMORTAL: [UnitID.ROBOTICSFACILITY],
UnitID.IMMORTAL: [
UnitID.GATEWAY,
UnitID.CYBERNETICSCORE,
UnitID.ROBOTICSFACILITY,
],
UnitID.INFESTOR: [UnitID.INFESTATIONPIT],
UnitID.LIBERATOR: [UnitID.STARPORT],
UnitID.LURKERMP: [UnitID.LURKERDENMP],
UnitID.MARAUDER: [UnitID.BARRACKS, UnitID.BARRACKSTECHLAB],
UnitID.MARINE: [UnitID.BARRACKS],
UnitID.MEDIVAC: [UnitID.STARPORT],
UnitID.MOTHERSHIP: [UnitID.NEXUS, UnitID.FLEETBEACON],
UnitID.MOTHERSHIP: [
UnitID.NEXUS,
UnitID.GATEWAY,
UnitID.CYBERNETICSCORE,
UnitID.STARGATE,
UnitID.FLEETBEACON,
],
UnitID.MUTALISK: [UnitID.SPIRE],
UnitID.OBSERVER: [UnitID.ROBOTICSFACILITY],
UnitID.ORACLE: [UnitID.STARGATE],
UnitID.OBSERVER: [
UnitID.GATEWAY,
UnitID.CYBERNETICSCORE,
UnitID.ROBOTICSFACILITY,
],
UnitID.ORACLE: [UnitID.GATEWAY, UnitID.CYBERNETICSCORE, UnitID.STARGATE],
UnitID.OVERLORD: [UnitID.HATCHERY],
UnitID.OVERLORDTRANSPORT: [UnitID.LAIR],
UnitID.OVERSEER: [UnitID.LAIR],
UnitID.PHOENIX: [UnitID.STARGATE],
UnitID.PHOENIX: [UnitID.GATEWAY, UnitID.CYBERNETICSCORE, UnitID.STARGATE],
UnitID.PROBE: [UnitID.NEXUS],
UnitID.QUEEN: [UnitID.SPAWNINGPOOL],
UnitID.RAVAGER: [UnitID.ROACHWARREN],
Expand All @@ -51,13 +85,22 @@
UnitID.SIEGETANK: [UnitID.FACTORY, UnitID.FACTORYTECHLAB],
UnitID.STALKER: [UnitID.GATEWAY, UnitID.CYBERNETICSCORE],
UnitID.SWARMHOSTMP: [UnitID.INFESTATIONPIT],
UnitID.TEMPEST: [UnitID.STARGATE, UnitID.FLEETBEACON],
UnitID.TEMPEST: [
UnitID.GATEWAY,
UnitID.CYBERNETICSCORE,
UnitID.STARGATE,
UnitID.FLEETBEACON,
],
UnitID.THOR: [UnitID.FACTORY, UnitID.FACTORYTECHLAB, UnitID.ARMORY],
UnitID.ULTRALISK: [UnitID.ULTRALISKCAVERN],
UnitID.VIKINGFIGHTER: [UnitID.STARPORT],
UnitID.VIPER: [UnitID.HIVE],
UnitID.VOIDRAY: [UnitID.STARGATE],
UnitID.WARPPRISM: [UnitID.ROBOTICSFACILITY],
UnitID.WARPPRISM: [
UnitID.GATEWAY,
UnitID.CYBERNETICSCORE,
UnitID.ROBOTICSFACILITY,
],
UnitID.WIDOWMINE: [UnitID.FACTORY],
UnitID.ZEALOT: [UnitID.GATEWAY],
UnitID.ZERGLING: [UnitID.SPAWNINGPOOL],
Expand Down
3 changes: 3 additions & 0 deletions src/ares/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -987,6 +987,9 @@ def structure_present_or_pending(self, structure_type: UnitID) -> bool:
bool
"""
structures: list[Unit] = self.mediator.get_own_structures_dict[structure_type]
if structure_type == UnitID.GATEWAY:
structures.extend(self.mediator.get_own_structures_dict[UnitID.WARPGATE])
return (
len(self.mediator.get_own_structures_dict[structure_type]) > 0
or self.mediator.get_building_counter[structure_type] > 0
Expand Down
24 changes: 9 additions & 15 deletions src/ares/managers/intel_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -335,14 +335,15 @@ async def update(self, iteration: int) -> None:

def _check_for_enemy_rush(self):
if self.ai.enemy_race == Race.Zerg and not self.enemy_ling_rushed:
enemy_lings: list[Unit] = self.manager_mediator.get_enemy_army_dict[
UnitID.ZERGLING
]
if (
self.ai.time < 150.0
and len(
[
ling
for ling in self.manager_mediator.get_enemy_army_dict[
UnitID.ZERGLING
]
for ling in enemy_lings
if cy_distance_to_squared(ling.position, self.ai.start_location)
< 2500.0
]
Expand All @@ -352,18 +353,11 @@ def _check_for_enemy_rush(self):
logger.info(f"{self.ai.time}: enemy ling rush detected")
self.enemy_ling_rushed = True

if (
self.ai.time < 180.0
and len(
[
ling
for ling in self.manager_mediator.get_enemy_army_dict[
UnitID.ZERGLING
]
]
)
> 7
):
if self.ai.time < 180.0 and len(enemy_lings) > 7:
logger.info(f"{self.ai.time}: enemy ling rush detected")
self.enemy_ling_rushed = True

if self.ai.time < 90.0 and len(enemy_lings) > 4:
logger.info(f"{self.ai.time}: enemy ling rush detected")
self.enemy_ling_rushed = True

Expand Down
17 changes: 7 additions & 10 deletions src/ares/managers/placement_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -439,24 +439,21 @@ def request_building_placement(
)
for location in locations:
logger.warning(
f"No available {building_size} found near location: "
f"{base_location}, trying near {location}"
f"{self.ai.time_formatted}: No available {building_size} found "
f"near location: {base_location}, trying near {location}"
)
available: list[Point2] = self._find_potential_placements_at_base(
building_size, location, structure_type, within_psionic_matrix
)

if len(available) == 0:
logger.warning(
f"No {building_size} found near location: {location}"
)
# FOUND SOMETHING! Break out and continue logic after this loop
else:
if len(available) > 0:
building_at_base = location
break

if len(available) == 0:
logger.warning(f"No available {building_size} found, giving up")
logger.info(
f"{self.ai.time_formatted}: No available {building_size}"
f" found anywhere on map, giving up."
)
return

# get closest available by default
Expand Down

0 comments on commit 5b0f0bb

Please sign in to comment.