Skip to content

whompyjaw/queens-sc2

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

queens-sc2

queens-sc2 is a small customizable library to aid development of sc2 zerg bots developed with python-sc2. A challenge when developing zerg bots is effective queen management since queens have various roles including injecting, creep, defence and nydusing. queens-sc2 was created to allow zerg authors to rapidly develop a bot without being encumbered by queen management. Using policies that can be updated at any time queens-sc2 provides a lot of flexibility, whether that would be aggressive nydus play, defensive queens or a mass creep style

sharpy-sc2 support

Thanks to lladdy, queens-sc2 can now also be integrated with sharpy-sc2. See here for documentation and example code.

Otherwise the rest of this readme assumes integration with python-sc2

Setting up queens-sc2 to work with python-sc2

Prerequisites

It is expected the user has already installed python-sc2, queens-sc2 also relies on numpy and scipy (any modern version is fine).

Getting started

Clone or download this repository and put the queens_sc2 directory in your bot folder like so:

MyBot
└───queens_sc2
│   └───queens_sc2 library files
└───your bot files and directories

Alternatively feel free to download QueenBot from the AI Arena ladder which always contains the most up to date version of queens-sc2.

Example bot file using python-sc2

Out of the box, the library will run without a policy but remember you have to build the queens yourself:

from sc2 import BotAI
from queens_sc2.queens import Queens

class ZergBot(BotAI):
    queens: Queens
    
    async def on_start(self) -> None:
        self.queens = Queens(self)
        
    async def on_unit_destroyed(self, unit_tag: int):
        # checks if unit is a queen or th, library then handles appropriately
        self.queens.remove_unit(unit_tag)
        
    async def on_step(self, iteration: int) -> None:
        # call the queen library to handle our queen_control
        await self.queens.manage_queens(iteration)
        
        # can optionally pass in a custom selection of queen_control, ie:
        # queen_control: Units = self.units.tags_in(self.sc2_queen_tags)
        # await self.queen_control.manage_queens(iteration, queen_control)
        # if not the library will manage all queen_control automatically
        
        
        # the rest of my awesome bot ...

Queen policy

To get the most out of this library, a custom queen policy can be passed to the library with the following options:

queen_policy: Dict = {
  "creep_queens": {
      "active": bool,
      "max": int,
      "priority": Union[bool, int],
      "defend_against_air": bool,
      "defend_against_ground": bool,
      "distance_between_existing_tumors": int, # how far an existing tumor can spread to
      "distance_between_queen_tumors": int, # when deciding to lay a tumor, queen should leave this much distance between existing tumors
      "min_distance_between_existing_tumors": int, # min distance a tumor is allowed to spread to
      "should_tumors_block_expansions": bool,
      # If using Map Analyzer, a list of start and end goals can be passed in for creep targets, creep will then follow these paths
      "creep_targets": Union[List[Point2], List[Tuple[Point2, Point2]]], # library will cycle through these locations
      "spread_style": str, # "targeted" is default, or "random".
      "rally_point": Point2,
      "first_tumor_position": Optional[Point2],
      "prioritize_creep": Callable, # prioritize over defending bases if energy is available?
      "pass_own_threats": bool, # if set to True, library wont calculate enemy near bases, you should pass air and ground threats to manage_queens() method
      "priority_defence_list": Set[UnitID] # queen_control will prioritise defending these unit types over all other jobs
  },
  "creep_dropperlord_queens": {
      "active": bool,
      "max": int, # only supports 1 queen / 1 dropperlord for now
      "priority": Union[bool, int],
      "defend_against_air": bool,
      "defend_against_ground": bool,
      "attack_condition": Callable, # only if you intend for defend queen_control to turn offensive
      "attack_target": Point2, # used by offensive defence queen_control, otherwise not required
      "rally_point": Point2,
      "pass_own_threats": bool,
      "priority_defence_list": Set[UnitID],
      "target_expansions": List[Point2]
  },
  "defence_queens": {
      "active": bool,
      "max": int,
      "priority": Union[bool, int],
      "defend_against_air": bool,
      "defend_against_ground": bool,
      "attack_condition": Callable, # only if you intend for defend queen_control to turn offensive
      "attack_target": Point2, # used by offensive defence queen_control, otherwise not required
      "rally_point": Point2,
      "pass_own_threats": bool,
      "priority_defence_list": Set[UnitID]
  },
  "inject_queens": {
      "active": bool,
      "max": int,
      "priority": Union[bool, int],
      "defend_against_air": bool,
      "defend_against_ground": bool,
      "pass_own_threats": bool,
      "priority_defence_list": Set[UnitID]
    },
    # NOTE: Nydus Queens only become active when a Canal is placed on the map, so assign Nydus Queens to another role then set that role in `steal_from`.
  "nydus_queens": {
      "active": bool,
      "max": int,
      "priority": Union[bool, int],
      "defend_against_air": bool,
      "defend_against_ground": bool,
      "pass_own_threats": bool,
      "priority_defence_list": Set[UnitID],
      "attack_target": Point2,
      "nydus_move_function": Optional[Callable], # completely optional, nydus will still work without this
      "nydus_target": Point2, # not the nydus canal itself, but the target area we want to attack once out of the canal
      "steal_from": Set[QueenRoles], # found in `queens_sc2.consts`, should contain any of: QueenRoles.Creep, QueenRoles.Defence, QueenRoles.Inject
    },
}

However the library has sane defaults for missing values, this is a valid policy for example:

async def on_start(self) -> None:
  early_game_queen_policy: Dict = {
    "creep_queens": {
        "active": True,
        "priority": True,
        "max": 4,
        "defend_against_ground": True,
    },
    "inject_queens": {"active": True, "priority": False, "max": 2},
  }
  
  self.queens = Queens(self, early_game_queen_policy)

You can pass new policies on the fly with the set_new_policy method:

mid_game_queen_policy: Dict = {
    "creep_queens": {
        "max": 2,
        "priority": True,
        "defend_against_ground": False,
        "creep_style": "random",
    },
    "defence_queens": {
        "attack_condition": lambda: self.units(UnitID.QUEEN).amount > 30,
    },
    "inject_queens": {"active": False, "max": 0},
}
self.queens.set_new_policy(queen_policy=mid_game_queen_policy, reset_roles=True)

Attack target for offensive defence queens can be updated:

self.queens.update_attack_target(self.enemy_start_locations[0])

Creep targets can also be updated with a new List of locations. (By default this is set to all expansion locations) Or if using Map Analyzer you can pass in a List of Tuple's, where each Tuple contains a starting Point2 and target Point2, queens-sc2 will then try to creep along the ground path.

# path should ideally contain no creep points
self.queens.update_creep_targets(path_to_third_base)

If using nyduses, make sure the nydus target is updated, this is not where the Nydus should be placed, rather the focal attack point from the Nydus itself:

self.queens.update_nydus_target(self.enemy_start_locations[0])

Creep Dropperlord Queens

queens-sc2 now supports a dropperlord and queen combo. The dropperlord will find a creep target, drop the queen off and poop creep while the queen lays a tumor. After which the queens is picked back up and flown to the next creep location.

** Only supports a single dropperlord and queen combo **

queens-sc2 will steal a creep queen so ensure your policy reflects this. There are already sane defaults for the creep dropperlord but refer to policy example above. queens-sc2 will NOT morph the dropperlord, and you should pass in a Set of dropperlord tags via the main manage_queens method, for example:

await self.queens.manage_queens(
    iteration, 
    creep_queen_dropperlord_tags=self.my_freely_available_dropperlord_tags
)

Despite only a single dropperlord being supported currently, a Set of unit tags is required, in case multiple dropperlords are supported in the future.

SC2 Map Analyzer support

queens-sc2 comes with completely optional support for SC2 Map Analyzer, currently this allows for improved creep spread and better Queen control. A priority avoidance grid may be passed, with threats prepopulated on the grid so that Queens avoid areas.

Example setup with MA (please follow instructions on the MA repo if needed):

    from sc2 import BotAI
    from MapAnalyzer import MapData
    from queens_sc2.queens import Queens
    
    class ZergBot(BotAI):
        async def on_start(self) -> None:
            self.map_data = MapData(self)  # where self is your BotAI object from python-sc2
            self.queens = Queens(
                self, queen_policy=self.my_policy, map_data=self.map_data
            )
            
        async def on_step(self, iteration: int) -> None:
            avoidance_grid: np.ndarray = self.map_data.get_pyastar_grid()
            # add cost to avoidance_grid, for example positions of nukes / biles / storms etc
            ground_grid: np.ndarray = self.map_data.get_pyastar_grid()
            # you may want to add cost etc depending on your bot, 
            
            # depending on usecase it may not need a fresh grid every step
            await self.queens.manage_queens(iteration, avoidance_grid=avoidance_grid, grid=ground_grid)

I only want creep spread

Check the example in creep_example.py which shows how to set a creep policy and manage separate groups of queens.

Contributing

Pull requests are welcome, please submit an issue for feature requests or bug reports.

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • Python 98.8%
  • Dockerfile 1.2%