Skip to content

Commit 1620f16

Browse files
author
Reynald Pader
committed
Merge branch 'master' into build-order-support
# Conflicts: # examples/zerg_rush.py # sc2/bot_ai.py # sc2/data.py # sc2/ids/ability_id.py
2 parents 6eb9c0e + ad9d314 commit 1620f16

26 files changed

+1077
-911
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ from sc2 import run_game, maps, Race, Difficulty
3030
from sc2.player import Bot, Computer
3131

3232
class WorkerRushBot(sc2.BotAI):
33-
async def on_step(self, state, iteration):
33+
async def on_step(self, iteration):
3434
if iteration == 0:
3535
for worker in self.workers:
3636
await self.do(worker.attack(self.enemy_start_locations[0]))

examples/cannon_rush.py

Lines changed: 21 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -6,46 +6,46 @@
66
from sc2.player import Bot, Computer
77

88
class CannonRushBot(sc2.BotAI):
9-
async def on_step(self, state, iteration):
9+
async def on_step(self, iteration):
1010
if iteration == 0:
1111
await self.chat_send("(probe)(pylon)(cannon)(cannon)(gg)")
1212

13-
if not self.units(UnitTypeId.NEXUS).exists:
13+
if not self.units(NEXUS).exists:
1414
for worker in self.workers:
1515
await self.do(worker.attack(self.enemy_start_locations[0]))
1616
return
1717
else:
18-
nexus = self.units(UnitTypeId.NEXUS).first
18+
nexus = self.units(NEXUS).first
1919

2020
if self.workers.amount < 16 and nexus.noqueue:
21-
if self.can_afford(UnitTypeId.PROBE):
22-
await self.do(nexus.train(UnitTypeId.PROBE))
21+
if self.can_afford(PROBE):
22+
await self.do(nexus.train(PROBE))
2323

24-
elif not self.units(UnitTypeId.PYLON).exists and not self.already_pending(UnitTypeId.PYLON):
25-
if self.can_afford(UnitTypeId.PYLON):
26-
await self.build(UnitTypeId.PYLON, near=nexus)
24+
elif not self.units(PYLON).exists and not self.already_pending(PYLON):
25+
if self.can_afford(PYLON):
26+
await self.build(PYLON, near=nexus)
2727

28-
elif not self.units(UnitTypeId.FORGE).exists:
29-
pylon = self.units(UnitTypeId.PYLON).ready
28+
elif not self.units(FORGE).exists:
29+
pylon = self.units(PYLON).ready
3030
if pylon.exists:
31-
if self.can_afford(UnitTypeId.FORGE):
32-
await self.build(UnitTypeId.FORGE, near=pylon.closest_to(nexus))
31+
if self.can_afford(FORGE):
32+
await self.build(FORGE, near=pylon.closest_to(nexus))
3333

34-
elif self.units(UnitTypeId.PYLON).amount < 2:
35-
if self.can_afford(UnitTypeId.PYLON):
34+
elif self.units(PYLON).amount < 2:
35+
if self.can_afford(PYLON):
3636
pos = self.enemy_start_locations[0].towards(self.game_info.map_center, random.randrange(8, 15))
37-
await self.build(UnitTypeId.PYLON, near=pos)
37+
await self.build(PYLON, near=pos)
3838

39-
elif not self.units(UnitTypeId.PHOTONCANNON).exists:
40-
if self.units(UnitTypeId.PYLON).ready.amount >= 2 and self.can_afford(UnitTypeId.PHOTONCANNON):
41-
pylon = self.units(UnitTypeId.PYLON).closer_than(20, self.enemy_start_locations[0]).random
42-
await self.build(UnitTypeId.PHOTONCANNON, near=pylon)
39+
elif not self.units(PHOTONCANNON).exists:
40+
if self.units(PYLON).ready.amount >= 2 and self.can_afford(PHOTONCANNON):
41+
pylon = self.units(PYLON).closer_than(20, self.enemy_start_locations[0]).random
42+
await self.build(PHOTONCANNON, near=pylon)
4343

4444
else:
45-
if self.can_afford(UnitTypeId.PYLON) and self.can_afford(UnitTypeId.PHOTONCANNON): # ensure "fair" decision
45+
if self.can_afford(PYLON) and self.can_afford(PHOTONCANNON): # ensure "fair" decision
4646
for _ in range(20):
4747
pos = self.enemy_start_locations[0].random_on_distance(random.randrange(5, 12))
48-
building = UnitTypeId.PHOTONCANNON if state.psionic_matrix.covers(pos) else UnitTypeId.PYLON
48+
building = PHOTONCANNON if self.state.psionic_matrix.covers(pos) else PYLON
4949
r = await self.build(building, near=pos)
5050
if not r: # success
5151
break

examples/distributed_workers.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,22 +5,22 @@
55

66

77
class TerranBot(sc2.BotAI):
8-
async def on_step(self, state, iteration):
8+
async def on_step(self, iteration):
99
await self.distribute_workers()
10-
await self.build_supply(state)
11-
await self.build_workers(state)
12-
await self.expand(state)
10+
await self.build_supply()
11+
await self.build_workers()
12+
await self.expand()
1313

14-
async def build_workers(self, state):
14+
async def build_workers(self):
1515
for cc in self.units(UnitTypeId.COMMANDCENTER).ready.noqueue:
1616
if self.can_afford(UnitTypeId.SCV):
1717
await self.do(cc.train(UnitTypeId.SCV))
1818

19-
async def expand(self, state):
19+
async def expand(self):
2020
if self.units(UnitTypeId.COMMANDCENTER).amount < 3 and self.can_afford(UnitTypeId.COMMANDCENTER):
2121
await self.expand_now()
2222

23-
async def build_supply(self, state):
23+
async def build_supply(self):
2424
cc = self.units(UnitTypeId.COMMANDCENTER).ready.first
2525
if self.supply_left < 4 and not self.already_pending(UnitTypeId.SUPPLYDEPOT):
2626
if self.can_afford(UnitTypeId.SUPPLYDEPOT):

examples/onebase_battlecruiser.py

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
import random
2+
3+
import sc2
4+
from sc2 import Race, Difficulty
5+
from sc2.constants import *
6+
from sc2.player import Bot, Computer
7+
from sc2.player import Human
8+
9+
class ProxyRaxBot(sc2.BotAI):
10+
def select_target(self):
11+
target = self.known_enemy_structures
12+
if target.exists:
13+
return target.random.position
14+
15+
target = self.known_enemy_units
16+
if target.exists:
17+
return target.random.position
18+
19+
if min([u.position.distance_to(self.enemy_start_locations[0]) for u in self.units]) < 5:
20+
return self.enemy_start_locations[0].position
21+
22+
return self.state.mineral_field.random.position
23+
24+
async def on_step(self, iteration):
25+
cc = (self.units(COMMANDCENTER) | self.units(ORBITALCOMMAND))
26+
if not cc.exists:
27+
target = self.known_enemy_structures.random_or(self.enemy_start_locations[0]).position
28+
for unit in self.workers | self.units(BATTLECRUISER):
29+
await self.do(unit.attack(target))
30+
return
31+
else:
32+
cc = cc.first
33+
34+
35+
if iteration % 50 == 0 and self.units(BATTLECRUISER).amount > 2:
36+
target = self.select_target()
37+
forces = self.units(BATTLECRUISER)
38+
if (iteration//50) % 10 == 0:
39+
for unit in forces:
40+
await self.do(unit.attack(target))
41+
else:
42+
for unit in forces.idle:
43+
await self.do(unit.attack(target))
44+
45+
if self.can_afford(SCV) and self.workers.amount < 22 and cc.noqueue:
46+
await self.do(cc.train(SCV))
47+
48+
if self.units(FUSIONCORE).exists and self.can_afford(BATTLECRUISER):
49+
for sp in self.units(STARPORT):
50+
if sp.has_add_on and sp.noqueue:
51+
if not self.can_afford(BATTLECRUISER):
52+
break
53+
await self.do(sp.train(BATTLECRUISER))
54+
55+
elif self.supply_left < 3:
56+
if self.can_afford(SUPPLYDEPOT):
57+
await self.build(SUPPLYDEPOT, near=cc.position.towards(self.game_info.map_center, 8))
58+
59+
if self.units(SUPPLYDEPOT).exists:
60+
if not self.units(BARRACKS).exists:
61+
if self.can_afford(BARRACKS):
62+
await self.build(BARRACKS, near=cc.position.towards(self.game_info.map_center, 8))
63+
64+
elif self.units(BARRACKS).exists and self.units(REFINERY).amount < 2:
65+
if self.can_afford(REFINERY):
66+
vgs = self.state.vespene_geyser.closer_than(20.0, cc)
67+
for vg in vgs:
68+
if self.units(REFINERY).closer_than(1.0, vg).exists:
69+
break
70+
71+
worker = self.select_build_worker(vg.position)
72+
if worker is None:
73+
break
74+
75+
await self.do(worker.build(REFINERY, vg))
76+
break
77+
78+
if self.units(BARRACKS).ready.exists:
79+
f = self.units(FACTORY)
80+
if not f.exists:
81+
if self.can_afford(FACTORY):
82+
await self.build(FACTORY, near=cc.position.towards(self.game_info.map_center, 8))
83+
elif f.ready.exists and self.units(STARPORT).amount < 2:
84+
if self.can_afford(STARPORT):
85+
await self.build(STARPORT, near=cc.position.towards(self.game_info.map_center, 30).random_on_distance(8))
86+
87+
for sp in self.units(STARPORT).ready:
88+
if sp.add_on_tag == 0:
89+
await self.do(sp.build(STARPORTTECHLAB))
90+
91+
if self.units(STARPORT).ready.exists:
92+
if self.can_afford(FUSIONCORE) and not self.units(FUSIONCORE).exists:
93+
await self.build(FUSIONCORE, near=cc.position.towards(self.game_info.map_center, 8))
94+
95+
for a in self.units(REFINERY):
96+
if a.assigned_harvesters < a.ideal_harvesters:
97+
w = self.workers.closer_than(20, a)
98+
if w.exists:
99+
await self.do(w.random.gather(a))
100+
101+
for scv in self.units(SCV).idle:
102+
await self.do(scv.gather(self.state.mineral_field.closest_to(cc)))
103+
104+
def main():
105+
sc2.run_game(sc2.maps.get("Sequencer LE"), [
106+
# Human(Race.Terran),
107+
Bot(Race.Terran, ProxyRaxBot()),
108+
Computer(Race.Zerg, Difficulty.Hard)
109+
], realtime=False)
110+
111+
if __name__ == '__main__':
112+
main()

examples/play_tvz.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
def main():
99
sc2.run_game(sc2.maps.get("Abyssal Reef LE"), [
1010
Human(Race.Terran),
11-
# Bot(Race.Protoss, CannonRushBot())
1211
Bot(Race.Zerg, ZergRushBot())
1312
], realtime=True)
1413

examples/proxy_rax.py

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6,39 +6,39 @@
66
from sc2.player import Bot, Computer
77

88
class ProxyRaxBot(sc2.BotAI):
9-
async def on_step(self, state, iteration):
10-
cc = self.units(UnitTypeId.COMMANDCENTER)
9+
async def on_step(self, iteration):
10+
cc = self.units(COMMANDCENTER)
1111
if not cc.exists:
1212
target = self.known_enemy_structures.random_or(self.enemy_start_locations[0]).position
13-
for unit in self.workers | self.units(UnitTypeId.MARINE):
13+
for unit in self.workers | self.units(MARINE):
1414
await self.do(unit.attack(target))
1515
return
1616
else:
1717
cc = cc.first
1818

19-
if self.units(UnitTypeId.MARINE).idle.amount > 15 and iteration % 50 == 1:
19+
if self.units(MARINE).idle.amount > 15 and iteration % 50 == 1:
2020
target = self.known_enemy_structures.random_or(self.enemy_start_locations[0]).position
21-
for marine in self.units(UnitTypeId.MARINE).idle:
21+
for marine in self.units(MARINE).idle:
2222
await self.do(marine.attack(target))
2323

24-
if self.can_afford(UnitTypeId.SCV) and self.workers.amount < 16 and cc.noqueue:
25-
await self.do(cc.train(UnitTypeId.SCV))
24+
if self.can_afford(SCV) and self.workers.amount < 16 and cc.noqueue:
25+
await self.do(cc.train(SCV))
2626

27-
elif self.supply_left < (2 if self.units(UnitTypeId.BARRACKS).amount < 3 else 4):
28-
if self.can_afford(UnitTypeId.SUPPLYDEPOT):
29-
await self.build(UnitTypeId.SUPPLYDEPOT, near=cc.position.towards(self.game_info.map_center, 5))
27+
elif self.supply_left < (2 if self.units(BARRACKS).amount < 3 else 4):
28+
if self.can_afford(SUPPLYDEPOT):
29+
await self.build(SUPPLYDEPOT, near=cc.position.towards(self.game_info.map_center, 5))
3030

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

36-
for rax in self.units(UnitTypeId.BARRACKS).ready.noqueue:
37-
if not self.can_afford(UnitTypeId.MARINE):
36+
for rax in self.units(BARRACKS).ready.noqueue:
37+
if not self.can_afford(MARINE):
3838
break
39-
await self.do(rax.train(UnitTypeId.MARINE))
39+
await self.do(rax.train(MARINE))
4040

41-
for scv in self.units(UnitTypeId.SCV).idle:
41+
for scv in self.units(SCV).idle:
4242
await self.do(scv.gather(self.state.mineral_field.closest_to(cc)))
4343

4444
def main():

examples/run_external.py

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
# Usage: python run_external.py [--host]
2+
3+
import argparse
4+
15
import sys
26
import asyncio
37

@@ -7,12 +11,11 @@
711

812
from zerg_rush import ZergRushBot
913

10-
def main(pc):
11-
if pc:
12-
host = False
14+
def main(is_host, pc):
15+
if args.portconfig:
1316
portconfig = sc2.portconfig.Portconfig.from_json(pc)
1417
else:
15-
host = True
18+
assert args.host, "Must be host if portconfig is not given"
1619
portconfig = sc2.portconfig.Portconfig()
1720
print(portconfig.as_json)
1821

@@ -21,9 +24,9 @@ def main(pc):
2124
Bot(Race.Zerg, None)
2225
]
2326

24-
player_config[0 if host else 1].ai = ZergRushBot()
27+
player_config[0 if is_host else 1].ai = ZergRushBot()
2528

26-
if host:
29+
if is_host:
2730
g = sc2.main._host_game(
2831
sc2.maps.get("Abyssal Reef LE"),
2932
player_config,
@@ -41,4 +44,9 @@ def main(pc):
4144
print(result)
4245

4346
if __name__ == '__main__':
44-
main(sys.argv[1] if len(sys.argv) > 1 else None)
47+
parser = argparse.ArgumentParser(description='Process some integers.')
48+
parser.add_argument('--host', action='store_true', help='host a game')
49+
parser.add_argument('portconfig', type=str, nargs="?", help='port configuration as json')
50+
args = parser.parse_args()
51+
52+
main(args.host, args.portconfig)

0 commit comments

Comments
 (0)