Skip to content

Commit fa339fb

Browse files
authored
Merge pull request #3 from Dentosal/develop
Develop
2 parents 11403a0 + fd673a4 commit fa339fb

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

62 files changed

+175
-89
lines changed

.travis.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ jobs:
3030
- docker exec app pip install --upgrade pipenv
3131
# Create pipenv virtual environment and install dev packages for testing
3232
# Command origins from here: https://stackoverflow.com/a/28037991/10882657
33-
- docker exec -i app bash -c "cd /root/template && pipenv install --dev"
33+
- docker exec -i app bash -c "cd /root/template && pipenv install --dev --python 3.7"
3434
# Run tests
3535
- docker exec -i app bash -c "cd /root/template && pipenv run pytest test/"
3636
# Shut down and remove container
@@ -43,7 +43,7 @@ jobs:
4343
- docker run -it -d --name app python:3.8-rc-slim
4444
- docker cp . app:/root/template
4545
- docker exec app pip install --upgrade pipenv
46-
- docker exec -i app bash -c "cd /root/template && pipenv --python python install --dev"
46+
- docker exec -i app bash -c "cd /root/template && pipenv --python python install --dev --python 3.8"
4747
- docker exec -i app bash -c "cd /root/template && pipenv run pytest test/"
4848
- docker rm -f app
4949

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: 23 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,6 @@
55
from collections import Counter
66
from typing import Any, Dict, List, Optional, Set, Tuple, Union # mypy type checking
77

8-
from s2clientprotocol import common_pb2 as common_pb
9-
108
from .cache import property_cache_forever, property_cache_once_per_frame
119
from .data import ActionResult, Alert, Race, Result, Target, race_gas, race_townhalls, race_worker
1210
from .game_data import AbilityData, GameData
@@ -126,15 +124,24 @@ def known_enemy_structures(self) -> Units:
126124

127125
@property
128126
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 """
127+
""" Returns the Ramp instance of the closest main-ramp to start location.
128+
Look in game_info.py for more information """
130129
if hasattr(self, "cached_main_base_ramp"):
131130
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) """
134-
self.cached_main_base_ramp = min(
135-
(ramp for ramp in self.game_info.map_ramps if len(ramp.upper) in {2, 5}),
136-
key=lambda r: self.start_location.distance_to(r.top_center),
137-
)
131+
# The reason for len(ramp.upper) in {2, 5} is:
132+
# ParaSite map has 5 upper points, and most other maps have 2 upper points at the main ramp.
133+
# The map Acolyte has 4 upper points at the wrong ramp (which is closest to the start position).
134+
try:
135+
self.cached_main_base_ramp = min(
136+
(ramp for ramp in self.game_info.map_ramps if len(ramp.upper) in {2, 5}),
137+
key=lambda r: self.start_location.distance_to(r.top_center),
138+
)
139+
except ValueError:
140+
# Hardcoded hotfix for Honorgrounds LE map, as that map has a large main base ramp with inbase natural
141+
self.cached_main_base_ramp = min(
142+
(ramp for ramp in self.game_info.map_ramps if len(ramp.upper) in {4, 9}),
143+
key=lambda r: self.start_location.distance_to(r.top_center),
144+
)
138145
return self.cached_main_base_ramp
139146

140147
@property_cache_forever
@@ -149,13 +156,9 @@ def expansion_locations(self) -> Dict[Point2, Units]:
149156

150157
# Distance we group resources by
151158
RESOURCE_SPREAD_THRESHOLD = 8.5
152-
minerals = self.state.mineral_field
153159
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))
157160
# Create a group for every resource
158-
resource_groups = [[resource] for resource in all_resources]
161+
resource_groups = [[resource] for resource in self.state.resources]
159162
# Loop the merging process as long as we change something
160163
found_something = True
161164
while found_something:
@@ -177,9 +180,8 @@ def expansion_locations(self) -> Dict[Point2, Units]:
177180
offset_range = 7
178181
offsets = [
179182
(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+
for x, y in itertools.product(range(-offset_range, offset_range + 1), repeat=2)
184+
if math.hypot(x, y) <= 8
183185
]
184186
# Dict we want to return
185187
centers = {}
@@ -189,20 +191,19 @@ def expansion_locations(self) -> Dict[Point2, Units]:
189191
amount = len(resources)
190192
# Calculate center, round and add 0.5 because expansion location will have (x.5, y.5)
191193
# 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+
center_x = int(sum(resource.position.x for resource in resources) / amount) + 0.5
195+
center_y = int(sum(resource.position.y for resource in resources) / amount) + 0.5
194196
possible_points = (Point2((offset[0] + center_x, offset[1] + center_y)) for offset in offsets)
195197
# Filter out points that are too near
196198
possible_points = (
197199
point
198200
for point in possible_points
199201
# Check if point can be built on
200-
if self._game_info.placement_grid[point.rounded] != 0
202+
if self._game_info.placement_grid[point.rounded] == 1
201203
# 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)
204+
and all(point.distance_to(resource) > (7 if resource in geysers else 6) for resource in resources)
203205
)
204206
# Choose best fitting point
205-
# TODO can we improve this by calculating the distance only one time?
206207
result = min(possible_points, key=lambda point: sum(point.distance_to(resource) for resource in resources))
207208
centers[result] = resources
208209
return centers

sc2/client.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,26 @@ async def get_game_data(self) -> GameData:
138138
)
139139
return GameData(result.data)
140140

141+
async def dump_data(self, ability_id=True, unit_type_id=True, upgrade_id=True, buff_id=True, effect_id=True):
142+
"""
143+
Dump the game data files
144+
choose what data to dump in the keywords
145+
this function writes to a text file
146+
call it one time in on_step with:
147+
await self._client.dump_data()
148+
"""
149+
result = await self._execute(
150+
data=sc_pb.RequestData(
151+
ability_id=ability_id,
152+
unit_type_id=unit_type_id,
153+
upgrade_id=upgrade_id,
154+
buff_id=buff_id,
155+
effect_id=effect_id,
156+
)
157+
)
158+
with open("data_dump.txt", "a") as file:
159+
file.write(str(result.data))
160+
141161
async def get_game_info(self) -> GameInfo:
142162
result = await self._execute(game_info=sc_pb.RequestGameInfo())
143163
return GameInfo(result.game_info)

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

0 commit comments

Comments
 (0)