Exemple #1
0
def test_position_point2(x1, y1, x2, y2):
    pos1 = Point2((x1, y1))
    pos2 = Point2((x2, y2))
    assert pos1.x == x1
    assert pos1.y == y1
    assert pos1.to2 == pos1
    assert pos1.to3 == Point3((x1, y1, 0))

    length1 = (pos1.x**2 + pos1.y**2)**0.5
    assert abs(pos1.length - length1) < 0.001
    if length1:
        normalized1 = pos1 / length1
        assert abs(pos1.normalized.is_same_as(pos1 / length1))
        assert abs(normalized1.length - 1) < 0.001
    length2 = (pos2.x**2 + pos2.y**2)**0.5
    assert abs(pos2.length - length2) < 0.001
    if length2:
        normalized2 = pos2 / length2
        assert abs(pos2.normalized.is_same_as(normalized2))
        assert abs(normalized2.length - 1) < 0.001

    assert isinstance(pos1.distance_to(pos2), float)
    assert isinstance(pos1.distance_to_point2(pos2), float)
    if 0 < x2:
        assert pos1.random_on_distance(x2) != pos1
        assert pos1.towards_with_random_angle(pos2, x2) != pos1
    assert pos1.towards_with_random_angle(pos2) != pos1
    if pos1 != pos2:
        dist = pos1.distance_to(pos2)
        intersections1 = pos1.circle_intersection(pos2, r=dist / 2)
        assert len(intersections1) == 1
        intersections2 = pos1.circle_intersection(pos2, r=dist * 2 / 3)
        assert len(intersections2) == 2
    neighbors4 = pos1.neighbors4
    assert len(neighbors4) == 4
    neighbors8 = pos1.neighbors8
    assert len(neighbors8) == 8

    assert pos1 + pos2 == Point2((x1 + x2, y1 + y2))
    assert pos1 - pos2 == Point2((x1 - x2, y1 - y2))
    assert pos1 * pos2 == Point2((x1 * x2, y1 * y2))
    if 0 not in {x2, y2}:
        assert pos2
        assert pos1 / pos2 == Point2((x1 / x2, y1 / y2))

    if pos1._distance_squared(pos2) < 0.1:
        assert pos1.is_same_as(pos2, dist=0.1)

    assert pos1.unit_axes_towards(pos2) == pos1.direction_vector(pos2)
 def position_around_unit(self,
                          pos: Union[Unit, Point2, Point3],
                          distance: int = 1,
                          step_size: int = 1,
                          exclude_out_of_bounds: bool = True):
     pos = pos.position.to2.rounded
     positions = {
         pos.offset(Point2((x, y)))
         for x in range(-distance, distance + 1, step_size)
         for y in range(-distance, distance + 1, step_size)
         if (x, y) != (0, 0)
     }
     if exclude_out_of_bounds:
         positions = {
             p
             for p in positions
             if 0 <= p[0] < self._game_info.pathing_grid.width
             and 0 <= p[1] < self._game_info.pathing_grid.height
         }
     return positions
Exemple #3
0
 def __init__(self, knowledge):
     self.knowledge: 'Knowledge' = knowledge
     self.ai: sc2.BotAI = knowledge.ai
     self.unit_values: UnitValue = knowledge.unit_values
     self.cd_manager: CooldownManager = knowledge.cooldown_manager
     self.pather: PathingManager = knowledge.pathing_manager
     self.cache: UnitCacheManager = knowledge.unit_cache
     self.delay_to_shoot = self.ai._client.game_step + 1.5
     self.enemy_groups: List[CombatUnits] = []
     self.ready_to_attack_ratio: float = 0.0
     self.center: Point2 = Point2((0, 0))
     self.group: CombatUnits
     self.engage_ratio = 0
     self.can_engage_ratio = 0
     self.closest_group: CombatUnits
     self.engaged: Dict[int, List[int]] = dict()
     self.engaged_power = ExtendedPower(knowledge.unit_values)
     self.our_power = ExtendedPower(knowledge.unit_values)
     self.closest_units: Dict[int, Optional[Unit]] = dict()
     self.move_type = MoveType.Assault
Exemple #4
0
    def find_influence_ground_path(
            self,
            start: Point2,
            target: Point2,
            target_index: int = 5,
            map_type: MapType = MapType.Ground) -> Point2:
        result = self.map.find_path_influence(map_type, start, target)
        path = result[0]

        if len(path) < 1:
            self.print(f"No path found {start}, {target}")
            return target

        if len(path) <= target_index:
            return target

        target = path[target_index]
        if self.debug:
            self.found_points_air.extend(path)
        return Point2((target[0], target[1]))
    async def on_step(self, iteration):
        if iteration == 1:
            self.cannon_positions = [
                Point2((max({p.x for p in d}), min({p.y for p in d})))
                for d in self.api.main_base_ramp.top_wall_depos
            ]

        for nexus in self.api.units(NEXUS).ready:
            await self.train_new_workers(nexus)
            await self.build_pylons(nexus)
            await self.build_gateway(nexus)
            await self.build_stargate(nexus, iteration)
            await self.manage_workers(nexus, iteration)
            await self.build_cannons(nexus, iteration)

        await self.build_gas_stuff()
        await self.build_cybernetics_core()
        await self.build_forge()
        await self.build_twilight_cauncil()
        await self.expanse(iteration)
Exemple #6
0
    async def build_ramp_depots(self, bot):
        depos = [
            Point2((max({p.x for p in d}), min({p.y for p in d})))
            for d in bot.main_base_ramp.top_wall_depos
        ]

        depo_count = (bot.units(SUPPLYDEPOT) |
                      bot.units(SUPPLYDEPOTLOWERED)).amount

        if bot.can_afford(SUPPLYDEPOT) and not bot.already_pending(SUPPLYDEPOT):
            if depo_count >= len(depos):
                return
            depo = list(depos)[depo_count]
            pos = await find_place_to_build(bot,
                                            self.agent,
                                            SUPPLYDEPOT,
                                            max_distance=2,
                                            position_close=depo,
                                            placement_step=1)
            await bot.do(self.agent.build(SUPPLYDEPOT, pos))
Exemple #7
0
def points_on_circumference_sorted(center: Point2,
                                   closest_to: Point2,
                                   radius,
                                   n=10) -> List[Point2]:
    """Calculates all points on the circumference of a circle, and sorts the points so that first one
    on the list has shortest distance to closest_to parameter."""
    points = points_on_circumference(center, radius, n)

    closest_point = closest_to.closest(points)
    closest_point_index = points.index(closest_point)

    sorted_points = []

    # Points from closest point to the end
    sorted_points.extend(points[closest_point_index:])

    # Points from start of list to closest point (closest point not included)
    sorted_points.extend(points[0:closest_point_index])

    return sorted_points
 def _set_sides(self):
     org = self.top
     pts = [self.bottom, self.right, self.left]
     res = self.map_data.closest_towards_point(points=pts, target=org)
     self.side_a = int(round(
         (res[0] + org[0]) / 2)), int(round((res[1] + org[1]) / 2))
     if res != self.bottom:
         org = self.bottom
         pts = [self.top, self.right, self.left]
         res = self.map_data.closest_towards_point(points=pts, target=org)
         self.side_b = int(round(
             (res[0] + org[0]) / 2)), int(round((res[1] + org[1]) / 2))
     else:
         self.side_b = int(round((self.right[0] + self.left[0]) / 2)), int(
             round((self.right[1] + self.left[1]) / 2))
     points = list(self.points)
     points.append(self.side_a)
     points.append(self.side_b)
     self.points = set([Point2((int(p[0]), int(p[1]))) for p in points])
     self.indices = self.map_data.points_to_indices(self.points)
Exemple #9
0
    def harass_move(self, unit, target):
        harassment_home = Point2(
            (self.bot.start_location.y, self.bot.enemy_start_locations[0].x))
        harass_target = self.bot.known_enemy_structures.closest_to(
            harassment_home
        ) if self.bot.known_enemy_structures.exists else self.bot.enemy_start_locations[
            0]

        if abs(unit.position.x - harassment_home.x) > 15:
            if unit.is_idle:
                self.actions.append(unit.move(harassment_home))
        elif unit.distance_to(target) > 25:
            if self.bot.iteration % 10 == 0:
                self.actions.append(unit.move(target))
        else:
            self.unit_move(unit,
                           harass_target,
                           order="harass",
                           retreat_to=harassment_home,
                           exclude_buildings=True)
Exemple #10
0
    async def spawn_units(self, ressources):
        """ Spawns units for the amount of ressources given, for each player """
        spawn_info = []
        self.wave_units = []
        ressources_left = ressources
        spawn_location = self._game_info.map_center - Point2((12, 12)) if self.race == Race.Zerg else self._game_info.map_center + Point2((12, 12))

        # Selecting random units to be spawned
        while ressources_left > 100:
            for unit in self.spawnable_units:
                unit_cost = self.calculate_cost(unit)
                # Adding the cost of previous tech unit if necessary
                if unit == UnitTypeId.BROODLORD:  unit_cost += self.calculate_cost(UnitTypeId.CORRUPTOR)
                elif unit == UnitTypeId.BANELING: unit_cost += self.calculate_cost(UnitTypeId.ZERGLING)
                elif unit == UnitTypeId.LURKER:   unit_cost += self.calculate_cost(UnitTypeId.HYDRALISK)
                elif unit == UnitTypeId.ZERGLING:   unit_cost = Cost(25, 0) # A pair of Zerglings cost 50 minerals

                unit_cost = unit_cost.minerals + unit_cost.vespene
                amount = int(random.uniform(0, 1)*int(ressources_left/unit_cost))
                if amount > 0 and random.uniform(0, 1) < 1./len(self.spawnable_units):
                    # Adding the unit to the list of units that will fight
                    # If the unit is already in the list, just adding the amount 
                    found = False
                    for i in range(len(self.wave_units)):
                        if self.wave_units[i][0] == unit:
                            self.wave_units[i][1] += amount
                            spawn_info[i][1] += amount
                            found = True
                    # Else, just create a new couple [unit, amount]
                    if not found:
                        spawn_info.append([unit, amount, spawn_location, self.playerID])
                        self.wave_units.append([unit, amount]) # Saving which units were spawned for this wave
                    # Updating ressources left
                    ressources_left -= unit_cost*amount
                    print("Added "+str(amount)+" unit "+str(unit)+" for a cost of "+str(unit_cost*amount)+" (already in list: "+str(found)+")")

        print("Ressources left for "+str(self.race)+": "+str(ressources_left)+" (Used "+str(ressources-ressources_left)+")")

        # Spawning selected units
        await self._client.debug_create_unit(spawn_info)
        print("Spawned units of wave "+str(self.nwaves))
Exemple #11
0
    async def attack(self, phys_swarm, iteration):
        if phys_swarm.amount > 10:
            orders = []

            # I should be able to dynamically add and subtract particles from the swarm... should only init once at beginning...
            if # The business of adding/subrtracting from swarm should be done in on created/destroyed methods...
            # do a comprehension that deletes matches positions and alive units?

            
            # calcuate the current
            self.log_swarm.current_cost = self.fitness(  self.log_swarm.position,  phys_swarm  )
            self.log_swarm.pbest_cost = self.fitness(  self.log_swarm.pbest_pos,  phys_swarm  )
            self.log_swarm.pbest_pos, self.log_swarm.pbest_cost = P.compute_pbest(  self.log_swarm  )


            #
            if np.min(  self.log_swarm.pbest_cost  ) < self.log_swarm.best_cost:
                self.log_swarm.best_pos, self.log_swarm.best_cost = self.my_topology.compute_gbest(  self.log_swarm  )



            #
            self.logical_swarm.velocity = self.my_topology.compute_velocity(  self.log_swarm  )
            self.logical_swarm.position = self.my_topology.compute_position(  self.log_swarm  )
            

            #this should be parameterized as aggression...
            wounded_units = phys_swarm.filter(lambda u: u.health_percentage <= .7)

            for unit in wounded_units:
                unit.move(self.townhalls.first.position)

            
            phys_swarm = phys_swarm.filter(lambda u: u.health_percentage > .7)

            for row, unit in zip(self.logical_swarm.position, phys_swarm):
                orders.append(unit.attack(Point2(Pointlike((row[0], row[1])))))
            # might need to get the nearest unit to do this... also check to make sure nearest unit not already assigned a task


            await self.do_actions(orders)
Exemple #12
0
    def test_points_on_circumference_sorted_with_unit_circle(self):
        center = Point2((0, 0))
        closest_to = Point2((0, 10))
        radius = 1
        n = 4

        points = points_on_circumference_sorted(center, closest_to, radius, n)

        assert len(points) == n
        # Points should be sorted so that first item has shortest distance to
        # closest_to parameter
        assert points[0] == Point2((0, 1))
        assert points[1] == Point2((-1, 0))
        assert points[2] == Point2((0, -1))
        assert points[3] == Point2((1, 0))
Exemple #13
0
    def get_next_plant_position(self, queen: Unit) -> Optional[Point2]:
        """ Tries to find a suitable position for queens to plant tumors at. """

        # Map is covered in creep, no need to place more tumors
        if not self.available_tumor_locations:
            return None

        # If queen is close to cached target location, don't return it instantly as creep could've evolved further while the queen was moving to target location
        old_cached_location: Optional[
            Point2] = self.queen_plant_location_cache.pop(queen.tag, None)

        queen_pos: Point2 = queen.position
        # TODO Find the closest by ground path instead of air distance
        target_pos: Point2 = queen_pos.closest(self.available_tumor_locations)

        # Find path and move along the path and find the last location where it is possible to plant a tumor
        path = self.knowledge.pathing_manager.path_finder_terrain.find_path(
            queen_pos, target_pos)[0]
        # TODO Figure out why sometimes a queen is stuck and doesn't plant a tumor
        for position_tuple in path[::-1]:
            if queen.tag in self.queen_plant_location_cache:
                # A position to plant tumor was found
                break
            position = Point2(position_tuple)
            if self.is_placeable(position):
                self.queen_plant_location_cache[queen.tag] = position

        # Return the position if one was found
        if queen.tag in self.queen_plant_location_cache:
            return self.queen_plant_location_cache[queen.tag]

        # If no position could be found, return old cached location if it existed
        if old_cached_location and self.is_placeable(old_cached_location):
            self.queen_plant_location_cache[queen.tag] = old_cached_location
            return old_cached_location

        # Mark queen location as possible creep tumor plant location if no location was found
        if queen.tag not in self.queen_plant_location_cache and self.is_placeable(
                queen_pos):
            self.queen_plant_location_cache[queen.tag] = queen_pos
            return queen_pos
    async def build_at(self,
                       building,
                       at,
                       worker=None,
                       detailed_failures=False):
        """
        Build the given building at the x,y coordinate of 'at'.
        Where the x,y coordinate denotes the top left corner of the structure's grid.
        Uses the given worker but by default will find the closest available worker.
        Returns True on success False otherwise.
        If detailed_failures is True (by default False) then it
        returns the ActionResult of the build command. If no worker can be found
        ActionResult.Error is returned.
        """
        if isinstance(at, Unit):
            raise "must specify top left position to place building, not the position of a unit"
        at[0] = int(at[0])
        at[1] = int(at[1])
        if building == None or at == None:
            return False

        placement = Point2([
            at[0] + self.building_size[building] / 2,
            at[1] + self.building_size[building] / 2
        ])
        worker = worker or self.select_build_worker(placement)

        if worker is None:
            if detailed_failures:
                return ActionResult.Error
            return False

        res = self.do(worker.build(building, placement))

        if detailed_failures:
            return res

        if res:  # returns an empty list if successful otherwise list given contains list of errors
            return False
        return True
Exemple #15
0
    def __init__(self, ai: sc2.BotAI, knowledge: 'Knowledge', x: int, y: int, x2: int, y2: int):
        self.ai = ai
        self.knowledge = knowledge
        self.cache: UnitCacheManager = self.knowledge.unit_cache
        self.bottom_left_x = x
        self.bottom_left_y = y
        self.top_right_x = x2
        self.top_right_y = y2
        self.center = Point2(((x + x2) / 2.0, (y + y2) / 2.0))
        self._x, self._y = self.center.rounded
        self.zone: Optional['Zone'] = None
        self.heat: float = 0
        self.stealth_heat: float = 0
        self.last_enemy_power = ExtendedPower(knowledge.unit_values)

        d2 = 15
        for zone in knowledge.expansion_zones:
            if zone.center_location.distance_to(self.center) < d2:
                if ai.get_terrain_height(zone.center_location) == ai.get_terrain_height(self.center):
                    # if zone == self.knowledge.own_main_zone:
                    #     print("MAIN ZONE")
                    self.zone = zone
Exemple #16
0
    def set_borders(self, r=20):
        self.coords = self.coords.rounded
        loc = self.coords

        row_start = loc.y - r
        row_end = loc.y + r
        col_start = loc.x - r
        col_end = loc.x + r
        points = []
        p_arr = []
        for (b, a), value in np.ndenumerate(
                self.grid
        ):  # TODO should take a sub matrix with the radius and not entire grid
            p = (a, b)
            # skip non placements which are zero
            if value == 0 or not self.same_height(Point2(p), self.coords):
                continue
            # skip if not in expansion zone
            if not (col_start <= a <= col_end):
                continue
            if not (row_start <= b <= row_end):
                continue
            points.append(p)
            point = [p[0], p[1]]
            p_arr.append(point)
        self.grid_points = points
        p_arr = np.array(p_arr)
        raw_edges = get_edge_points(p_arr, 0.8, only_outer=True)
        edges = []
        for edge in raw_edges:
            if not self.too_close_to_another_expansion(self.coords, edge):
                edges.append(edge)
        # final_edges = []
        # step = 1
        # for i in range(0,len(edges),step):
        #     final_edges.append(edges[i])
        # self.borders = final_edges
        self.borders = edges
        self.fix_borders()
Exemple #17
0
    def pending_building_positions(self, unit_type: UnitTypeId) -> List[Point2]:
        """Returns positions of buildings of the specified type that have either been ordered to be built by a worker
        or are currently being built."""
        positions: List[Point2] = list()
        creation_ability: AbilityId = self.ai._game_data.units[unit_type.value].creation_ability

        # Workers ordered to build
        for worker in self.ai.workers:  # type: Unit
            for order in worker.orders:  # type: UnitOrder
                if order.ability.id == creation_ability.id:
                    p2: Point2 = Point2.from_proto(order.target)
                    positions.append(p2)

        # Already building structures
        # Avoid counting structures twice for Terran SCVs.
        if self.knowledge.my_race != Race.Terran:
            pending_buildings: List[Point2] = list(
                map(lambda structure: structure.position, self.cache.own(unit_type).structure.not_ready)
            )
            positions.extend(pending_buildings)

        return positions
Exemple #18
0
    def get_path(self, source, dest) -> Optional[List[Point2]]:
        """
        Constructs and returns a path, if one exists, from source to dest (or a nearby eligible dest, if dest is not
        pathable).
        :return: A path in the form of a list of waypoints.
        """
        nearest_source = (round(source[0] / PATH_RESOLUTION) * PATH_RESOLUTION,
                          round(source[1] / PATH_RESOLUTION) * PATH_RESOLUTION)
        nearest_dest = (round(dest[0] / PATH_RESOLUTION) * PATH_RESOLUTION,
                        round(dest[1] / PATH_RESOLUTION) * PATH_RESOLUTION)
        if nearest_source == nearest_dest:
            # you are close enough that we consider you already there
            return None
        nearest_eligible_dest = self.find_eligible_dest(
            nearest_source, nearest_dest)
        if nearest_eligible_dest is None:
            # no destination in the neighborhood of dest which we can path to
            return None

        chunk_idx = int(nearest_eligible_dest[1] //
                        PATH_ROW_CHUNK_SIZE)  # is int() here redundant?
        path = []
        next_point = nearest_source
        # because we don't store the whole path in the file, we just store the next step, we need to walk
        # along these steps and save them in a list. This becomes the path
        while next_point[0] != nearest_eligible_dest[0] or next_point[
                1] != nearest_eligible_dest[1]:
            path.append(Point2(next_point))
            if (next_point[0], next_point[1], nearest_eligible_dest[0],
                    nearest_eligible_dest[1]) not in self.chunks[chunk_idx]:
                # should hopefully be impossible. This would mean that at one point it thought there was a path from
                # the start to the dest, but as it followed it it suddenly stopped being possible.
                return None
            next_point = self.chunks[chunk_idx][(next_point[0], next_point[1],
                                                 nearest_eligible_dest[0],
                                                 nearest_eligible_dest[1])]
        if len(path) == 0:
            return None
        return path
Exemple #19
0
    def _calc_chokes(self) -> None:
        # compute ChokeArea

        self._clean_plib_chokes()
        chokes = [
            c for c in self.c_ext_map.chokes
            if c.id not in self.overlapping_choke_ids
        ]
        self.map_chokes = self.map_ramps.copy()
        self.map_chokes.extend(self.map_vision_blockers)

        for choke in chokes:

            points = [Point2(p) for p in choke.pixels]
            if len(points) > 0:
                new_choke_array = self.points_to_numpy_array(points)
                cm = center_of_mass(new_choke_array)
                cm = int(cm[0]), int(cm[1])
                areas = self.where_all(cm)

                new_choke = RawChoke(map_data=self,
                                     array=new_choke_array,
                                     raw_choke=choke)
                for area in areas:

                    if isinstance(area, Region):
                        area.region_chokes.append(new_choke)
                        new_choke.areas.append(area)
                    if area.is_choke and not area.is_ramp and not area.is_vision_blocker:
                        self.polygons.remove(new_choke)
                        area.points.update(new_choke.points)
                        new_choke = None
                        break

                if new_choke:
                    self.map_chokes.append(new_choke)
            else:  # pragma: no cover
                logger.debug(
                    f" [{self.map_name}] Cant add {choke} with 0 points")
    async def control_scouting_reaper(self):
        '''Reaper moves to enemy location at the beginning of the game.'''
        for r in self.units(REAPER):
            if r:
                enemy_start_loc = self.enemy_start_locations[0]
                self.combinedActions.append(r.move(enemy_start_loc))
                print(self.find_friendly_unit_pos(r), 'r unit pos')
                print(self.find_closest_enemy_threat(r), 'enemy threat pos')
            enemy = self.known_enemy_units.exists
            if enemy:
                enemy_threat = self.find_closest_enemy_threat(r)
                unit_power = (r.health + r.shield) / r.ground_dps
                enemy_unit_power = (enemy_threat.health + enemy_threat.shield
                                    ) / enemy_threat.ground_dps
                #Update values through self.map (array)
                new_harass_position = self.Micro.influence_map(
                    self.map, enemy_threat.ground_range, enemy_unit_power,
                    enemy_threat)

                ## new_harass_position = self.Micro.harass_micro_avg(self, self.find_friendly_unit_pos(r), self.find_closest_enemy_workers(r), self.find_closest_enemy_threat(r))
                #convert new_harass_position to Point2 position tuple.
                new_harass_position_point2 = Point2(tuple(new_harass_position))
                #move_closer_to_probes = working on function atm
                if r.weapon_cooldown != 0:
                    self.combinedActions.append(
                        r.move(new_harass_position_point2))
                    self.Micro.influence_map(self.map,
                                             enemy_threat.ground_range,
                                             enemy_unit_power, enemy_threat)
                else:
                    self.combinedActions.append(
                        r.attack(self.find_closest_enemy_worker(r)))
                    self.Micro.influence_map(self.map,
                                             enemy_threat.ground_range,
                                             enemy_unit_power, enemy_threat)
                if r.health_percentage < 45 / 60:
                    self.combinedActions.append(
                        r.move(self.game_info.map_center))
Exemple #21
0
    async def on_step(self, iteration):
        cc = self.units(COMMANDCENTER)
        if not cc.exists:
            return
        else:
            cc = cc.first

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


        # Raise depos when enemies are nearby
        for depo in self.units(SUPPLYDEPOT).ready:
            for unit in self.known_enemy_units.not_structure:
                if unit.position.to2.distance_to(depo.position.to2) < 15:
                    break
            else:
                await self.do(depo(MORPH_SUPPLYDEPOT_LOWER))

        # Lower depos when no enemies are nearby
        for depo in self.units(SUPPLYDEPOTLOWERED).ready:
            for unit in self.known_enemy_units.not_structure:
                if unit.position.to2.distance_to(depo.position.to2) < 10:
                    await self.do(depo(MORPH_SUPPLYDEPOT_RAISE))
                    break

        depos = [
            Point2((max({p.x for p in d}), min({p.y for p in d})))
            for d in self.main_base_ramp.top_wall_depos
        ]

        depo_count = (self.units(SUPPLYDEPOT) | self.units(SUPPLYDEPOTLOWERED)).amount

        if self.can_afford(SUPPLYDEPOT) and not self.already_pending(SUPPLYDEPOT):
            if depo_count >= len(depos):
                return
            depo = list(depos)[depo_count]
            r = await self.build(SUPPLYDEPOT, near=depo, max_distance=2, placement_step=1)
    async def post_update(self):
        if self.debug:  # and self.chat_count < self.ai.time / 15:
            self.chat_count += 1
            idle = len(self.roles[UnitTask.Idle.value].tags)
            building = len(self.roles[UnitTask.Building.value].tags)
            gathering = len(self.roles[UnitTask.Gathering.value].tags)
            scouting = len(self.roles[UnitTask.Scouting.value].tags)
            moving = len(self.roles[UnitTask.Moving.value].tags)
            fighting = len(self.roles[UnitTask.Fighting.value].tags)
            defending = len(self.roles[UnitTask.Defending.value].tags)
            attacking = len(self.roles[UnitTask.Attacking.value].tags)
            reserved = len(self.roles[UnitTask.Reserved.value].tags)
            hallucination = len(self.roles[UnitTask.Hallucination.value].tags)

            enemy_total_power: ExtendedPower = self.knowledge.enemy_units_manager.enemy_total_power
            power_text = f'{enemy_total_power.power} ({enemy_total_power.ground_power}/{enemy_total_power.air_power})'

            # msg = f'{self.ai.time_formatted} I{idle} B{building} G{gathering} S{scouting} M{moving} ' \
            #     f'F{fighting} D{defending} A{attacking} R{reserved} H{hallucination} ETP{power_text}'
            msg = f'I{idle} B{building} G{gathering} S{scouting} M{moving} ' \
                f'F{fighting} D{defending} A{attacking} R{reserved} H{hallucination}'
            client: Client = self.ai._client
            client.debug_text_2d(msg, Point2((0.4, 0.1)), None, 16)
Exemple #23
0
 async def find_tumor_placement(self) -> Point2:
     # TODO: SLOW function fix fix fix. Also doesn't take into consideration whether theres something blocking tumor or not
     creep_emitters: Units = self.units(
         {HATCHERY, UnitTypeId.CREEPTUMORBURROWED})
     count = 0
     while count < 10:
         count += 1
         target_emitter: Unit = creep_emitters.random
         angle = random.randint(0, 360)
         x = math.cos(angle)
         y = math.sin(angle)
         target_position: Point2 = target_emitter.position + (9 * Point2(
             (x, y)))
         check = True
         for emitter in creep_emitters:
             if target_position.distance_to(emitter.position) < 9:
                 check = False
                 break
         if self.position_blocks_expansion(target_position):
             check = False
         if check:
             return target_position
     return None
Exemple #24
0
    def follow_path(self, unit: Unit) -> None:
        """
        Follow the path set or set a new one if none exists.

        Args:
            unit (Unit): the unit moving

        Returns:
            None
        """
        if unit.tag not in self.pathing_dict:
            self.add_to_path_dict(unit, self.target)
        else:
            advance_factor = int(unit.movement_speed) + 2
            self.pathing_dict[unit.tag]["step"] += advance_factor
        curr_step = self.pathing_dict[unit.tag]["step"]
        if curr_step >= len(self.pathing_dict[unit.tag]["path"]):
            curr_step = len(self.pathing_dict[unit.tag]["path"]) - 1
        self.do(
            unit.attack(Point2(
                self.pathing_dict[unit.tag]["path"][curr_step])))
        if curr_step == len(self.pathing_dict[unit.tag]["path"]) - 1:
            del self.pathing_dict[unit.tag]
Exemple #25
0
    def find_highground_centroids(self, highground_tiles) -> np.array:
        # using db index, find the optimal number of clusters for kmeans
        range_of_k = range(4, 22)
        # store all the davies-bouldin index values
        dbindexes = []

        for k in range_of_k:
            # try kmeans for each k value
            kmeans = KMeans(n_clusters=k,
                            random_state=42).fit(highground_tiles)
            dbindexes.append(
                self.davis_bouldin_index(highground_tiles, kmeans.labels_, k))

        kmeans = KMeans(n_clusters=np.argmin(dbindexes) + 4,
                        random_state=42).fit(highground_tiles)

        ol_spots: List[Point2] = [
            Point2(position.Pointlike((pos[0], pos[1])))
            for pos in kmeans.cluster_centers_
        ]

        # each clusters centroid is the overlord positions
        return ol_spots
Exemple #26
0
    async def step(self):
        actions = list()
        recon_tag = self.bot.units.filter(
            lambda unit: unit.tag in self.bot.reconArray)

        for unit in recon_tag:
            # 근처에 적들이 있는지 파악
            unit.move(Point2((self.pos, 60)))
            threaten = self.bot.known_enemy_units.closer_than(
                self.perimeter_radious, unit.position)

            if unit.type_id == UnitTypeId.RAVEN:
                if unit.health_percentage > 0.8 and unit.energy >= 50:
                    print("유닛오더? ", unit.orders)
                    if threaten.amount > 0:  # 근처에 적이 하나라도 있으면
                        alert = 1
                        if unit.orders and unit.orders[
                                0].ability.id != AbilityId.RAVENBUILD_AUTOTURRET:
                            closest_threat = threaten.closest_to(unit.position)
                            pos = unit.position.towards(
                                closest_threat.position, 5)
                            pos = await self.bot.find_placement(
                                UnitTypeId.AUTOTURRET, pos)
                            order = unit(AbilityId.BUILDAUTOTURRET_AUTOTURRET,
                                         pos)
                            actions.append(order)
                '''else:
                    if unit.distance_to(self.target) > 5:
                        order = unit.move(self.target)
                        actions.append(order)'''

            elif unit.type_id == UnitTypeId.MARINE:
                if self.bot.known_enemy_units.exists:
                    enemy_unit = self.bot.known_enemy_units.closest_to(unit)
                    actions.append(unit.attack(enemy_unit))

        return actions
Exemple #27
0
    async def on_start(self):
        self.map_data = MapData(self, loglevel="DEBUG", arcade=True)

        base = self.townhalls[0]
        self.base = reg_start = self.map_data.where_all(base.position_tuple)[0]
        reg_end = self.map_data.where_all(
            self.enemy_start_locations[0].position)[0]
        self.p0 = reg_start.center
        self.p1 = reg_end.center
        self.influence_grid = self.map_data.get_pyastar_grid()
        ramps = reg_end.region_ramps
        logger.info(ramps)
        if len(ramps) > 1:
            if self.map_data.distance(ramps[0].top_center,
                                      reg_end.center) < self.map_data.distance(
                                          ramps[1].top_center, reg_end.center):
                self.ramp = ramps[0]
            else:
                self.ramp = ramps[1]
        else:
            self.ramp = ramps[0]

        self.influence_points = [(self.ramp.top_center, 2),
                                 (Point2((66, 66)), 18)]

        self.influence_points = self._get_random_influence(25, 5)
        """Uncomment this code block to add random costs and make the path more complex"""
        # for tup in self.influence_points:
        #     p = tup[0]
        #     r = tup[1]
        #     self.map_data.add_cost(p, r=r, arr=self.influence_grid)

        self.path = self.map_data.pathfind(start=self.p0,
                                           goal=self.p1,
                                           grid=self.influence_grid,
                                           sensitivity=self.sens)
        self.hero_tag = self.workers[0].tag
Exemple #28
0
    def SolveCliffs(self, ai: sc2.BotAI):
        maxDifference = 3
        hMap = self.game_info.terrain_height
        correction = Point2((0, 1))

        x = 2
        while x < self.width - 3:
            y = 3
            while y < self.height - 3:
                pos = Point2((x, y))
                h = hMap[pos + correction]
                possibles = [
                    Point2((x - 2, y - 2)),
                    Point2((x + 2, y - 2)),
                    Point2((x - 2, y + 2)),
                    Point2((x + 2, y + 2)),
                ]

                for possible in possibles:
                    # To ensure rounding errors don't drop it to previous pixel.
                    middle = (possible + pos) * 0.500001
                    cell_possible: GridArea = self[possible]
                    cell_middle: GridArea = self[middle]

                    if cell_possible.Area == BuildArea.Empty and cell_middle.Area == BuildArea.NotBuildable:
                        h2 = hMap[possible + correction]
                        difference = h - h2
                        if abs(difference) > maxDifference:
                            continue

                        cell: GridArea = self.get(x, y)

                        if difference < 0:
                            if cell.Cliff == Cliff.HighCliff:
                                cell.Cliff = Cliff.BothCliff
                            else:
                                cell.Cliff = Cliff.LowCliff
                        if difference > 0:
                            if cell.Cliff == Cliff.LowCliff:
                                cell.Cliff = Cliff.BothCliff
                            else:
                                cell.Cliff = Cliff.HighCliff
                y += 1
            x += 1
Exemple #29
0
    async def on_step(self, iteration):
        self.shared.attackers = self.units.tags_in(self.allocated)
        if self.attack_objective:
            await self.attack_objective.tick()
            if self.attack_objective.is_complete():
                self.shared.victims = Units([], self.bot)
                self.attack_objective = None
            else:
                self.shared.victims = self.attack_objective.enemies
                return

        # for cleanup in self.cleanup_objectives:
        #   await cleanup.tick()
        #   if cleanup.is_complete():
        #     self.shared.victims = Units([], self.bot)
        #     self.cleanup_objectives.remove(cleanup)

        if (self.supply_used > 196
                or self.shared.optimism > 1.5) and not self.attack_objective:
            known_enemy_units = self.shared.known_enemy_units.values()
            enemy_bases = self.enemy_structures(BaseStructures)
            if enemy_bases.exists:
                self.attack_objective = AttackObjective(
                    self,
                    enemy_bases.furthest_to(
                        Point2.center([u.position for u in known_enemy_units]
                                      ) if known_enemy_units else self.
                        enemy_start_locations[0]).position)
            elif self.enemy_structures.exists:
                self.attack_objective = AttackObjective(
                    self,
                    self.enemy_structures.closest_to(
                        self.units.center).position)
            else:
                self.attack_objective = AttackObjective(
                    self, self.enemy_start_locations[0])
    def _set_sides(self):
        ramp_dir = self.ramp.bottom_center - self.ramp.top_center
        perpendicular_dir = Point2((-ramp_dir[1], ramp_dir[0])).normalized
        step_size = 1

        current = self.ramp.top_center.offset(ramp_dir / 2)
        side_a = current.rounded
        next_point = current.rounded
        while next_point in self.points:
            side_a = next_point
            current = current.offset(perpendicular_dir * step_size)
            next_point = current.rounded

        self.side_a = side_a

        current = self.ramp.top_center.offset(ramp_dir / 2)
        side_b = current.rounded
        next_point = current.rounded
        while next_point in self.points:
            side_b = next_point
            current = current.offset(-perpendicular_dir * step_size)
            next_point = current.rounded

        self.side_b = side_b