def minimum_supply(self, enemy_units): #everyone...! but no less supply than we know we'll be facing return max( sum(supply_cost(u) for u in enemy_units), sum( supply_cost(u) for u in (self.units.tags_in(self.allocated) + self.unallocated(urgency=self.urgency).filter( lambda u: not is_worker(u)))))
def log_unit_breakdown(self): units = {} for u in self.units: tid = str(u.type_id) cost = supply_cost(u) if tid in units: units[tid] += cost else: units[tid] = cost for unit_type, supply_used in units.items(): self.log.info({ "message": "Unit count", "unit_type": unit_type, "supply_used": supply_used, "game_time": self.bot.time })
def allocate(self): may_proceed = False enemy_units = self.enemies minimum_supply = int(self.minimum_supply(enemy_units)) optimum_supply = int(self.optimum_supply(enemy_units)) allocated_supply = int( sum(supply_cost(u) for u in self.units.tags_in(self.allocated))) if minimum_supply <= allocated_supply: may_proceed = True still_needed = minimum_supply - allocated_supply still_wanted = max(optimum_supply - allocated_supply, still_needed) usable_units = self.unallocated( urgency=self.urgency).filter(lambda u: not is_worker(u)) if enemy_units.filter(lambda e: not e.is_flying).empty: usable_units = usable_units.filter(lambda u: u.can_attack_air) preferred_units = usable_units.filter( lambda u: u.can_attack_both ) if usable_units.exists else usable_units adding_units = set() if sum(supply_cost(u) for u in preferred_units) >= still_needed: # still_wanted is actually supply, not units, so this will over-select for protoss and under-select for zerg adding_units = set(unit.tag for unit in preferred_units.closest_n_units( self.target.position, still_wanted)) elif sum(supply_cost(u) for u in usable_units) >= still_needed: adding_units = set(preferred_units) adding_units.update((unit.tag for unit in usable_units.closest_n_units( self.target.position, still_wanted))) self.deallocate(adding_units) self.allocated = self.allocated.union(adding_units) if sum(supply_cost(u) for u in self.units.tags_in(self.allocated)) >= minimum_supply: may_proceed = True if may_proceed: if self.status == ObjectiveStatus.ALLOCATING: self.status = ObjectiveStatus.STAGING self.status_since = self.time elif self.status == ObjectiveStatus.RETREATING and \ self.shared.optimism > 1.5 and \ self.units.exists and \ self.units.closer_than(15, median_position([u.position for u in self.units])).amount > self.units.amount / 2: self.status = ObjectiveStatus.STAGING self.status_since = self.time self.units = self.bot.units.tags_in(self.allocated) if len(adding_units) > 0: self.log.debug({ "message": "Allocating units", "quantity": len(adding_units), "now_allocated": len(self.allocated), }) # noisy, but possibly informative # self.log.info(f"{self.units.amount} units allocated for {self.enemies.amount} known enemies") return
def optimum_supply(self, enemy_units): return sum( supply_cost(unit) for unit in self.bot.units.filter( lambda u: u.ground_dps + u.air_dps > 5 and not is_worker(u)))
def optimum_supply(self, enemy_units): return sum(supply_cost(u) for u in enemy_units) * 3
def optimum_supply(self, enemy_units): return sum( supply_cost(u) for u in self.units.filter(lambda u: not is_worker(u)))