BurnySc2 / python-sc2

A StarCraft II bot api client library for Python 3
MIT License
485 stars 155 forks source link

Assigning amount limits to units trained or buildings constructed #140

Closed VovaTch closed 1 year ago

VovaTch commented 2 years ago

Hi, I started with this package not long ago and I'm working on a Protoss bot trying to make it follow build orders written as a .yaml file. I came across an issue that I can't seem to control the amount of units and buildings the bot builds, i.e. it overshoots very often. For example, I'm trying to set a limit of 22 workers per mining base via:

async def default_econ_power(bot: BotAI, iteration):

    try: # Try and see there is a nexus
        nexus = bot.townhalls.ready.random
    except:
        print('No Nexi are left!')
        return

    if bot.can_afford(UnitTypeId.PROBE) \
            and nexus.is_idle and bot.workers.amount < bot.townhalls.amount * 22:
        nexus.train(UnitTypeId.PROBE)

The nexus always trains 24 instead of the desired 22 if going on one base. Another similar example is where I'm aiming for a 4gate build and the bot often goes to 5 gates.

async def build_building(bot: BotAI, struct_id: UnitTypeId, iteration, location, worker=None, amount_limit=1):

    if struct_id != UnitTypeId.ASSIMILATOR:

        # Count all required buildings
        struct_amount = bot.structures(UnitTypeId.GATEWAY).amount\
            + bot.structures(UnitTypeId.WARPGATE).amount + bot.already_pending(UnitTypeId.GATEWAY)\
            if struct_id in [UnitTypeId.GATEWAY, UnitTypeId.WARPGATE]\
            else bot.structures(struct_id).amount + bot.already_pending(struct_id)

        if (bot.can_afford(struct_id) and 
            struct_amount < amount_limit):

            if worker is None:
                await bot.build(struct_id, near=location)
            else:
                worker.build(struct_id, location)

Similarly it can overshoot the number of stalkers, I want to limit the amount to 5 and I get 7 for example. Am I missing something here? Is this a consequence of some parallel computation scheme here? This is problematic if I want a pinpoint accurate build-order following. I'm using Win11.

BurnySc2 commented 2 years ago

The issue with overshooting the worker count to 24 instead of the wanted 22 is due to 2 workers being in the Assimilator, which means they will not be included in self.workers. This can be fixed by using https://github.com/BurnySc2/python-sc2/blob/40dc00a01544d1405ad15b25ae6250a2e9382ec9/sc2/bot_ai_internal.py#L91

As for the count of the stalkers, I would count them with stalker_count = self.units(UnitTypeId.STALKER).amount + self.already_pending(UnitTypeId.STALKER) and for gateways gateway_count = self.structures.of_type({UnitTypeId.GATEWAY, UnitTypeId.WARPGATE}).ready.amount + self.already_pending(UnitTypeId.GATEWAY) However your gateway building example looks fine to me, or at least I cannot see an issue with it.

If that doesn't work, let me know. Also feel free to join the discord server, where you can ask questions more casually and it is more likely to have an response faster.

For build order bots you could also take a look at https://github.com/DrInfy/sharpy-sc2 which uses this library. This way you don't need to reinvent the wheel.

VovaTch commented 2 years ago

If that's the case for the workers, I can safely just deduct 1 worker per assimilator for the correct maximum amount of workers, it shouldn't affect much the middle-game and end-game I believe. In my bot I already counting the gateways and stalkers with ready.amount + already_pending, I guess the 'ready' makes problems? I'll try without it and I let you know.

About Sharpy, thanks! I'll take a look, I'm just a little concerned about how do I integrate Pytorch neural networks with it, but I guess I'll see.