|
| 1 | +from functools import reduce |
| 2 | +from operator import or_ |
| 3 | +import random |
| 4 | + |
| 5 | +import sc2 |
| 6 | +from sc2 import Race, Difficulty |
| 7 | +from sc2.constants import * |
| 8 | +from sc2.player import Bot, Computer |
| 9 | +from sc2.data import race_townhalls |
| 10 | + |
| 11 | +import enum |
| 12 | + |
| 13 | +class BroodlordBot(sc2.BotAI): |
| 14 | + def select_target(self): |
| 15 | + if self.known_enemy_structures.exists: |
| 16 | + return random.choice(self.known_enemy_structures).position |
| 17 | + |
| 18 | + return self.enemy_start_locations[0] |
| 19 | + |
| 20 | + async def on_step(self, iteration): |
| 21 | + larvae = self.units(LARVA) |
| 22 | + forces = self.units(ZERGLING) | self.units(CORRUPTOR) | self.units(BROODLORD) |
| 23 | + |
| 24 | + if self.units(BROODLORD).amount > 2: |
| 25 | + for unit in forces: |
| 26 | + await self.do(unit.attack(self.select_target())) |
| 27 | + |
| 28 | + if self.supply_left < 2: |
| 29 | + if self.can_afford(OVERLORD) and larvae.exists: |
| 30 | + await self.do(larvae.random.train(OVERLORD)) |
| 31 | + return |
| 32 | + |
| 33 | + if self.units(GREATERSPIRE).ready.exists: |
| 34 | + corruptors = self.units(CORRUPTOR) |
| 35 | + # build half-and-half corruptors and broodlords |
| 36 | + if corruptors.exists and corruptors.amount > self.units(BROODLORD).amount: |
| 37 | + if self.can_afford(BROODLORD): |
| 38 | + await self.do(corruptors.random.train(BROODLORD)) |
| 39 | + elif self.can_afford(CORRUPTOR) and larvae.exists: |
| 40 | + await self.do(larvae.random.train(CORRUPTOR)) |
| 41 | + return |
| 42 | + |
| 43 | + if not self.townhalls.exists: |
| 44 | + for unit in self.units(DRONE) | self.units(QUEEN) | forces: |
| 45 | + await self.do(unit.attack(self.enemy_start_locations[0])) |
| 46 | + return |
| 47 | + else: |
| 48 | + hq = self.townhalls.first |
| 49 | + |
| 50 | + for queen in self.units(QUEEN).idle: |
| 51 | + abilities = await self.get_available_abilities(queen) |
| 52 | + if AbilityId.EFFECT_INJECTLARVA in abilities: |
| 53 | + await self.do(queen(EFFECT_INJECTLARVA, hq)) |
| 54 | + |
| 55 | + if not (self.units(SPAWNINGPOOL).exists or self.already_pending(SPAWNINGPOOL)): |
| 56 | + if self.can_afford(SPAWNINGPOOL): |
| 57 | + await self.build(SPAWNINGPOOL, near=hq) |
| 58 | + |
| 59 | + if self.units(SPAWNINGPOOL).ready.exists: |
| 60 | + if not self.units(LAIR).exists and not self.units(HIVE).exists and hq.noqueue: |
| 61 | + if self.can_afford(LAIR): |
| 62 | + await self.do(hq.build(LAIR)) |
| 63 | + |
| 64 | + if self.units(LAIR).ready.exists: |
| 65 | + if not (self.units(INFESTATIONPIT).exists or self.already_pending(INFESTATIONPIT)): |
| 66 | + if self.can_afford(INFESTATIONPIT): |
| 67 | + await self.build(INFESTATIONPIT, near=hq) |
| 68 | + |
| 69 | + if not (self.units(SPIRE).exists or self.already_pending(SPIRE)): |
| 70 | + if self.can_afford(SPIRE): |
| 71 | + await self.build(SPIRE, near=hq) |
| 72 | + |
| 73 | + if self.units(INFESTATIONPIT).ready.exists and not self.units(HIVE).exists and hq.noqueue: |
| 74 | + if self.can_afford(HIVE): |
| 75 | + await self.do(hq.build(HIVE)) |
| 76 | + |
| 77 | + if self.units(HIVE).ready.exists: |
| 78 | + spires = self.units(SPIRE).ready |
| 79 | + if spires.exists: |
| 80 | + spire = spires.random |
| 81 | + if self.can_afford(GREATERSPIRE) and spire.noqueue: |
| 82 | + await self.do(spire.build(GREATERSPIRE)) |
| 83 | + |
| 84 | + if self.units(EXTRACTOR).amount < 2 and not self.already_pending(EXTRACTOR): |
| 85 | + if self.can_afford(EXTRACTOR): |
| 86 | + drone = self.workers.random |
| 87 | + target = self.state.vespene_geyser.closest_to(drone.position) |
| 88 | + err = await self.do(drone.build(EXTRACTOR, target)) |
| 89 | + |
| 90 | + if hq.assigned_harvesters < hq.ideal_harvesters: |
| 91 | + if self.can_afford(DRONE) and larvae.exists: |
| 92 | + larva = larvae.random |
| 93 | + await self.do(larva.train(DRONE)) |
| 94 | + return |
| 95 | + |
| 96 | + for a in self.units(EXTRACTOR): |
| 97 | + if a.assigned_harvesters < a.ideal_harvesters: |
| 98 | + w = self.workers.closer_than(20, a) |
| 99 | + if w.exists: |
| 100 | + await self.do(w.random.gather(a)) |
| 101 | + |
| 102 | + if self.units(SPAWNINGPOOL).ready.exists: |
| 103 | + if not self.units(QUEEN).exists and hq.is_ready and hq.noqueue: |
| 104 | + if self.can_afford(QUEEN): |
| 105 | + await self.do(hq.train(QUEEN)) |
| 106 | + |
| 107 | + if self.units(ZERGLING).amount < 40 and self.minerals > 1000: |
| 108 | + if larvae.exists and self.can_afford(ZERGLING): |
| 109 | + await self.do(larvae.random.train(ZERGLING)) |
| 110 | + |
| 111 | +def main(): |
| 112 | + sc2.run_game(sc2.maps.get("Abyssal Reef LE"), [ |
| 113 | + Bot(Race.Zerg, BroodlordBot()), |
| 114 | + Computer(Race.Terran, Difficulty.Medium) |
| 115 | + ], realtime=False, save_replay_as="ZvT.SC2Replay") |
| 116 | + |
| 117 | +if __name__ == '__main__': |
| 118 | + main() |
0 commit comments