Everything is an unit.Random Apex
import sc2 from sc2 import run_game, maps, Race, Difficulty from sc2.player import Bot, Computer from sc2.ids.unit_typeid import * class AlanBot(sc2.BotAI): async def on_step(self, iteration): await self.buildWorkers() await self.distribute_workers() await self.buildRefineries() async def buildWorkers(self): for commandcenter in self.units(UnitTypeId.COMMANDCENTER).ready.noqueue: if self.can_afford(UnitTypeId.SCV) and self.workers.amount < self.units(UnitTypeId.COMMANDCENTER).amount * 14 + 4: await self.do(commandcenter.train(UnitTypeId.SCV)) async def buildRefineries(self): for commandcenter in self.units(UnitTypeId.COMMANDCENTER).ready: vespenes = self.state.vespene_geyser.closer_than(18.0, commandcenter) for vespene in vespenes: if not self.can_afford(UnitTypeId.REFINERY): break worker = self.select_build_worker(vespene.position) if worker is None: break if not self.units(UnitTypeId.REFINERY).closer_than(1.0, vespene).exists: await self.do(worker.build(UnitTypeId.REFINERY, vespene)) run_game(maps.get("AbyssalReefLE"), [ Bot(Race.Terran, AlanBot()), Computer(Race.Zerg, Difficulty.Hard) ], realtime=True)
You need to check different things. When you want to create one Barrack you need:
- A location
- A worker
- Some requirements (such as Supply Depots)
And when you want to create a Marine you need:
- Enough minerals
- At least one Barrack
- A limit of units to create
This is why we create two different functions: buildStructure() and buildOffensiveUnit().
In this function we are going to receive two parameters: the structure that we want to build, and the amount of structures that we want of it.
A good place to start building some Supply Depots and Barracks is around your first Command Center. So we are going to save the position in a variable:
commandCenter = self.units(UnitTypeId.COMMANDCENTER).ready.random nearCC = await self.find_placement(UnitTypeId.SUPPLYDEPOT, commandcenter.position, placement_step=2)
But for the Barracks is a little more special: we need to check if there are already Supply Depots (see the Terran Tech Tree), if we have reached the limit of Barracks that we want, and if we can afford to built it.
The complete function is the following:
async def buildStructure(self, structureName, amount): if self.units(UnitTypeId.COMMANDCENTER).ready.exists: commandCenter = self.units(UnitTypeId.COMMANDCENTER).ready.random workers = self.workers.gathering nearCC = await self.find_placement(UnitTypeId.SUPPLYDEPOT, commandCenter.position, placement_step=2) if structureName == 'supplydepot': if self.supply_left < 6 and self.can_afford(UnitTypeId.SUPPLYDEPOT): if workers: w = workers.furthest_to(workers.center) if nearCC: await self.do(w.build(UnitTypeId.SUPPLYDEPOT, nearCC)) if structureName == 'barracks': if self.units.of_type([UnitTypeId.SUPPLYDEPOT, UnitTypeId.SUPPLYDEPOTLOWERED, UnitTypeId.SUPPLYDEPOTDROP]).ready.exists and self.units(UnitTypeId.BARRACKS).amount + self.already_pending(UnitTypeId.BARRACKS) < amount and self.can_afford(UnitTypeId.BARRACKS): if workers: w = workers.furthest_to(workers.center) if nearCC: await self.do(w.build(UnitTypeId.BARRACKS, nearCC))
The nearCC variable store a location that match a free place for the Supply Depots size. You can add a second location that find a place for the size of the Barracks later.
The offensive unit is the way of the program to spawn our Terrans. We pass it a name, where to build it, and how many of them.
async def buildOffensiveUnit(self, unitName, structureName, maxAmount): structure = self.unitSelector(structureName) unit = self.unitSelector(unitName) if self.units(structure).ready.exists: for struct in self.units(structure).ready.noqueue: if self.can_afford(unit) and self.supply_left > 0 and self.units(unit).amount < maxAmount: await self.do(struct.train(unit))
– Call it all in on_step()
For the bot to do things you need to put all your functions in the on_step() function. That way the program takes control on the synchs, and will launch everything written in the function. Maybe a good thing would be making a FSM machine, but this case is very simple.
You can give it a bit of logic for some amounts of units
async def on_step(self, iteration): await self.buildWorkers() await self.distribute_workers() await self.buildRefineries() await self.buildStructure('supplydepot', 2000) await self.buildStructure('barracks', 4) await self.buildOffensiveUnit('marine', 'barracks', 27) if self.units(UnitTypeId.MARINE).amount > 17: await self.move('marine', True) else: await self.move('marine', False)
Do you want me to release the [very old] code?