Hey Screeps world, bonzai and o4kapuk here! This article is about our bunker designs. It may be interesting for people trying to create efficient layouts.
(o4kapuk’s part, best read in a Russian accent)
As I said before, I think that my modifications deserve 25% of the successful defense of E2S7, and here I’ll try to explain each of them, and the approaches behind them, and why I think that they’re so important.
My bunker design is a child of an unnatural intercourse between the bonzai’s original bunker layout and my approaches. Unfortunately, I do not know much about what’s behind his design, so it’s best to ask him to tell us about it.
(bonzai’s part, please lose a Russian accent)
The classic “bonzAI bunker” was my first attempt at implementing an auto-layout. Auto-layout is a problem with potentially limitless depth. I decided for my first iteration, I would keep it simple by using a static arrangement of structures. With some clever arranging, you could fit everything into a fairly compact area. The arrangement itself didn’t need to be cached in memory, it could be defined in a file as a collection of coordinates relative to a single anchor point. The only thing left to do was determine the position and rotation within the room.
This worked very well for its intended purpose. It allowed me to focus on other aspects of my auto-layout implementation. Eventually I even wrote a layout algorithm that would be generated dynamically based on the features of the room. This was important because not every room has the space needed for the fixed layout. However, I started to appreciate my original design for its simplicity and dependability, so I opted to use the dynamic layout only as a fallback.
Like many things in Screeps, I don’t believe there is a single best approach. Walling off the entire room has its virtues and drawbacks, and so does using a bunker design. I don’t believe my own design is the pinnacle. Scrolling around the map, it is possible to find many examples of clever designs. It is interesting that half a year ago, they were fairly rare. It was myself and maybe just a couple other players.
During the weeks that I spent trying to take down o4kapuk’s room, I became very acquainted with his designs and improvements, and even considered stealing them. I’m very glad he has decided to write this article, as it should make that easier to do.
(o4kapuk’s part, best read in a Russian accent)
Now I’m ready to tell you about my own work. Here is an issue: I can’t understandably explain why I did this or that without explaining a background, without describing how my old-style rooms work.
So this is how my old-style room looks like.
Here you can see three blocks of structures: labs block (very popular layout), extensions block (it’s more or less unique because I designed it from scratch earlier) and ‘head’ block with important/energy consuming structures.
Looking at head block you could probably guess my first tenet: the fewer .move(), the better. I took it very seriously to not move creeps unless it’s absolutely necessary. All of my resource management is concentrated in the logic of these small 1 MOVE 8 CARRY creeps always standing inside a head block having all structures in range 1. Understanding this concept is important to realize why I don’t have to prioritize towers charging and extension filing: if my room has energy, my towers always charged. As far as I know, charging priority always was an issue for most low-level players, some mid-level players, and even few high-level players – the issue which can be abused to either drain towers or disable the ability to spawn defenders; that’s how I avoided it. Also worth mentioning that these resource managers always stand next to spawn so they able to renew themselves, just to keep unceasing supplying (I once had a creep in my very first room who was over 2 million ticks old). But, head block is more or less narrow so I had to implement very basic traffic control (which would be useful later in a bunker).
Let’s take a look at my extensions block. It’s not that effective if you use standard approach of .findClosestByPath+.moveTo (too narrow), but with a specialized code, this structure provides a decent filling speed at fairly reasonable cpu cost. Two fillers always standing at their parking spots or running clockwise/counterclockwise by predefined path, thus they do not block each other or other creeps passing through extensions block. They take an energy from the central link and two ‘caching’ containers at their parking spots and refilling them later when idle. All of the aforementioned activity consume 0.4 to 0.9 average cpu/tick for both fillers operating RCL8 room (depends on spawn capacity utilization).
This is a perfect illustration of my second approach: I’m not afraid to write a layout-specific code. I think it’s better to have many efficient implementations than one general-purpose implementation of a task which could work everywhere. Or, it’s best to have many specialized things plus one universal thing, just in case.
Labs block is more or less usual, so nothing interesting to be said about it. Moreover, I shit my pants every time I look into lab worker code, so… I just don’t want to talk about it 🙂
Now when we have the background we’re ready to proceed to the layout itself. I’ll skip all of the considered versions which I declined later.
This is a typical bonzai bunker. It’s easy to see how unfriendly it is to my approaches: there are virtually no good places for my stationary resource managers, and there are no obvious reasonable routes which could be predefined to cover all of the extensions. This puzzled me, so I decided to redesign the placement of structures starting with roads only.
I decided to ram all of my blocks of structures into that bunker.
The obvious candidate to replace ‘head’ block was the central square. If I place a storage to the center and assign my resource managers to stand at the corners, that would give me 12 tiles in range 1: 8 tiles inside the square and 4 more across the roads. 3 spawns, 6 towers, link, terminal, power spawn, nuker and a free tile for storage access require 14 tiles, which is 2 tiles more than I have. After spending hours of placing structures so or so I decided to sacrifice non-critical structures: nuker which require charging only occasionally and power spawn (just because it’s less important than all of the other structures).
Labs were easy to place to one of the corners, just like bonzai did; I was glad that I can keep a the familiar labs layout and be sure that new rooms are fully compatible with my reaction chain templates.
The rest was more or less easy, primarily because not much options left; three free rectangles were the only candidates for predefined simple charge routes so all I had to do is to place all of 60 extensions along that routes.
But here I faced another issue: there was no way to place all of them and keep the same number of free edge tiles for defenders as in the original bunker; I needed 4 more free tiles… but there were no free tiles close to the rectangles.
My options were:
- extend the bunker and do all the job from scratch;
- leave my bunker with 56 extensions;
- sacrifice 4 edge tiles;
- place them somewhere and abandon the idea of predefined charge routes;
- place them somewhere and complicate filing code with checking if they’re empty/losing the path for walking to them;
- place them in corners and extend the routes.
I didn’t like either of the given variants, but, you don’t always get what you want. I had to choose the lesser evil.
- wider bunker is harder to fit into relievo and harder to defend;
- 56-extensions room is not perfect;
- less edge space means less possibility of defense;
- non-routing charging is cpu-expensive;
- complicating the code is… well, complicating the code, I don’t think I have to explain why it is bad;
- extending the routes could make filling noticeable slower
After painful speculation, I decided to choose the third option. Placing nuker, power spawner and observer became the final touch.
I made some changes to resource managers (to make them place an energy into containers) and some changes to extensions fillers (to let them work without a link) and brought the room online to examine results.
The results were very satisfying: cpu consumption of filling was still 0.4..0.9 cpu/tick even with three fillers; filling speed was amazing (significantly faster than my previous ‘diamond’ solution), my basic traffic control was able to solve traffic jams, and as for defensibility… well, that was yet to discover.
Rooms of that type are very hard to take when they’re being properly defended and repaired, they may even seem overpowered. But, key words here are ‘properly defended and repaired’, which is not easy to achieve without advanced code, both military and civilian (efficient extensions filling, smart repairing, advanced traffic management, etc), so the layout itself is not a silver bullet; it’s strong, but not OP.
Moreover, bunker-style rooms have some disadvantages comparing to traditional layouts.
- First, it leaves your room controller unprotected in most cases, you should put additional efforts into protecting it.
- Second, you can’t place a bunker into narrow rooms, so you should have a good offensive code to take more spacious rooms from other players nearby.
- Third, a bunker can’t protect sources and mineral deposit, so when a room is under attack, you should be ready to supply the room from outside.
And here, as promised, the answers to why all of these things are important. The best illustrations I have is defending E2S7 against bonzai’s attack.
- If I did not have the smart fortifying code, the room would have been damaged too heavy by the nukes, and I would’ve lost it.
- If I did not have the efficient filling system, the room wouldn’t have to spawn enough defenders, and I would’ve lost it.
- If I did not have coordinated defense, most probably I wouldn’t have been able to keep attackers at distance, and they would have destroyed my ramparts.
- If I did not have good in-room and inter-room resource management, the room would have starved of boosts, and I would’ve lost it.
- If I did not have a strong economy, I wouldn’t have had enough of said boosts, which means I would’ve lost the room.
- If I did not have advanced traffic manager, I wouldn’t have been able to run enough workers to fortify the room enough (50k ticks to defend against 8 nukes, no shit!), and I would’ve lost it.
- If I did not have my code organized well, I wouldn’t have been able to reload XKHO2 into a free lab about time, and… guess what? Right! I would’ve lost the room.
(some more little secrets are not to disclose yet)
So many ifs, so many probabilities for things to go a wrong way. That story happened how it happened only because of every part of my code and the codebase as a whole had worked as expected, and here is my main secret: do write a good code, don’t be a dick. Be cool instead!
Peace! Or war. Your choice 🙂