Maturity Matrix
While developing your bot, there many, many different implementations different systems can use. Some are more efficient than others, comparing your progress to other such implementations can be useful to gauge where you are and how far you have to go. It is important to remember, that Screeps is a sandbox however, if something works for you and your happy with it, use it. However, if you are looking to improve a system, or just wondering how your implementation can compare then you may find this useful.
Structure
This article will be broken up into various game 'systems' that a bot normally has. Each system will then list different implementations generally from 'least efficient' or 'easiest to code' to 'most efficient' or 'hardest to code'. This will vary by user, of course, some things may be on-par or similar to other implementations efficiency wise, or be a small part to add on not necessarily a full rework.
!! - ~ FINAL WARNING ~ - !!
If you wish to view Screeps as a puzzle based game where your progression is working out your own solutions, then perhaps do not read further. While the following has been attempted to be curated in a way that does not give code examples or strict explanations (when possible) you could be 'spoiled' on various implementations you could have figured out on your own. Then fun of Screeps often comes as a sandbox from setting your own goals and building your own solutions although if you feel stuck, this may help.
Spawning Creeps
Hard-Coded & Console Generated
The first stage for spawning creeps introduced in Screep's tutorial. Creeps can be generated by a user typing the information out into the console, and subsequently spawning the creep, or hard-coding it into the main or other modules. This is very easy, as it is mostly user controlled but not very robust. If data changes in-game (say, a spawn in destroyed) the hard-coded item will cease to function, and a user can only spend so much time without having to fulfil other requirements than spawning creeps, like eating, or sleeping.
If & Else-If Chain & Filter Head-count
Introduced in Screep's Tutorial, this implementation centers around getting a head-count for currently living creeps then going though either a set of IF statements or a chain of IF ELSE IF statements looking for a (normally) hardcoded value. When a discrepancy is found, a spawning call is put out and a creep is spawned. This system can be further improved by optimizing how and when the headcount is done, vs how long / how many statements are checked. This implementation does tend to run into challenges when the number of roles/type of creeps a user is spawning gets past a certain point.
Library Object & Looping
A further evolution of the spawning system, by keeping an 'object' of paired role/type names along with quantities or other data a user can thereby implement a looping architecture to iterate though the object, using the contained data to fetch counts, and compare needs. This can then be further evolved by a management system adjusting counts as needed by pressures of the environment on the colony so that a balance of creeps of many times is maintained when they are needed, or counts reduced when they are not. By executing on a looping structure as well, a user can exit the loop when a legitmite need (spawning creep) is found, meaning that further checks are skipped as they would be redundant / unnecessary to preform since the spawn has found something to act on.
Queue System
Instead of looking down a list of 'highest priority' strictly on an object, a management system can go though its own processes to determine what 'needs to be' spawned next, then simply push it to a queue that the 'spawning system' can execute on when it can, or adjust as needed.
Dynamic Energy Considerations
Another part though not normally a major overhaul, depending on colony/room need some times it is imperative that certain creeps are replenished but not necessarily always at the maximum size. Having a user's spawn system know this, and take into account when it needs to 'make do' with what energy is at hand is useful to maintain a constant operation.
Examples Include:
- Catch-up - If a user's spawn/extension filler(s) have perished and no creep is going to take over, a creep needs to be spawned to do so, even if the 'normal size' is not available due to energy.
- Cold boot / Recovery - If something catastrophic has happened, and a user is not getting any more energy, the spawn system can take this into account (either by measuring income or by measuring reserves) and spawn with what it has to recover accordingly.
Dynamic Part Generation
Normally implemented along-side systems that keep track of things such as Hauling Logistics, Defense/Combat creeps, or other such systems. Dynamic Part Generation takes into account not only that a creep needs to be spawned, but what size and composition it needs to be. Examples include:
- Hauling Logistics - How many 'total carry parts' required to haul energy for a room (or chain of rooms), by how many creeps required/exist (as dependent on RCL creeps can only be so large due to energy requirements) and what energy is available now.
- Combat Logistics - How many 'total combat parts' are required to defeat the enemy defenses / enemy creeps? What configuration/order? Spread out over how many creeps?
Extension & Spawn Filling
First Found Filling
When first filling extensions, generally users have either harvesters or dedicated field fillers that look for energy then seek a target to fill. Generally the 'first empty' target is considered, which can be improved byPath or byRange considerations. Depending on implementation and extension field setup this can mean the creep either passes by, misses, or does not consider the most optimal route when filling.
Sporadic and Opportunity filling
It is quite possible, when haulers of energy are transporting energy to-and-fro that they will come across an extension or extension field in their route. If they are already hauling this energy to be used in the execution of filling and other tasks, why not fill on the fly? By searching their immediate area, if an empty spawn/extension is found a hauler can sporadically choose to execute a transfer operation even while moving as long as the transfer was valid when called. This cuts down on dedicated fillers having to execute on searching/pathing to an extension and speeds up fill time, but can cut down on the efficiency of some field filling routes.
Field and Route Filling
By having predictable extension fields or a dynamic path generator around given fields, when coupled with the spawn's ability to pull energy from a set order of spawns/extensions it is possible to fill extensions in a 'route' such as the creep starts at a designated point then proceeds along the route filling extensions/spawns as it goes cutting down on searching/pathing and speeding up the filling.
Capacitor Filling
A capacitor generally as an electronic component stores electrical energy then discharges it. In concept of extension filling, it is possible to have larger carry size creeps with few-to-no move parts that 'sit' in one space nearby a source of energy (container, storage, ect) then when extensions are used by the spawning process the capacitor creep then feeds on the source of energy and distributes it to the surrounding extensions/spawns without ever having to move. Haulers / other creeps can refill the reserves of the capacitor system, meaning the capacitors themselves only have to execute on withdraw and transfer intents, no pathfinding needed and generally very rapid without having to travel to find energy/a place to put it.
Upgrading a Controller
Harvester & Generic Creeps
As presented in the form of a 'harvester' or 'upgrader' in Screep's Tutorial, mainly these are creeps that gather energy opportunity wise and pump it into the controller. This works well to start, however does mean that they have to mine and pathfind to the source of energy and back to the controller
Static upgraders
Static upgraders can pull from a source of energy (container,storage,terminal ect) and only focusing on upgrading. As Withdraw and UpgradeController are non-conflicting actions, it is possible to consistently pull from the source of energy (when upgrading would put the creep below the lowest amount) and upgrade the controller at the same time. This means the upgrader needs fewer move parts and really, only one carry part as even a 49 part work creep still needs a carry party to use energy from, and as they store 50 energy, can only ever use 49 energy a tick.
Temple rooms, praising and boosts
Though the use of boosts, it is possible to use the same amount of energy but get more 'points' into a controller. Combined with whats known as 'praising' at a temple room, a user can have creeps consistently pump energy into a controller to gain Global Control Level points and speed up progression.
Base Building
User Generated
Bunker Placement
Stamp/Tile dynamic placement
Dynamic pattern / rule generation
Base enclosing (Passive Defense)
User Generated
'Box cut' area
Everything's a Rampart
Choke point / rule defined walls
Minimum cut
Highway Harvesting
User Generated Missions
Scout based / vision based (observer) missions
Scout reports / data based generation
Repairing Structures
First Found / Any damaged
Generally the first method introduced in Screep's Tutorial, repair creeps at an agent level look at all structures in their room, then find ones that are damaged (that their hits property value is not the same as their hitsMax property value) then seek energy (if needed) and repair.
Cached Repairables
Beyond always executing and looking for every structure, making a list or library object containing all damageable / frequently repaired structures (normally indexed/set by ID) then proceeding down the list until a damaged structure is found cuts down on time searching and CPU spent needlessly checking structures that would not be damaged elsewise.
Tower based repairing
Debatably tower repairing allows for a reduction in CPU usage due to their agility to repair anything in a given room however, this is at the cost of more energy. While an improvement for some, it can be considered a determent to others.
Opportunity based repairs
Again, debatable if it saves energy vs CPU, haulers and other general work creeps can in context of their area (repair range of 3 as-of-writing) while in transit to a task/location if they have energy repair on the fly. This again, cuts down on CPU used by repair creeps and energy based tower repairing but does mean the hauler/other creep is giving up energy that it could be spending on its assigned task, and generally, also costs CPU to look at the repairable area.
Task-based assignment
A manager or top-down system can take a look at all repairable structures (or if there are any) in a given tick, and assign tasks to either generic or flexible creeps as they are free or in context of being 'closest' or 'best' to do the task. In this way, tasks are done efficiently and only checked for once by the manager instead of multiple times by various different agents.
Building Structures (Placing Constructure Sites)
User Placed Structures
Queue Placed Structures
Fully Automatic / Automated Plan Structures
Building Structures (Creep based action)
First found / first placed
Most built / most needed
Queue based
Task based (top-down)
Multi-Room Management
Hard coded
Looping Architecture
Dynamic Looping
Harvesting Energy
Harvesters
Harvesters and 'on demand' source mining roles as shown in Screep's tutorial are the first most common implementation of creeps acquiring energy. When a creep needs energy, it seeks out a source acquires the energy needed then moves on. While easy to implement, this often leave sources with energy left-over in them when their regeneration timer goes off, meaning that it is 'wasted' (not used).
Drop-Mining & Static Harvesting
Static harvesters are a big step when it comes to maximizing energy for a room, with a creep or creeps dedicated to harvesting a source, a user can normally drain it long before the regeneration timer lapses meaning the maximum amount of energy is pulled from the source to be used. The first step is normally drop mining where the energy is dropped to the floor, some energy may be lost in this implementation as energy evaporates/sublimates (decays) and is lost forever. However, creeps when needing energy can instead move to these piles to collect energy without having to mine it.
Container Mining & Hauler Logistics
Container mining is a big step in insuring that the decay of the drop mining/static harvesting method is lessened though some investment must be made into the container as its hits will decay and require repair at a rate dependent on the state of the room (Owned/Unowned). To drop mine into the container, a creep also has to specifically select a location to stand, and always stand on to insure the energy is property dropped into the container.
Remote Mining
Once a room's energy has been harnessed, energy from other rooms can be as well. This becomes more complex due to having to assign miners to multiple rooms, getting them to the rooms (pathing), building and maintaining containers, reserving the room to increase the energy, and various other tasks.
Source Keeper Mining
Currently the hardest challenge when it comes to gathering energy. While source keeper's (SK's) rooms are very energy rich, and even include a mineral with a public extractor to mine resources from they are always guarded by SKs generated from SK lairs paired with each source. As well invasions in these rooms still occur and with stronger invaders as well as Invader Strongholds which have a chance to spawn.
To mine a SK room you generally need:
- A way to kill the keepers consistently
- Miners that know to avoid danger
- Haulers that know to avoid danger
- A way to deal with, or avoid invasions
- A plan for how to deal with or avoid Strongholds
Hauling Logistics
Opportunity Gathering
Generally when first starting on hauling energy around to either store or use, the first implementation tends to be having creeps seek out sources (such as piles of energy, containers with energy or storages) and then transporting to some centeralized location dependent on the creep's function (container/drop -> storage or storage -> controller to use for upgrading, ect). without consideration of other creep(s) actions.
Mining / Hauler Pairs
Another implementation is to have every container/drop miner have its own 'twin' hauler, this way there is not a conflict in different haulers going for similar tasks, but depending on how they are managed does mean the creep may have downtime or be waiting for a miner to spawn, or other situations in where it could do something else while 'waiting'
Task execution
When using a Top-Down or Management based approach haulers generally execute on tasks that they are assigned by their manager. The manager takes care to not have conflicts and assign tasks as-needed.
Creep Combat
// Break down into 'Creep Combat managment' vs 'spawning combat creeps'?
User-Spawned Defenders/Attackers
Automatic Spawning & Defending
Fully Automatic Dynamic Spawning
Time To Kill / Time to Die
Find Closest & Attack
Kiting & Ranged combat
Duo-combat
Quad-Combat
Room Attacking
Find any wall
Find Weakest / easiest path to goal
Observability (Logging & Statistics)
Console.log() and basic debugging
Room Visuals & Map Visuals
Web API & External Tool logging / visualization
Road Placement & Networks
User generated
Opportunity / frequency based placement
Cached Path based / PathFinder based generation
Multi-Path/goal based recursive generation
Alternative / custom based algorithms
minimum spanning tree
Factory Management
Mimnum filling & manual orders
Chaining & multiple tier managment
Full automatic production, balancing and T5 production
Lab Logistics
User Generated demands
Recipe demand
Fully automatic Recipe switching & lab configuring
Terminal Logic
Basic filling & hard coded / console transfering/dealing
Task based / need based filling & transfering/dealing
Fully automatic task-based system / Queue execution
Market Actions
User Generated
Automated Opportunity based Buying / Selling
Arbitrage based Buying / Selling
Inter-Shard based buying / selling
Arbitrage Inter-Shard based Buying / Selling
Scouting & Storing Information
Random Scout movement
Progressive / Area / Timed Scout movement
Pure String/object based storage
Compressed/encoded information
Creep Movement (Pathfinding)
moveTo
moveTo is the main pre-packaged solution when it comes to pathfinding, a user mainly only has to set a target desired to 'move to' and the function takes care of the pathing, caching and executing of the movement all in one. This is a powerful function that will carry a user far, however possibly by design it is not 'perfect' allowing the user to get familiar with the movement system and evolve past it in the future.
adding Options to moveTo
moveTo allows for various opts or 'options' to be passed as an argument in the form of an object along with the target you are looking to move to. These options can have a huge impact on the way moveTo itself acts and behaves allowing for more complex/efficient movement.
reusePath
by default, moveTo will cache and use the results of 'new' moveTo request for 5 ticks, or when it crosses a exit tile (as paths are only cached an encoded string 'in room'). This behavior can be modified by passing an object with the property reusePath
along with a numerical value of the amount of game ticks the user wishes the function to reuse the cached path. Depending on how far away the target is, or the complexity of the room(s) considered, repathing every 5 ticks can become costly when many creeps are considered. Increasing this, means that you have creeps that will reuse the path for longer but will react slower to pathing obstructions. This is up to the user to resolve normally in the form of collision management.
ignoreCreeps & Collision management
by default, moveTo will consider creep objects found when pathingfinding as 'impassable'. This means that it will attempt to pathfind around the creep found in the path, which can result in higher costs, even though the creep in the path is moveable, or may have moved by the time the creep arrives at that step in the path. The ignoreCreeps
option allows for a user to as the name suggests, tell moveTo to ignore creeps when considering blockages/obstacles in the path. This generally allows for faster/shorter routes to be found as in a crowded base or a long busy areas of road creeps can often be found.
However, if the creep in question blocking the path remains, that is where collision management comes in. moveTo will continue to attempt to execute the next step in the path, even though the path is obstructed meaning the creep does not move. Implementing a system that detects when a path obstruction/blockage/collision has occurred, and then resolving it helps fix this issue as insures that the creeps are taking the 'shortest route'
range
by default, the moveTo will attempt to path 'onto or near' the object it is targeting. However, there are times when moving between rooms or to certain areas that the user's creeps do not need to necessarily worry about being so precise. For example, a creep traveling to a distant room to scout without vision does not need to path to any particular tile to do so, just enter the room. This is where the range
option comes in handy, the pathfinding of moveTo will attempt to find a pathable location 'in range' of the target provided meaning many operations of pathfinding can be saved thus saving CPU.
maxRooms and maxOps
While not necessary in most use-cases, these two operations are important in several specific functions. For example with maxRooms, you can tell the moveTo function to only consider X number of rooms when pathfinding. If you have a creep, for example, that you want to only ever stay within its home room for whatever reason, then you can pass a maxRooms opt of 1 and it will not attempt to path outside of the room to get to any given target (even if it is a shorter path). As well, maxOps allows the user to set the maximum number of operations while pathfinding, when going a far distance or a complex path, increasing the number of maxOps opt will allow it to run for longer hopefully finding a path. This does, however, use more CPU.
costCallback and PathFinder.CostMatrix
by default, the moveTo system will use the built in PathFinder in screeps to create and cache (when necessary) CostMatricies for a user's creeps to use when using moveTo. With the costCallback option however, a user can provide a customized cost matrix to be used instead of the default one that is generated/cached. This is probably the more complex of the options and likely the last step before moving on beyond the confines of moveTo. The user must make a costMatrix for a room considering (or not considering) all impathable objects, this can include custom values for whatever locations the user desires either to fully obstruct or allow passage though. An example, say the user has dedicated static mining creeps that should not move, or be moved. As such, even though the container they stand on is passable, or the creep passable if ignoreCreeps is on, the user can modify the costmatrix for the room to make this location impassable so the creeps do not consider it when trying to move, allowing the miner to continue without being obstructed, moved ect.
PathFinder.search
This is the base function that as-of-writing all other pathfinding functions in Screeps uses. It is by far the most powerful solution to pathfinding given by the API. It requires the user to be far more specific when passing options but allows for a wide flexibility of path generation options.
Path Caching & moveByPath
Generally once a user has become familiar with the pathfinder system, they can begin storing paths to be reused along common routes. An example would be a miner is always assigned to X source, and spawns from a spawn. The route is always the same, or becomes the same once they reach a certain point along the path. This path can be found, cached, and then reused by moveByPath or a user's custom implementation to execute move commands so that instead of pathfinding every time, the user only has to pathfind the once, or once in a while (incase new structures or obstructions have been added) dramatically reducing CPU costs.
Node Networks & cached path assignment
Once paths have been cached, a user can then evolve into caching common routes or destinations to areas that can be reused by various creeps dynamically instead of by specific need. Mainly, a user needs to create this pathing network with a 'start' node and 'end' node or any other amount of 'nodes' they desire. A creep (or its management system) can then consider its position as well as the position of its assigned task (goal position, lets say) when looking for a path. If the goal position is within X distance of a pathing end, start, or other node and the creep is within Y of the 'other end' of the cached path / node pair then the creep can be assigned the cached path to use for traversing to nearby its target. This may require a short moveTo/pathing operation to snap to / affix to the path, but once on the path movebypath or a user's system of executing moves by the stored path can be used. The creep thereby didn't need to do the complex pathing operations to its target, only short jumps, saving CPU.
An Example:
A hauler creep is assigned a container in a remote harvesting room 2 rooms away, it is currently idling by the storage from a previous drop off. The hauler creep first looks at node(s) in the same room as its target, searching for the closest one to its assigned container, the creep then looks for the node(s) that pair with the desired node(s) for ones it is standing on or near to. Once found, it then moves to the 'start' node and once there, proceeds along the path till it is nearby its target (or closer enough to leave the 'rail' path).
Creep Action Management
Role Modules & Agent Based Approach
An agent based approach known as 'roles' is what is presented in Screep's Tutorial. Primarily, each creep is assigned a role via memory (normally as a string) which is used to then determine what module (normally of the 'same' or similar name) to have the creep execute. The creep then works though the module's logic to determine what to do and how to act. This works well in keeping creeps consistent and focused with their logic, however it does mean that unless otherwise programmed to do so, they only consider their own situation and also normally run checks multiple times instead of just once.
Top Down / Management based Approach
A Top-Down or Management based approach primarily means that instead of each creep being responsible for finding its own goals, targets, information and the like, it is instead assigned these things by a manager considering the entire picture. This enables the system to fetch data as-needed, pass it / use it over the span of multiple creeps instead of multiple times over creeps and even change creeps as needed.
An example:
A management system for assigning tasks for haulers beings its tick. It looks first for available haulers that do not have a task assigned to them, if found, it then proceeds to look at all available containers assigned to its room, filtering out any containers that are already assigned to other creeps already or that energy will be not enough for the task to be worth assigning. If containers were found, it then progresses though the available creeps, assigning them to containers as they are available. The creeps (or their own different management systems) then only act on their assigned task.