Skip to content

Commit 78cd842

Browse files
committed
Change walls for impossible ramps (HonorgroundsLE) so that they return None or empty set instead of crashing the game
1 parent d79c1ce commit 78cd842

File tree

4 files changed

+67
-33
lines changed

4 files changed

+67
-33
lines changed

examples/terran/ramp_wall.py

Lines changed: 25 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -43,30 +43,36 @@ async def on_step(self, iteration):
4343
# Uncomment the following if you want to build 3 supplydepots in the wall instead of a barracks in the middle + 2 depots in the corner
4444
# depot_placement_positions = self.main_base_ramp.corner_depots | {self.main_base_ramp.depot_in_middle}
4545

46-
barracks_placement_position = None
4746
barracks_placement_position = self.main_base_ramp.barracks_correct_placement
4847
# If you prefer to have the barracks in the middle without room for addons, use the following instead
4948
# barracks_placement_position = self.main_base_ramp.barracks_in_middle
5049

5150
depots = self.units(SUPPLYDEPOT) | self.units(SUPPLYDEPOTLOWERED)
5251

5352
# Draw ramp points
54-
# def terrain_to_z_height(h):
55-
# return round(16 * h / 255, 2)
56-
57-
# for ramp in self.game_info.map_ramps:
58-
# for p in ramp.points:
59-
# h = self.get_terrain_height(p)
60-
# h2 = terrain_to_z_height(h)
61-
# pos = Point3((p.x, p.y, h2))
62-
# p0 = Point3((pos.x - 0.25, pos.y - 0.25, pos.z))
63-
# p1 = Point3((pos.x + 0.25, pos.y + 0.25, pos.z - 0.5))
64-
# print(f"drawing {p0} to {p1}")
65-
# self._client.debug_box_out(p0, p1, color=Point3((255, 0, 0)))
66-
#
67-
# await self._client.send_debug()
68-
69-
# Filter locations close to finished supply depots
53+
def terrain_to_z_height(h):
54+
return round(16 * h / 255, 2)
55+
56+
for ramp in self.game_info.map_ramps:
57+
for p in ramp.points:
58+
h = self.get_terrain_height(p)
59+
h2 = terrain_to_z_height(h)
60+
pos = Point3((p.x, p.y, h2))
61+
p0 = Point3((pos.x - 0.25, pos.y - 0.25, pos.z))
62+
p1 = Point3((pos.x + 0.25, pos.y + 0.25, pos.z - 0.5))
63+
# print(f"Drawing {p0} to {p1}")
64+
color=Point3((255, 0, 0))
65+
if p in ramp.upper:
66+
color = Point3((0, 255, 0))
67+
if p in ramp.upper2_for_ramp_wall:
68+
color = Point3((0, 255, 255))
69+
if p in ramp.lower:
70+
color = Point3((0, 0, 255))
71+
self._client.debug_box_out(p0, p1, color=color)
72+
73+
await self._client.send_debug()
74+
75+
# # Filter locations close to finished supply depots
7076
if depots:
7177
depot_placement_positions = {d for d in depot_placement_positions if depots.closest_distance_to(d) > 1}
7278

@@ -82,7 +88,7 @@ async def on_step(self, iteration):
8288
await self.do(w.build(SUPPLYDEPOT, target_depot_location))
8389

8490
# Build barracks
85-
if depots.ready.exists and self.can_afford(BARRACKS) and not self.already_pending(BARRACKS):
91+
if depots.ready and self.can_afford(BARRACKS) and not self.already_pending(BARRACKS):
8692
if self.units(BARRACKS).amount + self.already_pending(BARRACKS) > 0:
8793
return
8894
ws = self.workers.gathering
@@ -108,6 +114,7 @@ def main():
108114
"DarknessSanctuaryLE",
109115
"ParaSiteLE", # Has 5 upper points at the main ramp
110116
"AcolyteLE", # Has 4 upper points at the ramp to the in-base natural and 2 upper points at the small ramp
117+
"HonorgroundsLE", # Has 4 or 9 upper points at the large main base ramp
111118
]
112119
)
113120
sc2.run_game(

sc2/bot_ai.py

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -133,10 +133,17 @@ def main_base_ramp(self) -> "Ramp":
133133
# The reason for len(ramp.upper) in {2, 5} is:
134134
# ParaSite map has 5 upper points, and most other maps have 2 upper points at the main ramp.
135135
# The map Acolyte has 4 upper points at the wrong ramp (which is closest to the start position).
136-
self.cached_main_base_ramp = min(
137-
(ramp for ramp in self.game_info.map_ramps if len(ramp.upper) in {2, 5}),
138-
key=lambda r: self.start_location.distance_to(r.top_center),
139-
)
136+
try:
137+
self.cached_main_base_ramp = min(
138+
(ramp for ramp in self.game_info.map_ramps if len(ramp.upper) in {2, 5}),
139+
key=lambda r: self.start_location.distance_to(r.top_center),
140+
)
141+
except ValueError:
142+
# Hardcoded hotfix for Honorgrounds LE map, as that map has a large main base ramp with inbase natural
143+
self.cached_main_base_ramp = min(
144+
(ramp for ramp in self.game_info.map_ramps if len(ramp.upper) in {4, 9}),
145+
key=lambda r: self.start_location.distance_to(r.top_center),
146+
)
140147
return self.cached_main_base_ramp
141148

142149
@property_cache_forever

sc2/game_info.py

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -92,8 +92,10 @@ def bottom_center(self) -> Point2:
9292
return pos
9393

9494
@property_immutable_cache
95-
def barracks_in_middle(self) -> Point2:
95+
def barracks_in_middle(self) -> Optional[Point2]:
9696
""" Barracks position in the middle of the 2 depots """
97+
if len(self.upper) not in {2, 5}:
98+
return None
9799
if len(self.upper2_for_ramp_wall) == 2:
98100
points = self.upper2_for_ramp_wall
99101
p1 = points.pop().offset((self.x_offset, self.y_offset))
@@ -105,27 +107,35 @@ def barracks_in_middle(self) -> Point2:
105107
raise Exception("Not implemented. Trying to access a ramp that has a wrong amount of upper points.")
106108

107109
@property_immutable_cache
108-
def depot_in_middle(self) -> Point2:
110+
def depot_in_middle(self) -> Optional[Point2]:
109111
""" Depot in the middle of the 3 depots """
110112
if len(self.upper2_for_ramp_wall) == 2:
111113
points = self.upper2_for_ramp_wall
112-
p1 = points.pop().offset((self.x_offset, self.y_offset)) # still an error with pixelmap?
114+
p1 = points.pop().offset((self.x_offset, self.y_offset))
113115
p2 = points.pop().offset((self.x_offset, self.y_offset))
114116
# Offset from top point to depot center is (1.5, 0.5)
115-
intersects = p1.circle_intersection(p2, 2.5 ** 0.5)
117+
try:
118+
intersects = p1.circle_intersection(p2, 2.5 ** 0.5)
119+
except AssertionError:
120+
# Returns None when no placement was found, this is the case on the map Honorgrounds LE with an exceptionally large main base ramp
121+
return None
116122
anyLowerPoint = next(iter(self.lower))
117123
return max(intersects, key=lambda p: p.distance_to_point2(anyLowerPoint))
118124
raise Exception("Not implemented. Trying to access a ramp that has a wrong amount of upper points.")
119125

120126
@property_mutable_cache
121127
def corner_depots(self) -> Set[Point2]:
122128
""" Finds the 2 depot positions on the outside """
129+
if not self.upper2_for_ramp_wall:
130+
return set()
123131
if len(self.upper2_for_ramp_wall) == 2:
124132
points = self.upper2_for_ramp_wall
125-
p1 = points.pop().offset((self.x_offset, self.y_offset)) # still an error with pixelmap?
133+
p1 = points.pop().offset((self.x_offset, self.y_offset))
126134
p2 = points.pop().offset((self.x_offset, self.y_offset))
127135
center = p1.towards(p2, p1.distance_to_point2(p2) / 2)
128136
depotPosition = self.depot_in_middle
137+
if depotPosition is None:
138+
return set()
129139
# Offset from middle depot to corner depots is (2, 1)
130140
intersects = center.circle_intersection(depotPosition, 5 ** 0.5)
131141
return intersects
@@ -140,8 +150,10 @@ def barracks_can_fit_addon(self) -> bool:
140150
raise Exception("Not implemented. Trying to access a ramp that has a wrong amount of upper points.")
141151

142152
@property_immutable_cache
143-
def barracks_correct_placement(self) -> Point2:
153+
def barracks_correct_placement(self) -> Optional[Point2]:
144154
""" Corrected placement so that an addon can fit """
155+
if self.barracks_in_middle is None:
156+
return None
145157
if len(self.upper2_for_ramp_wall) == 2:
146158
if self.barracks_can_fit_addon:
147159
return self.barracks_in_middle

test/test_pickled_data.py

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -169,15 +169,23 @@ def test_game_info(self, bot: BotAI):
169169

170170
# Test if main base ramp works
171171
ramp: Ramp = bot.main_base_ramp
172-
assert ramp.barracks_correct_placement
173-
assert ramp.barracks_in_middle
174-
assert ramp.depot_in_middle
175-
assert len(ramp.corner_depots) == 2
172+
# On the map HonorgroundsLE, the main base is large and it would take a bit of effort to fix, so it returns None or empty set
173+
if len(ramp.upper) in {2, 5}:
174+
assert ramp.barracks_correct_placement
175+
assert ramp.barracks_in_middle
176+
assert ramp.depot_in_middle
177+
assert len(ramp.corner_depots) == 2
178+
assert ramp.upper2_for_ramp_wall
179+
else:
180+
# On maps it is unable to find valid wall positions (Honorgrounds LE) it should return None
181+
assert ramp.barracks_correct_placement is None
182+
assert ramp.barracks_in_middle is None
183+
assert ramp.depot_in_middle is None
184+
assert ramp.corner_depots == set()
176185
assert ramp.top_center
177186
assert ramp.bottom_center
178187
assert ramp.size
179188
assert ramp.points
180-
assert ramp.upper2_for_ramp_wall
181189
assert ramp.upper
182190
assert ramp.lower
183191

0 commit comments

Comments
 (0)