Skip to content

Commit d79c1ce

Browse files
authored
Update bot_ai.py
1 parent e3002e7 commit d79c1ce

File tree

1 file changed

+64
-61
lines changed

1 file changed

+64
-61
lines changed

sc2/bot_ai.py

Lines changed: 64 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -126,11 +126,13 @@ def known_enemy_structures(self) -> Units:
126126

127127
@property
128128
def main_base_ramp(self) -> "Ramp":
129-
""" Returns the Ramp instance of the closest main-ramp to start location. Look in game_info.py for more information """
129+
""" Returns the Ramp instance of the closest main-ramp to start location.
130+
Look in game_info.py for more information """
130131
if hasattr(self, "cached_main_base_ramp"):
131132
return self.cached_main_base_ramp
132-
""" The reason for len(ramp.upper) in {2, 5} is:
133-
ParaSite map has 5 upper points, and most other maps have 2 upper points at the main ramp. The map Acolyte has 4 upper points at the wrong ramp (which is closest to the start position) """
133+
# The reason for len(ramp.upper) in {2, 5} is:
134+
# ParaSite map has 5 upper points, and most other maps have 2 upper points at the main ramp.
135+
# The map Acolyte has 4 upper points at the wrong ramp (which is closest to the start position).
134136
self.cached_main_base_ramp = min(
135137
(ramp for ramp in self.game_info.map_ramps if len(ramp.upper) in {2, 5}),
136138
key=lambda r: self.start_location.distance_to(r.top_center),
@@ -148,64 +150,65 @@ def expansion_locations(self) -> Dict[Point2, Units]:
148150
# any resource in a group is closer than 6 to any resource of another group
149151

150152
# Distance we group resources by
151-
RESOURCE_SPREAD_THRESHOLD = 8.5
152-
minerals = self.state.mineral_field
153-
geysers = self.state.vespene_geyser
154-
all_resources = minerals | geysers
155-
# Presort resources to get faster clustering
156-
all_resources.sort(key=lambda resource: (resource.position.x, resource.position.y))
157-
# Create a group for every resource
158-
resource_groups = [[resource] for resource in all_resources]
159-
# Loop the merging process as long as we change something
160-
found_something = True
161-
while found_something:
162-
found_something = False
163-
# Check every combination of two groups
164-
for group_a, group_b in itertools.combinations(resource_groups, 2):
165-
# Check if any pair of resource of these groups is closer than threshold together
166-
if any(
167-
resource_a.distance_to(resource_b) <= RESOURCE_SPREAD_THRESHOLD
168-
for resource_a, resource_b in itertools.product(group_a, group_b)
169-
):
170-
# Remove the single groups and add the merged group
171-
resource_groups.remove(group_a)
172-
resource_groups.remove(group_b)
173-
resource_groups.append(group_a + group_b)
174-
found_something = True
175-
break
176-
# Distance offsets we apply to center of each resource group to find expansion position
177-
offset_range = 7
178-
offsets = [
179-
(x, y)
180-
for x in range(-offset_range, offset_range + 1)
181-
for y in range(-offset_range, offset_range + 1)
182-
if 4 <= math.hypot(x, y) <= 7
183-
]
184-
# Dict we want to return
185-
centers = {}
186-
# For every resource group:
187-
for resources in resource_groups:
188-
# Possible expansion points
189-
amount = len(resources)
190-
# Calculate center, round and add 0.5 because expansion location will have (x.5, y.5)
191-
# coordinates because bases have size 5.
192-
center_x = round(sum(resource.position.x for resource in resources) / amount) + 0.5
193-
center_y = round(sum(resource.position.y for resource in resources) / amount) + 0.5
194-
possible_points = (Point2((offset[0] + center_x, offset[1] + center_y)) for offset in offsets)
195-
# Filter out points that are too near
196-
possible_points = (
197-
point
198-
for point in possible_points
199-
# Check if point can be built on
200-
if self._game_info.placement_grid[point.rounded] != 0
201-
# Check if all resources have enough space to point
202-
and all(point.distance_to(resource) >= (7 if resource in geysers else 6) for resource in resources)
203-
)
204-
# Choose best fitting point
205-
# TODO can we improve this by calculating the distance only one time?
206-
result = min(possible_points, key=lambda point: sum(point.distance_to(resource) for resource in resources))
207-
centers[result] = resources
208-
return centers
153+
from .helpers.devtools import time_this
154+
155+
with time_this("expo locations"):
156+
RESOURCE_SPREAD_THRESHOLD = 8.5
157+
minerals = self.state.mineral_field
158+
geysers = self.state.vespene_geyser
159+
all_resources = minerals | geysers
160+
# Presort resources to get faster clustering
161+
# all_resources.sort(key=lambda resource: resource.position.x ** 2 + resource.position.y ** 2)
162+
all_resources.sort(key=lambda resource: resource.position.x ** 2 + resource.position.y ** 2)
163+
# Create a group for every resource
164+
resource_groups = [[resource] for resource in all_resources]
165+
# Loop the merging process as long as we change something
166+
found_something = True
167+
while found_something:
168+
found_something = False
169+
# Check every combination of two groups
170+
for group_a, group_b in itertools.combinations(resource_groups, 2):
171+
# Check if any pair of resource of these groups is closer than threshold together
172+
if any(
173+
resource_a.distance_to(resource_b) <= RESOURCE_SPREAD_THRESHOLD
174+
for resource_a, resource_b in itertools.product(group_a, group_b)
175+
):
176+
# Remove the single groups and add the merged group
177+
resource_groups.remove(group_a)
178+
resource_groups.remove(group_b)
179+
resource_groups.append(group_a + group_b)
180+
found_something = True
181+
break
182+
# Distance offsets we apply to center of each resource group to find expansion position
183+
offset_range = 7
184+
offsets = [(x, y) for x, y in itertools.product(range(-offset_range, offset_range + 1), repeat=2)]
185+
# Dict we want to return
186+
centers = {}
187+
# For every resource group:
188+
for resources in resource_groups:
189+
# Possible expansion points
190+
amount = len(resources)
191+
# Calculate center, round and add 0.5 because expansion location will have (x.5, y.5)
192+
# coordinates because bases have size 5.
193+
center_x = round(sum(resource.position.x for resource in resources) / amount) + 0.5
194+
center_y = round(sum(resource.position.y for resource in resources) / amount) + 0.5
195+
possible_points = (Point2((offset[0] + center_x, offset[1] + center_y)) for offset in offsets)
196+
# Filter out points that are too near
197+
possible_points = (
198+
point
199+
for point in possible_points
200+
# Check if point can be built on
201+
if self._game_info.placement_grid[point.rounded] == 1
202+
# Check if all resources have enough space to point
203+
and all(point.distance_to(resource) > (7 if resource in geysers else 6) for resource in resources)
204+
)
205+
# Choose best fitting point
206+
# TODO can we improve this by calculating the distance only one time?
207+
result = min(
208+
possible_points, key=lambda point: sum(point.distance_to(resource) for resource in resources)
209+
)
210+
centers[result] = resources
211+
return centers
209212

210213
def _correct_zerg_supply(self):
211214
""" The client incorrectly rounds zerg supply down instead of up (see

0 commit comments

Comments
 (0)