forked from ClausewitzCPU0/SC2AI
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathch6_Defeating_Hard_AI.py
147 lines (129 loc) · 5.79 KB
/
ch6_Defeating_Hard_AI.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
"""
击败困难电脑
"""
import sc2
from sc2 import run_game, maps, Race, Difficulty
from sc2.player import Bot, Computer
from sc2.constants import NEXUS, PROBE, PYLON, ASSIMILATOR, GATEWAY, \
CYBERNETICSCORE, STALKER, STARGATE, VOIDRAY
import random
class SentdeBot(sc2.BotAI):
def __init__(self):
self.ITERATIONS_PER_MINUTE = 165
self.MAX_WORKERS = 80 # 限制最大农民数
async def on_step(self, iteration: int): # iteration类似游戏时钟 每分钟165个迭代(待确认)
self.iteration = iteration
await self.distribute_workers()
await self.build_workers()
await self.build_pylons()
await self.build_assimilators()
await self.expand()
await self.offensive_force_buildings()
await self.build_offensive_force()
await self.attack()
async def build_workers(self):
"""
选择空闲基地建造农民
noqueue意味着当前建造列表为空
"""
if len(self.units(NEXUS)) * 24 > len(self.units(PROBE)): # 每矿农民补满就不补了
if len(self.units(PROBE)) < self.MAX_WORKERS:
for nexus in self.units(NEXUS).ready.noqueue:
if self.can_afford(PROBE):
await self.do(nexus.train(PROBE))
async def build_pylons(self):
"""
人口空余不足5时造水晶。
"""
if self.supply_left < 5 and not self.already_pending(PYLON):
nexuses = self.units(NEXUS).ready
if nexuses.exists:
if self.can_afford(PYLON):
await self.build(PYLON, near=nexuses.first) # near表示建造地点。后期可以用深度学习优化
async def build_assimilators(self):
"""
建造气矿
"""
for nexus in self.units(NEXUS).ready:
vespenes = self.state.vespene_geyser.closer_than(25.0, nexus)
for vespene in vespenes:
if not self.can_afford(ASSIMILATOR):
break
worker = self.select_build_worker(vespene.position)
if worker is None:
break
if not self.units(ASSIMILATOR).closer_than(1.0, vespene).exists:
await self.do(worker.build(ASSIMILATOR, vespene))
async def expand(self):
"""
何时扩张 简化版
基地数量少于3个就立即扩张
"""
if self.units(NEXUS).amount < 3 and self.can_afford(NEXUS):
await self.expand_now()
async def offensive_force_buildings(self):
"""
建造产兵/科技建筑
"""
# print('iterations:', self.iteration / self.ITERATIONS_PER_MINUTE)
# print('iterations:', self.iteration)
if self.units(PYLON).ready.exists:
pylon = self.units(PYLON).ready.random
# 建造BY
if self.units(GATEWAY).ready.exists and not self.units(CYBERNETICSCORE):
if self.can_afford(CYBERNETICSCORE) and not self.already_pending(CYBERNETICSCORE):
await self.build(CYBERNETICSCORE, near=pylon)
# 建造更多BG
elif len(self.units(GATEWAY)) < ((self.iteration / self.ITERATIONS_PER_MINUTE) / 2): # 粗略计算
if self.can_afford(GATEWAY) and not self.already_pending(GATEWAY):
await self.build(GATEWAY, near=pylon)
# 这个VS放的早啊
if self.units(CYBERNETICSCORE).ready.exists:
if len(self.units(STARGATE)) < ((self.iteration / self.ITERATIONS_PER_MINUTE) / 2):
if self.can_afford(STARGATE) and not self.already_pending(STARGATE):
await self.build(STARGATE, near=pylon)
async def build_offensive_force(self):
"""
建造战斗单位
"""
for gw in self.units(GATEWAY).ready.noqueue:
if not self.units(STALKER).amount > self.units(VOIDRAY).amount: # 粗略判断
if self.can_afford(STALKER) and self.supply_left > 0:
await self.do(gw.train(STALKER))
for sg in self.units(STARGATE).ready.noqueue:
if self.can_afford(VOIDRAY) and self.supply_left > 0:
await self.do(sg.train(VOIDRAY))
def find_target(self, state):
"""
寻找敌方单位
注意这个函数不是异步的,不用加async
"""
if len(self.known_enemy_units) > 0:
return random.choice(self.known_enemy_units)
elif len(self.known_enemy_structures) > 0:
return random.choice(self.known_enemy_structures)
else:
return self.enemy_start_locations[0]
async def attack(self):
"""
控制单位攻击视野内敌方单位
"""
# {UNIT: [n to fight, n to defend] } 也是粗略计算
aggressive_units = {STALKER: [15, 5],
VOIDRAY: [8, 3]}
for UNIT in aggressive_units:
# 如果数量比预定攻击单位数量多,那就主动出击,否则防守(此处疑似代码冗余)
if self.units(UNIT).amount > aggressive_units[UNIT][0] and self.units(UNIT).amount > aggressive_units[UNIT][
1]:
for s in self.units(UNIT).idle:
await self.do(s.attack(self.find_target(self.state)))
elif self.units(UNIT).amount > aggressive_units[UNIT][1]:
if len(self.known_enemy_units) > 0:
for s in self.units(UNIT).idle:
await self.do(s.attack(random.choice(self.known_enemy_units)))
def main():
run_game(maps.get("AutomatonLE"), [
Bot(Race.Protoss, SentdeBot()),
Computer(Race.Protoss, Difficulty.Hard)], realtime=False) # realtime设为False可以加速
if __name__ == '__main__':
main()