Exemple #1
0
    def prepare_attack(self, military_ratio, interval=10):
        """
        Prepares an attack wave every interval when ready. Attack waves are 
        comprised of military units specified by the given ratio.

        :param military_ratio: <dict> [UnitId: int] specifying military 
        composition.
        :param interval: <int> time interval in seconds to prepare a wave.
        """

        if self.seconds_elapsed % interval != 0:
            return

        added_non_medic_units = False
        attack_wave = None
        for unit in military_ratio:
            if not added_non_medic_units and unit == MEDIVAC:
                continue

            amount = military_ratio[unit]
            units = self.units(unit)

            if units.idle.amount >= amount:
                if unit != MEDIVAC:
                    added_non_medic_units = True
                if attack_wave is None:
                    attack_wave = ControlGroup(units.idle)
                else:
                    attack_wave.add_units(units.idle)
        if attack_wave is not None and 0 < len(attack_wave) > 12:
            self.attack_waves.add(attack_wave)
Exemple #2
0
 async def addattackgroup(self):
     if self.units(MARINE).amount > 25:
         ad = ControlGroup(self.units(MARINE).idle)
         self.attack_groups.add(ad)
     elif self.units(MARINE).idle.amount > 15:
         ad = ControlGroup(self.units(MARINE).idle)
         self.attack_groups.add(ad)
Exemple #3
0
 def create_observer_control_groups(self):
     """ Create control groups """
     observers = self.units.of_type(OBSERVER)
     # will do nothing until an observer is made
     # then sequentially assign them to control groups one at a time
     valid_observers = []
     for obs in observers:
         try:
             o1 = self.control_groups['Observer 1']
             if obs.tag == o1.select_units(self.units)[0].tag:
                 continue  # to next observer
         except (KeyError, IndexError):
             pass
         try:
             o2 = self.control_groups['Observer 2']
             if obs.tag == o2.select_units(self.units)[0].tag:
                 continue  # to next observer
         except (KeyError, IndexError):
             pass
         valid_observers.append(obs)
     # valid_observers are not assigned to another control group
     for obs in valid_observers:
         # make sure valid_observers is of length 1
         try:
             assert len(valid_observers) == 1  # debug - observers must be assigned immediately
         except AssertionError:
             logger.error('valid_observers should be of length 1')
             valid_observers = Units(valid_observers[0])
         # if this observer is already in a control group do not reassign it
         try:
             o1 = self.control_groups['Observer 1']
             if o1.empty:
                 raise KeyError
         # KeyError if control group does not exist or is empty
         # TODO: maybe i should just init a bunch of control groups at the start of the game
         # and not have to worry about all this garbage
         except KeyError:
             self.control_groups['Observer 1'] = ControlGroup(valid_observers)
             logger.success('Assigned Observer to `Observer 1` Control Group')
             return
         try:
             o2 = self.control_groups['Observer 2']
             if o2.empty: raise KeyError
         except KeyError:
             self.control_groups['Observer 2'] = ControlGroup(valid_observers)
             logger.success('Assigned Observer to `Observer 2` Control Group')
             return
Exemple #4
0
    def __init__(self, bot):
        self.bot = bot
        self.logger = bot.logger
        self.opponent = bot.opponent

        self.first_overlord_tag = None
        self.first_overlord_ordered = False
        self.early_warning_overlord_tag = None
        self.early_warning_overlord_ordered = False

        self.has_verified_front_door = False
        self.all_combat_units = None
        self.reserve = ControlGroup([])
        self.harassing_base_scouts = ControlGroup([])
        self.no_mans_expansions_scouts = ControlGroup([])
        self.muta_flankers = ControlGroup([])
        self.base_defenders = ControlGroup([])
Exemple #5
0
    async def __group_idle_units(self, bot: sc2.BotAI):
        if bot.time > 480:
            idle_units = bot.units(UnitTypeId.MARINE).idle | bot.units(
                UnitTypeId.REAPER).idle

            if not bot.cc:
                idle_units = idle_units | bot.workers

            if idle_units.amount > 20:
                self.attack_groups.add(ControlGroup(idle_units))
Exemple #6
0
    async def on_step(self, iteration):
        actions = []

        cc = self.units(COMMANDCENTER)
        if not cc.exists:
            target = self.known_enemy_structures.random_or(
                self.enemy_start_locations[0]).position
            for unit in self.workers | self.units(MARINE):
                actions.append(unit.attack(target))
            await self.do_actions(actions)
            return
        else:
            cc = cc.first

        if self.units(MARINE).idle.amount > 15 and iteration % 50 == 1:
            cg = ControlGroup(self.units(MARINE).idle)
            self.attack_groups.add(cg)

        if self.can_afford(SCV) and self.workers.amount < 16 and cc.noqueue:
            actions.append(cc.train(SCV))

        elif self.supply_left < (2 if self.units(BARRACKS).amount < 3 else 4):
            if self.can_afford(
                    SUPPLYDEPOT) and self.already_pending(SUPPLYDEPOT) < 2:
                await self.build(SUPPLYDEPOT,
                                 near=cc.position.towards(
                                     self.game_info.map_center, 5))

        elif self.units(BARRACKS).amount < 3 or (
                self.minerals > 400 and self.units(BARRACKS).amount < 5):
            if self.can_afford(BARRACKS):
                p = self.game_info.map_center.towards(
                    self.enemy_start_locations[0], 25)
                await self.build(BARRACKS, near=p)

        for rax in self.units(BARRACKS).ready.noqueue:
            if not self.can_afford(MARINE):
                break
            actions.append(rax.train(MARINE))

        for scv in self.units(SCV).idle:
            actions.append(scv.gather(self.state.mineral_field.closest_to(cc)))

        for ac in list(self.attack_groups):
            alive_units = ac.select_units(self.units)
            if alive_units.exists and alive_units.idle.exists:
                target = self.known_enemy_structures.random_or(
                    self.enemy_start_locations[0]).position
                for marine in ac.select_units(self.units):
                    actions.append(marine.attack(target))
            else:
                self.attack_groups.remove(ac)

        await self.do_actions(actions)
Exemple #7
0
    def prepare_attack(self, military_ratio):
        """
        Prepares an attack wave when ready.

        :param military_ratio: <dict> [UnitId: int] specifying military 
        composition.
        """

        attack_wave = None
        for unit in military_ratio:
            amount = military_ratio[unit]
            units = self.units(unit)

            if units.idle.amount >= amount:
                if attack_wave is None:
                    attack_wave = ControlGroup(units.idle)
                else:
                    attack_wave.add_units(units.idle)
        if attack_wave is not None:
            self.attack_waves.add(attack_wave)
Exemple #8
0
    def prepare_attack(self):
        """
        Prepares an attack wave when ready.
        """
        total = 0
        for unit in self.military_distribution:
            units = self.units(unit)
            total += units.idle.amount

        if total >= self.num_troops_per_wave:
            attack_wave = None

            for unit in self.military_distribution:
                units = self.units(unit)

                if attack_wave is None:
                    attack_wave = ControlGroup(units.idle)
                else:
                    attack_wave.add_units(units.idle)

            self.attack_waves.add(attack_wave)
    async def attack(self):
        if self.units(MARINE).idle.amount > 15:
            cg = ControlGroup(self.units(MARINE).idle)
            self.attack_groups.add(cg)

        for ac in list(self.attack_groups):
            alive_units = ac.select_units(self.units)
            if alive_units.exists and alive_units.idle.exists:
                target = self.known_enemy_structures.random_or(
                    self.enemy_start_locations[0]).position
                for marine in ac.select_units(self.units):
                    await self.do(marine.attack(target))
            else:
                self.attack_groups.remove(ac)
Exemple #10
0
    async def on_step(self, iteration):
        if iteration == 0:
            if iteration == 0:
                await self.chat_send("(glhf)")

#for selecting our Units

        if self.units(REAPER).idle.amount > 15:
            for reaper in self.units(REAPER).idle:
                #Making the initial population for the first 10 reapers
                if reaper.tag in self.reapergenes:
                    print("already done")
                else:
                    if len(self.reaperrewards.values()) > 2:
                        v = list(self.reaperrewards.values())
                        k = list(self.reaperrewards.keys())
                        curmax = 0
                        for i in range(10):
                            pick = random.randint(0, len(v) - 1)
                            if (v[pick] >= curmax):
                                curmax = v[pick]
                                curpick = k[pick]

                        self.reapergenes[reaper.tag] = [0, 0, 0]
                        self.reapergenes[
                            reaper.tag][0] = self.reapergenes[curpick][0]
                        self.reapergenes[
                            reaper.tag][1] = self.reapergenes[curpick][1]
                        self.reapergenes[
                            reaper.tag][2] = self.reapergenes[curpick][2]

                        if random.randint(1, 100) / 100 <= .50:
                            print("mutate")
                            print([
                                reaper.tag, self.reapergenes[reaper.tag],
                                "Son of:", curpick, self.reapergenes[curpick],
                                self.reaperrewards[curpick]
                            ])
                            #mutate
                            pick = random.randint(0, 2)
                            if (random.randint(1, 2) == 1):
                                print("minus .1")
                                self.reapergenes[reaper.tag][pick] -= .3
                            else:
                                print("plus .1")
                                self.reapergenes[reaper.tag][pick] += .3

                        print([
                            reaper.tag, self.reapergenes[reaper.tag],
                            "Son of:", curpick, self.reapergenes[curpick],
                            self.reaperrewards[curpick]
                        ])
                    else:  #since there are no rewarded reapers
                        seed = [0, 0, 0]

                        seed[0] = (random.randint(1, 100) / 100)
                        seed[1] = (random.randint(1, 100) / 100)
                        seed[2] = (random.randint(1, 100) / 100)
                        self.reapergenes[reaper.tag] = seed

                        #del v[v.index(max(v))]
            print(self.reapergenes)

            cg = ControlGroup(self.units(REAPER).idle)
            self.attack_groups.add(cg)

        for cc in self.units(UnitTypeId.COMMANDCENTER).ready.noqueue:
            if self.can_afford(
                    SCV) and self.workers.amount < 20 and cc.noqueue:
                await self.do(cc.train(SCV))

        cc = self.units(COMMANDCENTER).ready.first
        bobthebuilder = self.units(SCV)[0]

        #We must construct additional pylons
        if self.supply_left < 2:
            if self.can_afford(
                    SUPPLYDEPOT) and self.already_pending(SUPPLYDEPOT) < 2:
                await self.build(SUPPLYDEPOT,
                                 near=cc.position.towards(
                                     self.game_info.map_center, 5))


#For building reapers
        if self.units(BARRACKS).amount < 3 or (
                self.minerals > 400 and self.units(BARRACKS).amount < 5):
            if self.can_afford(BARRACKS):
                err = await self.build(BARRACKS,
                                       near=cc.position.towards(
                                           self.game_info.map_center, 5))

        elif self.units(BARRACKS).ready.exists and self.units(
                REFINERY).ready.exists:
            barracks = self.units(BARRACKS).ready
            if self.can_afford(REAPER) and barracks.noqueue:
                await self.do(barracks.random.train(REAPER))
        '''
        if self.units(MISSILETURRET).amount < 3:
            if self.can_afford(MISSILETURRET):
                err = await self.build(MISSILETURRET, near=cc.position.towards(self.game_info.map_center, 5))  
        
        if self.units(ENGINEERINGBAY).amount < 1:
            if self.can_afford(ENGINEERINGBAY):
                err = await self.build(ENGINEERINGBAY, near=cc.position.towards(self.game_info.map_center, 5))        
        '''
        if self.refinerys < 2:
            if self.can_afford(REFINERY):
                worker = self.workers.random
                target = self.state.vespene_geyser.closest_to(worker.position)
                err = await self.do(bobthebuilder.build(REFINERY, target))
                if not err:
                    self.refinerys += 1

        for a in self.units(REFINERY):
            if a.assigned_harvesters < a.ideal_harvesters:
                w = self.workers.closer_than(20, a)
                if w.exists:
                    await self.do(w.random.gather(a))

        #TODO hash the reapers with info on health wieghts
        #TODO hash the enemy health totals to reward focusing
        #TODO reward reaper health maximization by hashing reaper health changes
        #TODO Create population
        #genes relevant to reaper movement
        #reaper attack allocation
        #weight for
        #
        #
        barracks = self.units(BARRACKS).ready
        for ac in list(self.attack_groups):
            alive_units = ac.select_units(self.units)
            total_x = []
            total_y = []
            total_z = []
            if alive_units.amount > 10:
                #Calculating which units are better to attack
                for reaper in ac.select_units(self.units):

                    ting = 10
                    targets = self.known_enemy_units.prefer_close_to(reaper)
                    self.enemyreward = {}
                    self.enemyindexer = {}
                    for enemy in targets:
                        if ting == 0:
                            break

                        self.enemyindexer[enemy.tag] = enemy
                        #the negative 1 gives more reward for enemies that are easily killed by your team/
                        if reaper.tag in self.reapergenes:
                            self.enemyreward[enemy.tag] = -1 * (
                                enemy.health - alive_units.amount *
                                8) * self.reapergenes[reaper.tag][1]
                            #since they are already in order of closeness we can add a value for being closest
                            #and decrement it each time to give different rewards
                            self.enemyreward[enemy.tag] += self.reapergenes[
                                reaper.tag][2] * (ting)

                        ting -= 1

                if len(self.enemyreward.values()) > 0:
                    v = list(self.enemyreward.values())
                    k = list(self.enemyreward.keys())

                    selectedtarget = self.enemyindexer[k[v.index(max(v))]]
                    target = selectedtarget.position
                else:
                    enemystart = 1
                    target = self.enemy_start_locations[0]

                #For loop deciding what a reaper should do
                for reaper in ac.select_units(self.units):

                    if reaper.tag in self.reaper_health and reaper.tag in self.reapergenes:
                        #If you've been hit kite away towards a safe place based on your genes
                        if reaper.health < self.reaper_health[reaper.tag]:
                            await self.do(
                                reaper.move(
                                    reaper.position.towards(
                                        barracks.random.position,
                                        self.reapergenes[reaper.tag][2] * 10)))

                        #if you are too injured to fight, run away
                        elif reaper.health < reaper.health_max * .4:
                            await self.do(reaper.move(barracks.random.position)
                                          )
                        #if you aren't attacking or running you have to fight
                        elif reaper.is_idle:
                            await self.do(reaper.attack(target))

                    #Setting up a reward slot for new reapers
                    if reaper.tag not in self.reaper_health:
                        self.reaperrewards[reaper.tag] = 0

                    #rewarding reapers for taking damage and surviving it
                    if reaper.tag in self.reaper_health:
                        self.reaperrewards[reaper.tag] += 60 - reaper.health

                    #rewarding reapers for Killing units
                    if reaper.tag in self.reaperlasttarget:
                        #reward for a unit killed
                        if not self.reaperlasttarget[reaper.tag].health > 0:
                            self.reaperrewards[reaper.tag] += 2000
                            del self.reaperlasttarget[reaper.tag]
                        #reward for a unit maimed
                        elif self.reaperlasttarget[
                                reaper.
                                tag].health < self.reaperlasttargethealth[
                                    reaper.tag]:
                            self.reaperrewards[reaper.tag] += .1 * (
                                self.reaperlasttargethealth[reaper.tag] -
                                self.reaperlasttarget[reaper.tag].health)

                    #resetting sentinel dictionaries
                    if len(self.enemyreward.values()) > 0:
                        self.reaperlasttarget[reaper.tag] = selectedtarget
                        self.reaperlasttargethealth[
                            reaper.tag] = selectedtarget.health
                        self.reaper_health[reaper.tag] = reaper.health
            #if we don't have enough units to feasably continue the fight run back home
            else:
                for reaper in ac.select_units(self.units):
                    await self.do(reaper.move(cc.position))
                self.attack_groups.remove(ac)
Exemple #11
0
class ArmyManager:
    def __init__(self, bot):
        self.bot = bot
        self.logger = bot.logger
        self.opponent = bot.opponent

        self.first_overlord_tag = None
        self.first_overlord_ordered = False
        self.early_warning_overlord_tag = None
        self.early_warning_overlord_ordered = False

        self.has_verified_front_door = False
        self.all_combat_units = None
        self.reserve = ControlGroup([])
        self.harassing_base_scouts = ControlGroup([])
        self.no_mans_expansions_scouts = ControlGroup([])
        self.muta_flankers = ControlGroup([])
        self.base_defenders = ControlGroup([])

    def deferred_init(self):
        self.first_overlord_tag = self.bot.units(UnitTypeId.OVERLORD).first.tag

    def refresh(self):
        self.all_combat_units = self.bot.units(UnitTypeId.ZERGLING).ready | self.bot.units(UnitTypeId.ROACH).ready | self.bot.units(UnitTypeId.HYDRALISK).ready | self.bot.units(UnitTypeId.MUTALISK).ready
        self.strength = util.get_units_strength(self.bot, self.all_combat_units)
        """
        ControlGroup is actually just a set of unit tags. When units whose tag is added to a CG die, their tags remains in the CG. This is probably not
        a problem, but we could also cleanup the CGs by cycling tags into units and then back to tags. Not sure if worth it performance-wise.
        1) alive = self.bot.units.ready.tags_in(self.reserve)
        2) alive = self.reserve.select_units(self.all_combat_units)
        """

        # Add unassigned units to reserve
        unassigned = self.all_combat_units.tags_not_in(self.reserve | self.harassing_base_scouts | self.no_mans_expansions_scouts | self.muta_flankers | self.base_defenders)
        if unassigned:
            self.reserve.add_units(unassigned)

        # Early warning lookout against proxy rax
        overlords = self.bot.units(UnitTypeId.OVERLORD)
        early_warning = overlords.find_by_tag(self.early_warning_overlord_tag)
        if not early_warning:
            volunteers = overlords.ready.tags_not_in([self.first_overlord_tag])
            if volunteers:
                self.early_warning_overlord_tag = volunteers.first.tag
                self.early_warning_overlord_ordered = False
                self.logger.log("Found new volunteer to become early warning lookout")

        self._reinforce_from_reserve_if_empty(self.muta_flankers, UnitTypeId.MUTALISK, 10)
        self._reinforce_from_reserve_if_empty(self.harassing_base_scouts, UnitTypeId.ZERGLING, 1, True)
        if self.bot.time > 120:
            self._reinforce_from_reserve_if_empty(self.no_mans_expansions_scouts, UnitTypeId.ZERGLING, 1, True)

    def _reinforce_from_reserve_if_empty(self, group, unit_type, up_to=200, drone_fallback=False):
        survivors = group.select_units(self.bot.units)
        if not survivors:
            reserves = self.reserve.select_units(self.all_combat_units(unit_type)).take(up_to, require_all=False)
            for reserve in reserves:
                self.reserve.remove_unit(reserve)
                group.add_unit(reserve)
            if len(reserves) == 0 and drone_fallback:
                drones_available = self.bot.units(UnitTypeId.DRONE)  # TODO filter drones that have a special job
                if drones_available:
                    group.add_unit(drones_available.first)

    async def kamikaze(self):
        bot = self.bot
        if not bot.hq_loss_handled:
            try:
                actions = []
                bot.hq_loss_handled = True
                self.logger.warn("All townhalls lost, loss is probably imminent!")
                if bot.enemy_start_locations:
                    for unit in bot.units(UnitTypeId.DRONE) | bot.units(UnitTypeId.QUEEN) | self.all_combat_units:
                        actions.append(unit.attack(bot.enemy_start_locations[0]))
                    await bot.do_actions(actions)
            except Exception as e:
                print(e)

    def guess_front_door(self):
        bot = self.bot
        # Bot has main_base_ramp but it sometimes points to the back door ramp if base has multiple ramps
        bot.ramps_distance_sorted = sorted(bot._game_info.map_ramps, key=lambda ramp: ramp.top_center.distance_to(bot.start_location))
        doors = []
        for ramp in bot.ramps_distance_sorted:
            if ramp.top_center.distance_to(bot.start_location) <= MAX_BASE_DOOR_RANGE:
                doors.append(ramp)
        if len(doors) == 1:
            self.logger.log("This base seems to have only one ramp")
            return doors[0].top_center
        else:
            self.logger.warn("Base seems to have several ramps, scout will verify")
            return bot.start_location.towards(bot.game_info.map_center, 10)

    def _unit_dispersion(self, units):
        if units:
            center = units.center
            return statistics.median([unit.distance_to(center) for unit in units])
        else:
            return 0

    def get_seek_and_destroy_actions(self, units):
        # TODO sub-optimize by sending mutas to map corners
        actions = []
        for unit in units:
            if self.opponent.units:
                point = self.opponent.units.random.position.random_on_distance(random.randrange(5, 15))
            else:
                point = self.bot.map.get_random_point()
            actions.append(unit.attack(point))
        return actions

    def _large_enough_army(self, strength):
        enough = (ARMY_SIZE_BASE_LEVEL + ((self.bot.time / 60) * ARMY_SIZE_TIME_MULTIPLIER))
        if Strategy.PROXY in self.opponent.strategies:
            enough = 50
        return strength >= enough or self.bot.supply_used > ARMY_SIZE_MAX

    # Attack to enemy base
    def get_army_actions(self):
        bot = self.bot
        actions = []

        # TODO FIXME This should not manipulate reserve but only attack group
        units = self.reserve.select_units(bot.units)
        if units:
            bot.debugger.world_text("center", units.center)
            towards = None
            if self._large_enough_army(util.get_units_strength(bot, units)):

                towards = bot.opponent.get_next_potential_building_closest_to(bot.army_attack_point)
                if towards is None and Strategy.HIDDEN_BASE not in self.opponent.strategies:
                    self.logger.warn("Army does not know where to go, time to seek & destroy!")
                    self.opponent.strategies.add(Strategy.HIDDEN_BASE)
                elif towards and Strategy.HIDDEN_BASE in self.opponent.strategies:
                    self.logger.log("Found enemy from hiding!")
                    self.opponent.strategies.remove(Strategy.HIDDEN_BASE)

                if Strategy.HIDDEN_BASE in self.opponent.strategies:
                    return self.get_seek_and_destroy_actions(units.idle)

                if towards:
                    leader = units.closest_to(towards)
                    if leader:
                        bot.debugger.world_text("leader", leader.position)
                        main_pack = units.closer_than(ARMY_MAIN_FORCE_RADIUS, leader.position)
                        if main_pack.amount > 1:
                            bot.debugger.world_text("blob", main_pack.center)
                            dispersion = self._unit_dispersion(main_pack)
                            if dispersion < ARMY_MAIN_FORCE_DISPERSION_MAX: # Attack!
                                self.logger.debug(f"Tight main force advancing ({dispersion:.0f})")
                            else: # Regroup, too dispersed
                                self.logger.log(f"Main force is slightly dispersed ({dispersion:.0f})")
                                towards = leader.position
                        else:
                            self.logger.warning(f"Leader is too alone, pulling back!")
                            towards = units.center

            else: # Retreat, too weak!
                self.logger.debug(f"Army is too small, retreating!")
                towards = bot.hq_front_door

            bot.debugger.world_text("towards", towards)
            bot.army_attack_point = towards
            for unit in units:
                actions.append(unit.attack(bot.army_attack_point))

        return actions

    def flank(self):
        actions = []
        mutas = self.muta_flankers.select_units(self.bot.units).idle
        if mutas:
            for muta in mutas:
                actions.append(muta.move(self.bot.map.flanker_waypoint, queue=False))
                actions.append(muta.move(self.bot.map.opponent_corner, queue=True))
                actions.append(muta.attack(self.opponent.known_hq_location, queue=True))
                actions.append(muta.attack(self.opponent.known_natural, queue=True))
        return actions

    def scout_and_harass(self):
        actions = []
        scouts = self.harassing_base_scouts.select_units(self.bot.units)
        if scouts:
            for scout in scouts:
                # Harass workers
                if self.opponent.known_hq_location and scout.distance_to(self.opponent.known_hq_location) < 3:
                    worker_enemies = self.opponent.units(UnitTypeId.DRONE) | self.opponent.units(UnitTypeId.PROBE) | self.opponent.units(UnitTypeId.SCV)
                    if worker_enemies and not scout.is_attacking:
                        victim = worker_enemies.closest_to(scout.position)
                        actions.append(scout.attack(victim))
                else:
                    location = self.opponent.get_next_scoutable_location()
                    if location:
                        actions.append(scout.move(location))
                # Kite
                if self.opponent.units:
                    enemies_closeby = self.opponent.units.filter(lambda unit: unit.can_attack_ground).closer_than(2, scout)
                    if enemies_closeby and scout.health_percentage < 0.4:
                        closest_enemy = enemies_closeby.closest_to(scout)
                        actions.append(scout.move(util.away(scout.position, closest_enemy.position, 4)))

                # Home base door verification
                if not self.has_verified_front_door:
                    for ramp in self.bot._game_info.map_ramps:
                        if scout.distance_to(ramp.top_center) < 6:
                            self.has_verified_front_door = True
                            self.bot.hq_front_door = ramp.top_center
                            self.logger.log("Scout verified front door")
        return actions

    def scout_no_mans_expansions(self):
        actions = []
        scouts = self.no_mans_expansions_scouts.select_units(self.bot.units)
        if scouts.idle:
            exps = list(self.bot.expansion_locations)
            if self.opponent.known_hq_location:
                exps.remove(self.opponent.known_hq_location)
            if self.opponent.known_natural:
                exps.remove(self.opponent.known_natural)
            for scout in scouts:
                self.logger.debug(f"Sending scout {scout} to no man's land")
                actions.append(scout.move(self.bot.hq_front_door, queue=False))
                for exp in exps:
                    actions.append(scout.move(exp, queue=True))
        return actions

    # Scout home base with overlords
    def patrol_with_overlords(self):
        actions = []
        overlords = self.bot.units(UnitTypeId.OVERLORD)

        # First overlord will scout enemy natural
        firstborn = overlords.find_by_tag(self.first_overlord_tag)
        if firstborn and not self.first_overlord_ordered:
            if self.opponent.known_natural:
                near_enemy_front_door = self.opponent.known_natural.towards(self.opponent.known_hq_location, 4)
                safepoint_near_natural = util.away(self.opponent.known_natural, self.opponent.known_hq_location, 10)
                actions += [firstborn.move(near_enemy_front_door), firstborn.move(safepoint_near_natural, queue=True)]
            else:
                for enemy_loc in self.bot.enemy_start_locations:
                    actions.append(firstborn.move(enemy_loc, queue=True))
                actions.append(firstborn.move(self.bot.start_location, queue=True))
            self.first_overlord_ordered = True

        # Second overlord will scout proxy rax
        early_warner = overlords.find_by_tag(self.early_warning_overlord_tag)
        if early_warner:
            if Strategy.PROXY not in self.opponent.strategies:
                if not self.early_warning_overlord_ordered:
                    hq = self.bot.start_location
                    center = self.bot.game_info.map_center
                    dist_between_hq_and_center = hq.distance_to(center)
                    halfway = hq.towards(center, dist_between_hq_and_center * 0.7)
                    actions.append(early_warner.move(halfway, queue=False))
                    actions.append(early_warner.patrol(halfway.random_on_distance(5), queue=True))
                    actions.append(early_warner.patrol(halfway.random_on_distance(5), queue=True))
                    self.early_warning_overlord_ordered = True
            else:
                actions.append(early_warner.move(self.bot.start_location, queue=False))

        # Others will patrol around hq
        if len(overlords) < 4:
            patrol = self.bot.hq_front_door.random_on_distance(random.randrange(3, 8))
        else:
            patrol = self.bot.start_location.random_on_distance(40)
        for overlord in overlords.idle.tags_not_in([self.first_overlord_tag, self.early_warning_overlord_tag]):
            actions.append(overlord.move(patrol))
        return actions

    def is_worker_rush(self, town, enemies_approaching):
        enemies = enemies_approaching.closer_than(6, town)
        worker_enemies = enemies(UnitTypeId.DRONE) | enemies(UnitTypeId.PROBE) | enemies(UnitTypeId.SCV)
        if worker_enemies.amount > 1 and (worker_enemies.amount / enemies.amount) >= 0.8:
            return True
        return False

    def _get_enemies_that_should_be_evicted_from_base(self, town):
        enemies = self.opponent.units.closer_than(6, town).exclude_type(UnitTypeId.OVERLORD)
        if enemies:
            return enemies
        else:
            if self.opponent.structures:
                buildings = self.opponent.structures.closer_than(15, town)
                if buildings:
                    return buildings
        return None

    # Base defend
    def base_defend(self):
        actions = []
        for town in self.bot.townhalls:
            if self.opponent.units:
                enemies = self._get_enemies_that_should_be_evicted_from_base(town)
                if enemies and enemies.not_flying:  # Ground enemies are in this town
                    enemy = enemies.closest_to(town)

                    # Gather defenders
                    new_defenders = self.reserve.select_units(self.all_combat_units).idle.closer_than(30, town)
                    self.reserve.remove_units(new_defenders)
                    self.base_defenders.add_units(new_defenders)

                    armed_and_existing_defenders = self.base_defenders.select_units(self.bot.units)
                    if not armed_and_existing_defenders:
                        drones = self.bot.units(UnitTypeId.DRONE).closer_than(15, town)
                        if drones:
                            self.base_defenders.add_units(drones)
                            self.logger.log(f"Resorting to add {drones.amount} drones to defenders")

                    # TODO FIXME This will probably bug if several bases are under attack at the same time
                    all_defenders = self.base_defenders.select_units(self.bot.units)
                    if all_defenders:
                        self.logger.log(f"Defending our base against {enemies.amount} enemies with {all_defenders.amount} defenders: {all_defenders}")
                        for defender in all_defenders:
                            actions.append(defender.attack(enemy.position))

                    # if self.is_worker_rush(town, enemies) or Strategy.CANNON_RUSH in self.opponent.strategies:
                    #     self.logger.warn("We are being cheesed!")
                    #     for drone in bot.units(UnitTypeId.DRONE).closer_than(30, town):
                    #         actions.append(drone.attack(enemy.position))

                else:
                    if enemies and enemies.flying:
                        self.logger.warn("Enemies (not-overlords) flying in our base, not implemented!")

            # Base defenders back to work
            if self.base_defenders and not (self.opponent.units and self.opponent.units.closer_than(10, town).exclude_type(UnitTypeId.OVERLORD)):
                defenders = self.base_defenders.select_units(self.bot.units)
                self.logger.log(f"{defenders.amount} defenders calming down")
                for unit in defenders:
                    self.base_defenders.remove_unit(unit)
                    if unit.type_id == UnitTypeId.DRONE:
                        actions.append(unit.move(town.position))
                    else:
                        self.reserve.add_unit(unit)
                        actions.append(unit.move(self.bot.hq_front_door))

        return actions
Exemple #12
0
 async def add_marines_to_cg(self, iteration):
     if self.units(MARINE).idle.amount > 15 + (
             2 * self.units(BARRACKS).ready.amount) and iteration % 42 == 0:
         idle_marines = ControlGroup(self.units(MARINE).idle)
         self.attack_groups.add(idle_marines)
Exemple #13
0
    async def on_step(self, iteration):

            # State
        Available_Reapers = []
        Cooldown_Reapers = []
        Enemy_Units = []


        for reaper in self.units(REAPER):
            abilities = await self.get_available_abilities(reaper)
            if AbilityId.KD8CHARGE_KD8CHARGE in abilities:
                Available_Reapers.append(reaper)
            else:
                Cooldown_Reapers.append(reaper)
        for enemy in self.known_enemy_units:
            if (enemy in self.prev_Enemy) == False and enemy.is_structure == False:
                Enemy_Units.append(enemy)


        current_state = [
            Available_Reapers,
            Cooldown_Reapers,
            Enemy_Units,
        ]

            # Reward
        reward = 0
        if self.prev_action != None:

            for bomber in Cooldown_Reapers:
                reward += 1000
            for lazy in Available_Reapers:
                reward += -100
            for enemy in Enemy_Units:
                reward += 100

            self.qlearn.learn(str(self.prev_state), self.prev_action, reward, str(current_state))
            # Choose action
        rl_action = self.qlearn.choose_action(str(current_state))
        smart_action = smart_actions[rl_action]
            # Prep next step
        self.prev_score = reward
        self.prev_state = current_state
        self.prev_action = rl_action
        self.prev_Enemy = Enemy_Units
            # Actions
        if smart_action == ACTION_DO_NOTHING:
                # Run Away
            for reaper in self.units(REAPER):
                targetx = (random.randrange(0, 100))/20
                targety = (random.randrange(0, 100))/20
                home = Pointlike((24 + targetx, 24 + targety))
                moveto = reaper.position
                await self.do(reaper.move(moveto))

        if smart_action == ACTION_KD8_CHARGE:
                # default spot on the map
            targetx = (random.randrange(0, 100))/20
            targety = (random.randrange(0, 100))/20
            home = Pointlike((20 + targetx, 20 + targety))
            moveto = Point2(home)
                # throw grenade at enemy
            if len(Available_Reapers) > 5 and len(Enemy_Units) > 0:
                for reaper in Available_Reapers:
                    if reaper == self.units(REAPER).closest_to(Enemy_Units[0].position):
                        bomb = Point3(Enemy_Units[0].position)
                        await self.do(reaper(KD8CHARGE_KD8CHARGE, bomb))

                    else:
                        await self.do(reaper.move(moveto))
            else:
                for reaper in Available_Reapers:
                    await self.do(reaper.move(moveto))


        if iteration == 0:
            if iteration == 0:
                await self.chat_send("(glhf)")

#creates control groups of 14 reapers
        if self.units(REAPER).idle.amount > 14:
            cg = ControlGroup(self.units(REAPER).idle)
            self.attack_groups.add(cg)

# trains workers
        for cc in self.units(UnitTypeId.COMMANDCENTER).ready.noqueue:
            if self.can_afford(SCV) and self.workers.amount < 20 and cc.noqueue:
                await self.do(cc.train(SCV))

        cc = self.units(COMMANDCENTER).ready.first
        bobthebuilder = self.units(SCV)[0]

#build supply depots
        if self.supply_left < 2:
            if self.can_afford(SUPPLYDEPOT) and self.already_pending(SUPPLYDEPOT) < 2:
                await self.build(SUPPLYDEPOT, near=cc.position.towards(self.game_info.map_center, 5))

#build barracks
        if self.units(BARRACKS).amount < 3: # or (self.minerals > 400 and self.units(BARRACKS).amount < 5):
            if self.can_afford(BARRACKS):
                err = await self.build(BARRACKS, near=cc.position.towards(self.game_info.map_center, 5))
#train reapers
        elif self.units(BARRACKS).ready.exists and self.units(REAPER).amount < 28:
            barracks = self.units(BARRACKS).ready
            if self.can_afford(REAPER) and barracks.noqueue:
                await self.do(barracks.random.train(REAPER))
#build refinerys
        if self.refinerys < 2:
            if self.can_afford(REFINERY):
                worker = self.workers.random
                target = self.state.vespene_geyser.closest_to(worker.position)
                err = await self.do(bobthebuilder.build(REFINERY, target))
                if not err:
                    self.refinerys += 1
#workers in the mines/gas
        for a in self.units(REFINERY):
            if a.assigned_harvesters < a.ideal_harvesters:
                w = self.workers.closer_than(20, a)
                if w.exists:
                    await self.do(w.random.gather(a))
    async def on_step(self, iteration):

        if iteration == 0:
            if iteration == 0:
                await self.chat_send("(glhf)")

#creates control groups of 14 reapers
        if self.units(REAPER).idle.amount > 14:
            cg = ControlGroup(self.units(REAPER).idle)
            self.attack_groups.add(cg)

# trains workers
        for cc in self.units(UnitTypeId.COMMANDCENTER).ready.noqueue:
            if self.can_afford(
                    SCV) and self.workers.amount < 20 and cc.noqueue:
                await self.do(cc.train(SCV))

        cc = self.units(COMMANDCENTER).ready.first
        bobthebuilder = self.units(SCV)[0]

        #build supply depots
        if self.supply_left < 2:
            if self.can_afford(
                    SUPPLYDEPOT) and self.already_pending(SUPPLYDEPOT) < 2:
                await self.build(SUPPLYDEPOT,
                                 near=cc.position.towards(
                                     self.game_info.map_center, 5))

#build barracks
        if self.units(
                BARRACKS
        ).amount < 1:  # or (self.minerals > 400 and self.units(BARRACKS).amount < 5):
            if self.can_afford(BARRACKS):
                err = await self.build(BARRACKS,
                                       near=cc.position.towards(
                                           self.game_info.map_center, 5))
#train reapers
        elif self.units(BARRACKS).ready.exists and self.units(
                REFINERY).ready.exists and self.units(REAPER).amount < 1:
            barracks = self.units(BARRACKS).ready
            if self.can_afford(REAPER) and barracks.noqueue:
                await self.do(barracks.random.train(REAPER))
#build refinerys
        if self.refinerys < 2:
            if self.can_afford(REFINERY):
                worker = self.workers.random
                target = self.state.vespene_geyser.closest_to(worker.position)
                err = await self.do(bobthebuilder.build(REFINERY, target))
                if not err:
                    self.refinerys += 1
#workers in the mines/gas
        for a in self.units(REFINERY):
            if a.assigned_harvesters < a.ideal_harvesters:
                w = self.workers.closer_than(20, a)
                if w.exists:
                    await self.do(w.random.gather(a))


#send out reapers
        if self.units(REAPER).amount > 0:
            for reaper in self.units(REAPER).idle:
                #randomize where bomb lands a bit
                x = self.Target.x - .5
                y = self.Target.y - .5
                rand = random.random() * 100
                randx = (rand / 100) + x
                rand = random.random() * 100
                randy = (rand / 100) + y
                lz = Pointlike((randx, randy))
                boom = Point2(lz)
                #use grenade
                abilities = await self.get_available_abilities(reaper)
                if AbilityId.KD8CHARGE_KD8CHARGE in abilities:
                    await self.do(reaper(KD8CHARGE_KD8CHARGE, boom))