my screeps arena bot architecture “journey”

different environment, new opportunities

as a screeps world veteran who tends to have difficulties sticking to an architecture and who is somehow almost always writing boilerplate one thing was clear: the release of screeps arena and the new engine are an opportunity to start designing again!

the main differences between world and arena my architecture ideas revolved around were:

  • there is no need to design around intent cost anymore
  • there is no need to design around resets anymore
  • there is no need to design around the game map anymore (no more room edge cases! ha)

attempt 1: old habits

if i remember correctly my first idea was to port my screeps world architecture over, an idea which i threw out fairly quickly. the big advantage was obvious: it already existed. so i started porting over my code, refactoring some of the assumptions it made to fit the screeps world environment. it definitely worked, but i was noticing that i was basically throwing out pretty much everything except the skeleton. and the more i tried using it, the more i noticed that it just didnt quite feel like it would fit.

the whole bot felt a bit bloated. for example there really is no need for an overarching “empire” entity, a lot of assumptions around rooms and room owners are just completely irrelevant in arena. there is no real need for the concept of missions since there usually is only one “mission” in arena. the list goes on. i wanted something slimmer.

attempt 2: getting experimental

my next train of thought was a bit more data oriented. the idea: using an entity component system (ecs) to manage things. every game object in screeps arena already has an id, there we go: entities! just gotta map them to the game object somewhere… now throw in a bunch of components and write systems and we are good to go, right? not quite sadly.

i was very convinced by this attempt actually, i think it resulted in quite neat and simple code. once i was a couple hundred lines in i noticed that the ecs approach had a limit too: me and my limited understanding of data oriented design. well and things like the typical “role” code did not really go well with ecs.

attempt 3: remixing things for simplicity

the contant translation between actual game objects and ecs was another factor in the decision of moving away from that approach. the name of the game is KISS now! throwing properties on prototypes, writing “naive” functions instead of overdesigning things. meanwhile i could actually re-use most of my ecs systems code, just had to make it deal with game objects directly! throw in some role related things, and the bot was coming together nicely.

as i was hacking away some basic test strategies (the pure rush bot in simple CTF still being top 10 is highly amusing) i was noticing that i was approaching the game from the bottom up with the way things were organized: creeps were making strategy decisions in their role code, things got out of hand fairly quickly.

the obvious solution was to add a strategy layer that influences the decisions the individual agents make. i was playing around with different prototypes for a while and ended up looking at a bunch of star craft bots. the concepts used in those bots are mostly nicely applicable in screeps arena too.

attempt 4: hierarchical task networks

one star craft bot that i liked the design of in particular was purple wave. purple wave sets up a bunch of tasks, tasks then get prioritized and lock up resources like units, areas on the map or supplies. for micro the bot then picks intentions (sound familiar?) for each unit, and then it executes actions in game from there.

what i really liked about this was the way it structured the code:

 class GoSpeedlings extends Parallel(
    new Trigger(
      new GasForUpgrade(Zerg.ZerglingSpeed),
      new CapGasAt(0)),
    new Build(Get(Zerg.ZerglingSpeed)),
    new Pump(Zerg.Zergling),
    new If(
      new And(
        new UpgradeComplete(Zerg.ZerglingSpeed),
        new MineralsAtLeast(300)),
      new Build(Get(4, Zerg.Hatchery)))
  )

from my limited testing this approach seemed too expensive cpu wise however.

moving on, i just kept purple waves abstraction of gathering intel about the opponents strategy. in the star craft bot it is called fingerprinting, i am calling my (very much) simplified version “signals”. more on them later.

attempt 4: the current design

inspired by checking out various other star craft bot strategy layers i ended up with the following architecture (which i also intent to keep): the strategy layer deals with a StrategyEngine (probably one for each game mode for now, but the possibility is there to have multiple engines for testing or similar).

The StrategyEngine detects the hostile strategy, picks a (hopefully) good counter strategy to execute and handles transitions between strategies.

a strategy is a set of prioritized Plays. each play influences both spawning (by requesting creeps from the spawn), assignments (by requesting creeps from the StrategyEngine) and its assigned creeps (if any, by managing a Squad).

(of course the bot also has features outside of the strategy layer.)

my next post will describe these interactions in more detail!

conclusion

what im describing very briefly here took a lot of time. my screeps time is currently very limited so the many hours i spent experimenting with these different concepts spanned months due to being spread out so much.

my main hope is that the design i ended up with is flexible enough to be able to solve any arena that gets thrown at us. it certainly looks that way!