<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="https://sy-harabi.github.io/feed.xml" rel="self" type="application/atom+xml" /><link href="https://sy-harabi.github.io/" rel="alternate" type="text/html" /><updated>2026-06-16T15:13:11+00:00</updated><id>https://sy-harabi.github.io/feed.xml</id><title type="html">Harabi Screeps</title><subtitle>Screeps player with nickname Harabi</subtitle><author><name>Harabi</name></author><entry><title type="html">Theorycrafting a Combat Blob: A Research Log</title><link href="https://sy-harabi.github.io/Theorycrafting-a-Combat-Blob-A-Research-Log/" rel="alternate" type="text/html" title="Theorycrafting a Combat Blob: A Research Log" /><published>2026-06-16T00:00:00+00:00</published><updated>2026-06-16T00:00:00+00:00</updated><id>https://sy-harabi.github.io/Theorycrafting-a-Combat-Blob-A-Research-Log</id><content type="html" xml:base="https://sy-harabi.github.io/Theorycrafting-a-Combat-Blob-A-Research-Log/"><![CDATA[<p>A <strong>blob</strong> is the least structured attack force in Screeps: a loose pack of combat creeps, no formation, that you shove at an enemy base and hope survives. No clever shape to hold, nothing to micro, <em>or so it looks</em>. Anyone who’s tried it knows better. Keeping a blob alive on a defended room is one of the game’s nastier movement problems, and I’d left it alone for a long time precisely because it looked too hard to be worth the trouble. What changed my mind was watching other players pull it off: the blobs droidFreak and iamgqr have been running lately were equal parts inspiration and a push to finally start.</p>

<p>Knowing how hard it is, I didn’t want to wing it. So this series is less a victory lap than a build log: how I started from a testbed instead of tactics, and how a vague goal, “move the blob in,” turned into a handful of precise, measurable questions. This first post is the map. It’s mostly a tour of the ideas that <em>didn’t</em> work, because that’s where the questions got sharp.</p>

<div style="text-align:center; margin:1.5em 0">
  <iframe width="315" height="560" src="https://www.youtube.com/embed/063zXcRSQhc" title="A blob in the field" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen=""></iframe>
  <div style="font-size:0.85em; color:#888; margin-top:0.4em">One of mine, live on the server.</div>
</div>

<h2 id="three-goals-that-wont-sit-still">Three goals that won’t sit still</h2>

<p>Strip the blob down and there are only three things it’s trying to do, and they pull against each other every tick:</p>

<ul>
  <li><strong>Survive</strong>: don’t let a single creep die to focused fire.</li>
  <li><strong>Advance</strong>: close the distance to whatever you came to kill.</li>
  <li><strong>Park</strong>: once in range, hold still and keep as many attackers shooting as possible.</li>
</ul>

<p>Advancing means walking into massed tower fire that only gets worse the closer you get; parking deep is where you do damage and also where you die. And the enemy is a black box: I don’t get to know who they’ll shoot. The first real decision of the project was to stop guessing. <strong>I never model the enemy’s mind, only my own worst case.</strong> If a creep survives <em>any</em> focus the defense could put on it, I don’t care what it actually does. That one move turns “what will they do,” which is unanswerable, into “what’s the worst they <em>could</em> do,” which is just arithmetic over the towers and defenders in range.</p>

<p>That’s the pattern the whole series is really about: taking a question I can’t answer and beating it into one I can compute and measure.</p>

<h2 id="physics-first-policy-second">Physics first, policy second</h2>

<p>Before writing a line of tactics I built a deliberately dumb simulator. It knows Screeps combat physics: how damage lands, how heal nets against it, how moves and fatigue resolve, and nothing else. Hand it everyone’s intended moves, attacks, and heals for a tick and it returns the next state. That’s the entire job.</p>

<p>Every actual decision (where to move, who to heal) lives <em>outside</em> it, as a function that reads the world and proposes intents. The simulator only grades. It’s a wind tunnel: the engine is the air, each tactical idea is a shape I drop in and measure, and nothing I’m testing also gets to be the thing doing the measuring.</p>

<p>This is the highest-leverage decision in the project, entirely because the physics is pure and deterministic. Determinism is what lets me run thousands of ticks a second offline, isolate one idea, and replay any battle exactly the same way twice, which is the only reason the A/B numbers further down mean anything. The search layer that sits on this seam (how you pick a joint move for the whole blob each tick without it costing a fortune in CPU) is the most involved engineering in the project, and it gets its own post.</p>

<h2 id="one-classifier-shared-by-both-halves">One classifier, shared by both halves</h2>

<p>Two layers do the deciding: one moves the creeps, one routes the healing. They have to agree without reaching into each other’s internals, and the thing that lets them is a single classification. For each creep, on each tile it might step to, I weigh the <strong>worst damage it could take there</strong> against the <strong>most healing I could actually route to it</strong>, and label the result:</p>

<ul>
  <li><strong>Safe</strong>: survives the worst case on its own HP.</li>
  <li><strong>Rescue</strong>: dies on HP alone, but heal can cover the gap.</li>
  <li><strong>Doomed</strong>: no reachable amount of heal saves it.</li>
</ul>

<p>The point of three labels instead of a number is that <strong>survival is a gate, not a score.</strong> The blob never trades a death for progress at any exchange rate; one Doomed creep vetoes the entire plan.</p>

<p>My first version of that veto was wrong in a way worth keeping. It summed danger over <em>every</em> creep at once. So the creep at the very front, eating the most fire but sitting at full HP and the last one any sane defender would shoot, dumped a huge number into the sum and tripped the veto, freezing the advance for nothing. The fix was to gate on the one creep the defense would actually kill: the thinnest survival margin, not the largest incoming number. “Who’s taking the most fire” and “who can the enemy actually kill” are different questions, and only the second should be allowed to stop the blob. The classifier carries more than this one fix, and I’ll give it its own write-up.</p>

<h2 id="stock-vs-flow">Stock vs. flow</h2>

<p>For a while the blob handled big fortresses and then died, embarrassingly, to the cheapest defense on the board: two towers on a chokepoint. The expensive base was the easy one, and the cheap one kept killing it. I stared at that backwards result for a long time.</p>

<p>The bug wasn’t in the code, it was in the question. Every survival check I’d written asked <strong>“are we hurt?”</strong> That’s a <em>stock</em> question, about how much HP is in the tank right now. Against a slow trickle of tower fire the blob is never visibly hurt; it just loses a sliver more than it heals each tick until somebody quietly crosses zero. The question that actually mattered was a <em>flow</em> one: <strong>“is the bleed outrunning the heal?”</strong></p>

<p>Rewriting survival around flow instead of stock was the turning point of the project. On a heavily-walled fortress bed it pulled attack efficiency from <strong>0.146 to 0.719</strong>, from flinching at the wall to locking onto the target, and the two-tower case that started the whole thing got its fix one layer up (next section). Almost everything good that came later is some version of this same swap.</p>

<h2 id="knowing-when-to-leave">Knowing when to leave</h2>

<p>A blob that never retreats is just a slower way to lose. But retreating is something the move layer can’t do on its own, and the reason is myopia: the solver only ever optimizes the next tick. Close to a base that’s fatal. Inside a tower’s flat max-damage band every adjacent tile reads the same maximum hit, so a one-tick-greedy policy sees no gradient to follow out; every direction looks equally lethal, it never commits to the run of bad tiles a real escape costs, and it just stands in the fire and dies.</p>

<p>That’s the job of the next layer up: a small state machine, <strong>ADVANCE, RETREAT, HOLD</strong>, that holds a decision across many ticks no single tick could justify. RETREAT hands the solver a goal to walk toward while the local field is flat, and a flow test decides when to commit to it, the moment the bleed starts outrunning the heal. (The old trigger was stock-based and fired far too late, around 12% HP, while HOLD kept re-parking the blob on the next full-HP creep and feeding one death per cycle.) On the two-tower chokepoint that used to wipe every run, this took the blob from <strong>0 of 8 survivors to 7 of 8 clean</strong>, though only once it also stopped scattering on the way out, which is the next section’s problem.</p>

<div style="margin:1.5em 0; text-align:center">
  <a href="/assets/sim/blob-retreat.html" target="_blank" rel="noopener" style="display:inline-block; padding:0.7em 1.2em; border:1px solid #888; border-radius:6px; text-decoration:none; font-weight:600">&#9654;&nbsp; Open the interactive sim (new tab)</a>
  <div style="font-size:0.85em; color:#888; margin-top:0.6em; text-align:left">Two towers, open ground, six creeps: the macro layer cycling <b>advance &rarr; retreat &rarr; hold</b> and back. It opens a tick-stepper in a new tab &mdash; hit Play, or step one tick at a time with the arrow keys. (The 0/8 &rarr; 7/8 figures above come from the tighter two-room chokepoint bed; this is the same machinery on open terrain, where it reads more clearly.)</div>
</div>

<h2 id="holding-together-without-clumping-to-death">Holding together without clumping to death</h2>

<p>Creeps that drift get picked off alone, so I added a gentle pull toward the pack’s center, just enough to keep a straggler from wandering off the edge and dying by itself.</p>

<p>This looked like a genuine no-win trade-off, and I believed it for a while. The pull’s worth turns out to depend entirely on the terrain. On broken, walled maps, where a blob can get cut into pieces it can’t reunite, holding together is the only thing keeping it from being divided and killed a creep at a time. On open ground there’s nothing to divide it: every creep can reach its own best tile, and cohesion does nothing but drag each one off that optimum. Opposite preferences, no single setting serving both, and I almost filed it as a law of the problem.</p>

<p>The conflict came down to one thing: the pull was a single linear knob. One strength, applied to every creep, so anything strong enough to reel in a separating straggler tugged a settled creep off its optimum just as hard, and no value served both terrains at once. The fix wasn’t a compromise number, it was a different shape. I changed the pull from linear to quadratic, the distance to the pack’s center times the distance to where that center is heading, which sits near zero inside the swarm and climbs steeply only at the edge. Now it grips only the creeps actually drifting off and leaves the packed middle alone, which is what each terrain wanted all along.</p>

<p>(I’d tried cleverer pulls first. One tracked each creep’s own heading instead of the group’s; another enforced spacing with no sense of the pack’s shape. Both failed for the same reason: neither carried the only signal that mattered, how far <em>this</em> creep is from everyone else. A post of its own.)</p>

<p>So cohesion kept its place, not as the “hold formation” rule I first imagined but as a light nudge that grips only the creeps slipping off the edge.</p>

<h2 id="the-body-is-the-other-half-and-the-half-im-on-now">The body is the other half, and the half I’m on now</h2>

<p>I spent most of this obsessing over movement, but what you <em>spawn</em> is the other half of the problem, and it’s where the work actually is right now. Part order is a live design axis: a TOUGH plate up front, boosted hard enough to buy the formation time without costing firepower, and the heal-to-ranged split set against the focus you expect to eat. I’m trying to fold all of it into a closed-form <code class="language-plaintext highlighter-rouge">chooseBody</code>: a body straight from an energy budget and a boost tier, no simulation, so the live bot can call it inline.</p>

<p>It is not settled. The towers-only case works; against real defenders the calibration is still open, and I’ve already thrown out one version I was sure was finished. This is the current frontier of the project, not a closed box. It gets written up when it actually holds, not a post sooner.</p>

<h2 id="how-i-keep-myself-honest">How I keep myself honest</h2>

<p>The only reason any of the above is trustworthy is the measurement discipline, and it’s the part I’d hand a new builder first. Every change is A/B’d against a frozen baseline on the <em>same</em> seeds, never a fresh batch of battles. I judge on survivors and attack efficiency, over at least 8 seeds and 500 ticks, because tick-to-tick noise is large enough to fake a result on its own. And I sweep the whole ladder of scenarios, not one, because <strong>single-point tuning lies</strong>: constants I tuned on a fortress died on a chokepoint, and most of my “wins” evaporated the moment I swept across beds. That sweep, the one that tells you you were wrong, is most of what the lab is for.</p>

<h2 id="if-you-want-to-build-your-own">If you want to build your own</h2>

<p>The blob is nowhere near finished, which is most of the appeal. If this makes you want to build one, here’s roughly what I’d tell you.</p>

<p>Build the simulator before any tactics, and make every idea earn its place by beating the last one on the same battles. Spend real effort on the one abstraction your layers share. Mine was Safe / Rescue / Doomed, and one clean concept that lets the layers cooperate beat any number of clever heuristics. Watch flows, not stocks: “are we losing ground faster than we can recover it” is the better question almost everywhere I asked it. When two goals look flatly opposed and no coefficient reconciles them, suspect the quantity before the number: sometimes nothing fits because the term is the wrong shape, not the wrong size. And write the dead ends down: half of this post is failed ideas, and the note on <em>why</em> each one died is the only thing that keeps you from walking back into it.</p>

<p>None of the answers were the satisfying part, though. The satisfying part was almost always the sweep that proved me wrong and pointed at where to look next.</p>]]></content><author><name>Harabi</name></author><summary type="html"><![CDATA[A blob is the least structured attack force in Screeps: a loose pack of combat creeps, no formation, that you shove at an enemy base and hope survives. No clever shape to hold, nothing to micro, or so it looks. Anyone who’s tried it knows better. Keeping a blob alive on a defended room is one of the game’s nastier movement problems, and I’d left it alone for a long time precisely because it looked too hard to be worth the trouble. What changed my mind was watching other players pull it off: the blobs droidFreak and iamgqr have been running lately were equal parts inspiration and a push to finally start.]]></summary></entry><entry><title type="html">An ROI-Driven Target Selection System in Screeps: Balancing Threat and Elimination Cost</title><link href="https://sy-harabi.github.io/An-ROI-Driven-Target-Selection-System-In-Screeps/" rel="alternate" type="text/html" title="An ROI-Driven Target Selection System in Screeps: Balancing Threat and Elimination Cost" /><published>2026-05-29T00:00:00+00:00</published><updated>2026-05-29T00:00:00+00:00</updated><id>https://sy-harabi.github.io/An-ROI-Driven-Target-Selection-System-In-Screeps</id><content type="html" xml:base="https://sy-harabi.github.io/An-ROI-Driven-Target-Selection-System-In-Screeps/"><![CDATA[<p>In Screeps, choosing which bot to attack is a critical high-level strategic decision. Common approaches to target selection vary widely: remaining entirely passive, declaring unconditional hostility toward everyone, picking targets at random, or focusing purely on the player with the highest raw hostility.</p>

<p>This post introduces an alternative system based on the principle of Return on Investment (ROI). The objective is strictly economic: minimizing the total energy cost inflicted on my colony by external threats, resolved at the lowest possible resource expenditure.</p>

<h2 id="1-infamy-quantifying-incoming-damage-into-energy">1. Infamy: Quantifying Incoming Damage into Energy</h2>

<p>To make rational comparisons between different hostile bots, all forms of harassment must be converted into a single, unified metric: <strong>Energy</strong>. The system tracks this under a property called <code class="language-plaintext highlighter-rouge">infamy</code>.</p>

<h3 id="direct-calculations">Direct Calculations</h3>

<ul>
  <li><strong>Remote Harassment:</strong> When hostile creeps invade our remote mining rooms, the system estimates the energy cost required to build the invading creeps. For non-combat scouts, this is a flat baseline of <code class="language-plaintext highlighter-rouge">100</code> energy. For combatants, it uses the exact energy cost of their body parts (e.g., ATTACK, RANGED_ATTACK, HEAL).</li>
  <li><strong>Creep Casualties:</strong> When a friendly creep is destroyed by an enemy, the infamy value is scaled by the creep’s size and remaining lifetime:
    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Infamy Added = (Body Length * Part Energy Max * Ticks to Live) / Creep Lifetime
</code></pre></div>    </div>
    <p>This ensures that losing a freshly spawned, expensive creep adds significantly more infamy than losing a creep that was about to die of old age.</p>
  </li>
</ul>

<h3 id="heuristics-for-complex-interruptions">Heuristics for Complex Interruptions</h3>

<p>Certain hostile actions cannot be easily converted into a precise energy value. For these, consistent heuristics are applied to maintain internal logical consistency:</p>
<ul>
  <li>Power bank mission disruptions</li>
  <li>Direct attacks on owned rooms (e.g., nuke launches)</li>
</ul>

<h3 id="moving-average-decay-and-locking-mechanics">Moving Average, Decay, and Locking Mechanics</h3>

<p>Because infamy is measured dynamically, the bot accumulates the total damage over a specific tracking period (<code class="language-plaintext highlighter-rouge">CREEP_LIFE_TIME</code> ticks) and merges it into the existing historical score using an Exponential Moving Average (EMA). This mathematical structure governs how threat scores persist or decline over time:</p>

<ul>
  <li><strong>The Decay Mechanism:</strong> Past infamy naturally decays as new cycles with zero hostile activity are processed.</li>
  <li><strong>The Baseline Floor:</strong> To represent geographical threat, the bot calculates a static baseline infamy score based on proximity. For every room the opponent owns (containing active spawns and towers) that is within a close range of our territory (3 rooms if they are whitelisted, 5 rooms otherwise), a large flat infamy penalty is added to their baseline. This ensures that simply having a fully developed hostile base next door maintains a high, persistent baseline threat profile in the strategic planner, even during periods of peace.</li>
  <li><strong>The Enemy Lock:</strong> Once a bot accumulates enough infamy to cross a specific threshold, it is marked as an <code class="language-plaintext highlighter-rouge">"enemy"</code>. For these players, the infamy score is clamped at the enemy threshold baseline and prevented from decaying further—<strong>provided they have successfully breached one of our established rooms (RCL 4 or higher)</strong>. This guarantees that players who have demonstrated the capability to penetrate our core defenses remain permanently flagged as threats, while minor players or those who only breached a low-level expansion outpost are allowed to decay back to neutral.</li>
</ul>

<hr />

<h2 id="2-durability-estimation-of-elimination-cost">2. Durability: Estimation of Elimination Cost</h2>

<p>While <code class="language-plaintext highlighter-rouge">infamy</code> measures the threat, <code class="language-plaintext highlighter-rouge">durability</code> estimates the cost of eliminating that threat. It answers the question: <em>How many resources must my bot expend to completely wipe all known rooms of this player?</em></p>

<p>To establish a tangible baseline, Durability is defined as the estimated wall hits (where <code class="language-plaintext highlighter-rouge">1.0</code> durability = 1,000,000 hits) required to clear the target’s rooms.</p>

<h3 id="hardware-factors">Hardware Factors</h3>

<p>Instead of summing up every single wall and rampart in the room, the bot calculates the <strong>minimum path thickness</strong> to reach critical infrastructure (spawns, towers, terminal). Using Dijkstra pathfinding on exit positions to target structures, the durability score is derived from:</p>
<ul>
  <li><strong>Minimum Path Barrier Hits:</strong> The total hit points of the thinnest layer of walls/ramparts blocking access to the core room structures.</li>
  <li><strong>Energy-to-Repair Conversion:</strong> If the target player has been seen actively repairing structures, the system assumes they will spend their stored energy on defenses. The durability is scaled up by:
    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Barrier Hits + (Stored Energy * Repair Power Constant)
</code></pre></div>    </div>
  </li>
  <li><strong>Stored Boosts:</strong> The estimated defensive capabilities are increased based on the opponent’s stored Tier 1, Tier 2, and Tier 3 combat boosts.</li>
</ul>

<h3 id="software-multipliers-intel-system">Software Multipliers (Intel System)</h3>

<p>Raw defensive structures do not tell the whole story; the opponent’s defensive code matters. The bot maintains an intel object for each player stored in <code class="language-plaintext highlighter-rouge">Memory</code>. If the opponent has been seen utilizing advanced defenses, a multiplier scales up their durability score:</p>
<ul>
  <li>Spawning dedicated rampart defenders (melee or ranged)</li>
  <li>Deploying defensive combat units (especially if utilizing boosts)</li>
</ul>

<hr />

<h2 id="3-the-target-selection-algorithm-and-score-modifiers">3. The Target Selection Algorithm and Score Modifiers</h2>

<p>With both threat (<code class="language-plaintext highlighter-rouge">infamy</code>) and elimination cost (<code class="language-plaintext highlighter-rouge">durability</code>) quantified, the strategic planner selects targets by evaluating the overall return on investment.</p>

<p>The bot calculates an evaluation score for each potential target, taking into account a distance penalty:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Score = (Durability * Distance Penalty) / Infamy
</code></pre></div></div>

<p>Because the bot uses a <strong>Min-Heap</strong> to evaluate targets, the candidate with the <strong>lowest</strong> score is prioritized. This mathematically favors players who are highly hostile (<code class="language-plaintext highlighter-rouge">infamy</code> is high), close by (<code class="language-plaintext highlighter-rouge">distance</code> is low), and cheap to wipe out (<code class="language-plaintext highlighter-rouge">durability</code> is low).</p>

<h3 id="the-distance-penalty">The Distance Penalty</h3>

<p>To prevent the bot from launching costly campaigns halfway across the world map, a logarithmic penalty is applied based on the room distance between our nearest spawn and the target’s territory. This penalty heavily prioritizes local hostiles, while scaling down the strategic priority of distant opponents to reflect the high resource costs and travel-time risks of long-range combat operations.</p>

<h3 id="priority-multipliers">Priority Multipliers</h3>

<p>To handle critical tactical situations and manage target stickiness, modifiers are applied directly to the score:</p>

<ul>
  <li><strong>Invasion Multiplier:</strong> If a player has launched an attack against us recently (<code class="language-plaintext highlighter-rouge">lastInvasion</code>), their score is halved (doubling their priority in the Min-Heap) to prioritize immediate revenge.</li>
  <li><strong>Target Stickiness (Hysteresis):</strong> To prevent the bot from frequently switching war targets due to minor updates in structural data or infamy decay, the active target has its score halved. This introduces stickiness, ensuring the bot commits to a war target until a significant shift in the ROI balance occurs.</li>
</ul>

<hr />

<h2 id="conclusion">Conclusion</h2>

<p>This system does not offer perfect mathematical precision. The unpredictable variables of combat code and hidden player assets make strict calculations <strong>exceptionally difficult</strong>. However, by framing target selection as a resource allocation problem—weighing energy lost against path-based deployment costs—the bot can manage automated long-term conflicts with reasonable efficiency and zero human intervention.</p>]]></content><author><name>Harabi</name></author><summary type="html"><![CDATA[In Screeps, choosing which bot to attack is a critical high-level strategic decision. Common approaches to target selection vary widely: remaining entirely passive, declaring unconditional hostility toward everyone, picking targets at random, or focusing purely on the player with the highest raw hostility.]]></summary></entry><entry><title type="html">An Emergent Mission Architecture for Screeps</title><link href="https://sy-harabi.github.io/emergent-mission-architecture/" rel="alternate" type="text/html" title="An Emergent Mission Architecture for Screeps" /><published>2026-01-09T00:00:00+00:00</published><updated>2026-01-09T00:00:00+00:00</updated><id>https://sy-harabi.github.io/emergent-mission-architecture</id><content type="html" xml:base="https://sy-harabi.github.io/emergent-mission-architecture/"><![CDATA[<h1 id="an-emergent-mission-architecture-for-screeps">An Emergent Mission Architecture for Screeps</h1>

<p><em>How I structure my bot to handle strategy, warfare, and large-scale decisions without drowning in micro-management.</em></p>

<hr />

<h2 id="why-i-rewrote-my-bot">Why I Rewrote My Bot</h2>

<p>Like many Screeps players, my first bot grew organically: creeps made local decisions, special cases piled up, and every new feature felt harder than the last. Combat logic was especially painful—tactical decisions leaked everywhere, and it was difficult to answer simple questions like:</p>

<blockquote>
  <p><em>Is this war actually working?</em></p>
</blockquote>

<p>When I rewrote my bot, I committed to two guiding ideas:</p>

<ol>
  <li><strong>Top-down control where it matters</strong> Creeps shouldn’t decide <em>why</em> they act. Higher-level systems should.</li>
  <li><strong>Natural task decomposition</strong> Large goals should break down into smaller ones without relying on a rigid planner.</li>
</ol>

<p>The result is a <strong>mission-based architecture</strong>, where Managers act as the brains of the empire and Missions act as the specialized tools they deploy.</p>

<hr />

<h2 id="high-level-structure-managers-as-the-highest-level">High-Level Structure: Managers as the Highest Level</h2>

<p>In this architecture, <strong>Managers are the highest-level actors</strong>. They are persistent, “always-on” entities that bridge the gap between global state and specific action.</p>

<p>Managers serve two primary functions:</p>

<ol>
  <li><strong>Maintenance:</strong> They handle repetitive, baseline responsibilities (e.g., the Room Manager ensures the controller doesn’t downgrade).</li>
  <li><strong>Deployment:</strong> They act as the “commanders” who decide when the situation requires a specialized Mission.</li>
</ol>

<table>
  <thead>
    <tr>
      <th style="text-align: left">Manager</th>
      <th style="text-align: left">Repetitive Responsibility</th>
      <th style="text-align: left">Mission Deployment Example</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td style="text-align: left"><strong>Room Manager</strong></td>
      <td style="text-align: left">Local infrastructure, mining &amp; upgrading</td>
      <td style="text-align: left"><strong>Remote Defense Mission</strong></td>
    </tr>
    <tr>
      <td style="text-align: left"><strong>Combat Manager</strong></td>
      <td style="text-align: left">Global threat assessment</td>
      <td style="text-align: left"><strong>Total War Mission</strong></td>
    </tr>
    <tr>
      <td style="text-align: left"><strong>Expansion Manager</strong></td>
      <td style="text-align: left">Room scouting &amp; planning</td>
      <td style="text-align: left"><strong>Claim Mission</strong></td>
    </tr>
  </tbody>
</table>

<hr />

<h2 id="missions-goal-oriented-execution">Missions: Goal-Oriented Execution</h2>

<p>While Managers are the <strong>“who,”</strong> Missions are the <strong>“what.”</strong> A mission represents a concrete objective with a clear success or failure condition.</p>

<p>A useful mental model is chess:</p>

<ul>
  <li>The <strong>Manager</strong> is the chess player.</li>
  <li>The <strong>Mission</strong> is the specific opening or strategy being executed.</li>
  <li><strong>Creeps</strong> are the pieces.</li>
</ul>

<h3 id="recursive-decomposition-the-mission-chain">Recursive Decomposition (The Mission Chain)</h3>

<p>Missions are most powerful when they spawn sub-missions. This allows for complex behavior to emerge from simple, nested logic. A high-level mission defines the <em>intent</em>, while its children handle the <em>tactics</em>.</p>

<p><strong>Example Mission Chain:</strong>
<code class="language-plaintext highlighter-rouge">Total War</code> -&gt; <code class="language-plaintext highlighter-rouge">Siege</code> -&gt; <code class="language-plaintext highlighter-rouge">Quad</code></p>

<ol>
  <li><strong>Total War (deployed by Combat Manager):</strong> Tracks the overall economic drain on the enemy and decides which rooms to pressure.</li>
  <li><strong>Siege:</strong> Focuses on a specific room, managing staging points and wall-breaking progress.</li>
  <li><strong>Quad:</strong> A tactical unit mission that spawns and handles four creeps in formation to execute the siege’s goals.</li>
</ol>

<hr />

<h2 id="how-missions-communicate">How Missions Communicate</h2>

<p>All coordination happens through <strong>mission memory</strong>. The guiding rule is simple:</p>

<blockquote>
  <p><strong>A mission may read any mission’s memory, but may only write to its own.</strong></p>
</blockquote>

<h3 id="example-decision-flow">Example Decision Flow</h3>

<ol>
  <li>A <strong>Quad Mission</strong> loses a creep and records the loss in its memory.</li>
  <li>A <strong>Siege Mission</strong> observes the creep loss flag in its child Quad’s memory and adapts future squad composition.</li>
  <li>Continued poor results cause the siege to stagnate.</li>
  <li>The <strong>Total War Mission</strong> observes the lack of progress across multiple Sieges and decides to pivot the empire’s resources elsewhere.</li>
</ol>

<p>No explicit reporting or signaling is required—coordination emerges from shared observation of state.</p>

<hr />

<h2 id="mission-memory-structure">Mission Memory Structure</h2>

<p>All missions are stored in a double-layered structure: <code class="language-plaintext highlighter-rouge">Memory.missions[type][id]</code>. This allows for fast lookups and easy iteration.</p>

<h3 id="example">Example</h3>

<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">Memory</span><span class="p">.</span><span class="nx">missions</span><span class="p">[</span><span class="dl">"</span><span class="s2">siege</span><span class="dl">"</span><span class="p">][</span><span class="dl">"</span><span class="s2">W1N1</span><span class="dl">"</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span>
  <span class="na">type</span><span class="p">:</span> <span class="dl">"</span><span class="s2">siege</span><span class="dl">"</span><span class="p">,</span>
  <span class="na">id</span><span class="p">:</span> <span class="dl">"</span><span class="s2">W1N1</span><span class="dl">"</span><span class="p">,</span>
  <span class="na">targetRoomName</span><span class="p">:</span> <span class="dl">"</span><span class="s2">W1N1</span><span class="dl">"</span><span class="p">,</span>
  <span class="na">childMissions</span><span class="p">:</span> <span class="p">[</span>
    <span class="p">{</span> <span class="na">type</span><span class="p">:</span> <span class="dl">"</span><span class="s2">quad</span><span class="dl">"</span><span class="p">,</span> <span class="na">id</span><span class="p">:</span> <span class="dl">"</span><span class="s2">W1N1_17253400</span><span class="dl">"</span> <span class="p">}</span>
  <span class="p">],</span>
  <span class="na">status</span><span class="p">:</span> <span class="p">{</span>
    <span class="na">isEffective</span><span class="p">:</span> <span class="kc">false</span><span class="p">,</span>
    <span class="na">netDamage</span><span class="p">:</span> <span class="o">-</span><span class="mi">1500</span>
  <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<hr />

<h2 id="the-execution-loop">The Execution Loop</h2>

<p>The daily life of the bot follows a predictable cycle, moving from high-level observation down to individual action:</p>

<ol>
  <li><strong>Analyze:</strong> <strong>Managers</strong> maintain the baseline bot functions and scan the world state to identify strategic needs.</li>
  <li><strong>Deploy:</strong> Based on the analysis, Managers spawn or update <strong>Missions</strong>. For example, the Combat Manager may deploy a <code class="language-plaintext highlighter-rouge">Total War</code> mission if a player is being mean. The <code class="language-plaintext highlighter-rouge">Total War</code> mission then recursively deploys several <code class="language-plaintext highlighter-rouge">Siege</code> missions toward that player’s rooms.</li>
  <li><strong>Resolve:</strong> High-level missions read the memory of their child missions to evaluate progress. For example, a <code class="language-plaintext highlighter-rouge">Siege</code> mission checks its <code class="language-plaintext highlighter-rouge">Quad</code> mission’s results to see if the room’s defenses are cracking.</li>
  <li><strong>Act:</strong> Missions update their own state and issue direct orders to their assigned <strong>Creeps</strong>. In this phase, a <code class="language-plaintext highlighter-rouge">Quad</code> mission control creeps and reports how much damage it is dealing, feeding the loop for the next decision making.</li>
</ol>

<p>This sequence ensures that <strong>execution remains local</strong>, while <strong>evaluation remains strategic</strong>.</p>]]></content><author><name>Harabi</name></author><summary type="html"><![CDATA[An Emergent Mission Architecture for Screeps]]></summary></entry><entry><title type="html">How My Bot Boosts a Creep – A Detailed Explanation for Beginners</title><link href="https://sy-harabi.github.io/How-My-Bot_Boosts-A-Creep/" rel="alternate" type="text/html" title="How My Bot Boosts a Creep – A Detailed Explanation for Beginners" /><published>2025-10-18T00:00:00+00:00</published><updated>2025-10-18T00:00:00+00:00</updated><id>https://sy-harabi.github.io/How-My-Bot_Boosts-A-Creep</id><content type="html" xml:base="https://sy-harabi.github.io/How-My-Bot_Boosts-A-Creep/"><![CDATA[<h1 id="how-my-bot-boosts-a-creep--a-detailed-explanation-for-beginners">How My Bot Boosts a Creep – A Detailed Explanation for Beginners</h1>

<p>Boosting is one of the most important steps to becoming a veteran <strong>Screeps</strong> player. You’ll eventually need boosted creeps to attack high-level rooms or defend against them — and once you can boost efficiently, you can also use those boosted creeps to accelerate your economy.</p>

<p>In this post, I’ll explain how my bot handles boosting from start to finish — including how it requests boosts, prepares resources, and executes the actual boosting process.</p>

<p><img width="967" height="628" alt="image" src="https://github.com/user-attachments/assets/1874f640-467e-48ec-8183-1a08bec4d030" /></p>

<hr />

<h2 id="1-boost-request">1. Boost Request</h2>

<p>Whenever my bot requests a creep to be spawned and boosted, it also creates a boost request object in the room’s memory:</p>

<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">room</span><span class="p">.</span><span class="nx">memory</span><span class="p">.</span><span class="nx">boostRequests</span> <span class="o">=</span> <span class="p">[</span>
  <span class="p">{</span>
    <span class="na">creepName</span><span class="p">:</span> <span class="dl">"</span><span class="s2">Attacker_123</span><span class="dl">"</span><span class="p">,</span>
    <span class="na">requestedAt</span><span class="p">:</span> <span class="nx">Game</span><span class="p">.</span><span class="nx">time</span><span class="p">,</span>
    <span class="na">resources</span><span class="p">:</span> <span class="p">{</span>
      <span class="na">XKH2O</span><span class="p">:</span> <span class="mi">660</span><span class="p">,</span> <span class="c1">// Resource type and amount</span>
      <span class="na">XLHO2</span><span class="p">:</span> <span class="mi">540</span><span class="p">,</span>
      <span class="na">XZHO2</span><span class="p">:</span> <span class="mi">300</span><span class="p">,</span>
    <span class="p">}</span>
  <span class="p">},</span>
  <span class="p">...</span>
<span class="p">];</span>
</code></pre></div></div>

<p>Each <code class="language-plaintext highlighter-rouge">boostRequest</code> contains:</p>

<ol>
  <li>The creep name to be boosted.</li>
  <li>The <code class="language-plaintext highlighter-rouge">Game.time</code> when the request was made.</li>
  <li>The resource types and required amounts for each boost.</li>
</ol>

<p>While the creep is being spawned, another creep in the same room starts preparing everything needed for the boost.</p>

<hr />

<h2 id="2-boosting-process-overview">2. Boosting Process Overview</h2>

<p>My bot processes boost requests from <strong>oldest to newest</strong>.
Each request goes through three phases: <strong>Gather → Prepare → Boost</strong>.</p>

<hr />

<h3 id="-gather-phase">🧺 Gather Phase</h3>

<ol>
  <li>
    <p><strong>Check resources:</strong>
Make sure all the required minerals and energy are available to perform the boost.</p>
  </li>
  <li>
    <p><strong>Import if missing:</strong>
If some resources are missing, request them via the room’s terminal from other rooms.</p>
  </li>
  <li>
    <p><strong>Switch to prepare phase:</strong>
Once all resources are ready, the system transitions to the next step.</p>
  </li>
</ol>

<hr />

<h3 id="️-prepare-phase">⚗️ Prepare Phase</h3>

<ol>
  <li>
    <p><strong>Stop lab reactions:</strong>
If the labs are currently running reactions, stop them first.</p>
  </li>
  <li>
    <p><strong>Courier transfers:</strong>
Courier creep transport the correct resources to the appropriate labs.</p>
  </li>
  <li>
    <p><strong>Batch preparation:</strong>
If there are multiple boost requests, try to prepare all of them — again from the oldest to the newest.</p>
  </li>
  <li>
    <p><strong>Ready check:</strong>
If the target creep has finished spawning and everything is prepared, the bot switches to the boost phase.</p>
  </li>
</ol>

<hr />

<h3 id="-boost-phase">⚡ Boost Phase</h3>

<ol>
  <li>
    <p><strong>Move the creep:</strong>
The target creep moves to the prepared labs.</p>
  </li>
  <li>
    <p><strong>Perform boosting:</strong>
Each lab boosts the creep until the entire process completes.</p>
  </li>
</ol>

<hr />

<h2 id="3-tips-and-safety-checks">3. Tips and Safety Checks</h2>

<p>Here are a few lessons I learned the hard way:</p>

<ol>
  <li>📌 <strong>Create boost request only when spawn returend OK</strong> to avoid duplication.</li>
  <li>✅ <strong>Check if the target creep is alive</strong> and waiting before starting the boost phase.</li>
  <li>⚗️ <strong>Select labs wisely</strong> — prefer labs that already contain the required minerals or that are being used as reaction labs.</li>
  <li>⚡ <strong>Don’t forget energy</strong> — labs need energy as well as minerals to perform the boost!</li>
  <li>🔄 <strong>Handle failures</strong> — if something goes wrong, return to the gather or prepare phase instead of getting stuck.</li>
  <li>🤝 <strong>For duos or quads</strong>, make the creeps that spawn first get renewed until all teammates are ready.</li>
  <li>⏳ <strong>Timeouts matter</strong> — if a boost request makes no progress after a certain time, give up and move to the next one.</li>
</ol>

<hr />

<h2 id="4-final-thoughts">4. Final Thoughts</h2>

<p>So that’s how my bot handles boosting — a full cycle from request to completion, with recovery in case of failure.</p>

<p>Once you’ve built a stable boosting pipeline, you’ll unlock a huge new layer of Screeps gameplay.
Try spawning a boosted singleton with <strong>tough</strong>, <strong>ranged attack</strong> and <strong>heal</strong> boosts, and send it to your neighbor — it’s a great way to test your system (and maybe start a small war 😄).</p>]]></content><author><name>Harabi</name></author><summary type="html"><![CDATA[How My Bot Boosts a Creep – A Detailed Explanation for Beginners]]></summary></entry><entry><title type="html">Logistics – How My Bot Distributes Resources Across Rooms</title><link href="https://sy-harabi.github.io/Logistics-How-My-Bot-Distributes-Resources-Across-Rooms/" rel="alternate" type="text/html" title="Logistics – How My Bot Distributes Resources Across Rooms" /><published>2025-09-04T00:00:00+00:00</published><updated>2025-09-04T00:00:00+00:00</updated><id>https://sy-harabi.github.io/Logistics-How-My-Bot-Distributes-Resources-Across-Rooms</id><content type="html" xml:base="https://sy-harabi.github.io/Logistics-How-My-Bot-Distributes-Resources-Across-Rooms/"><![CDATA[<h1 id="logistics--how-my-bot-distributes-resources-across-rooms">Logistics – How My Bot Distributes Resources Across Rooms</h1>

<p>Today, I want to cover <strong>logistics</strong>. Many players manage logistics using a <strong>per-room method</strong>: they try to distribute resources equally to all rooms.<br />
While simple, I think this approach creates inefficiencies — unnecessary <code class="language-plaintext highlighter-rouge">terminal.send</code> operations, resource ping-pong between rooms, and wasted CPU.</p>

<p>Instead, I chose to treat logistics as an <strong>empire-wide (bot-level) system</strong>. My guiding principles are:</p>

<ol>
  <li><strong>Always think at bot-level if possible.</strong></li>
  <li><strong>Do not send resources unless necessary.</strong></li>
</ol>

<p>Here’s how I currently handle logistics.</p>

<hr />

<h2 id="managing-surplus-and-shortage-of-raw-minerals">Managing Surplus and Shortage of Raw Minerals</h2>

<p>My bot sets a <code class="language-plaintext highlighter-rouge">threshold_per_room</code> for each mineral. For the whole empire, this becomes:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>threshold = threshold_per_room * myRooms.length
</code></pre></div></div>

<ul>
  <li>
    <p><strong>Surplus case:</strong><br />
If a mineral amount is <em>far above</em> this threshold, the bot sells it.<br />
By the pigeonhole principle, some rooms must be holding more than <code class="language-plaintext highlighter-rouge">threshold_per_room</code>. Those rooms are chosen to sell the resource.</p>
  </li>
  <li>
    <p><strong>Shortage case:</strong><br />
If a mineral amount is <em>far below</em> the threshold, the bot buys it.<br />
By the same logic, some rooms must be holding less than <code class="language-plaintext highlighter-rouge">threshold_per_room</code>. Those rooms buy the resource.</p>
  </li>
</ul>

<p>This ensures that buy/sell actions naturally balance the empire without constant redistribution.</p>

<hr />

<h2 id="choosing-lab-process-targets">Choosing Lab Process Targets</h2>

<p>When labs are idle and looking for a new objective, my bot selects the boost with the <strong>lowest ratio</strong>:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>(current amount) / (desired amount)
</code></pre></div></div>

<p>across the entire empire, but only among boosts where the bot has enough ingredients available.</p>

<ul>
  <li><strong>Empire-wide view:</strong><br />
The <code class="language-plaintext highlighter-rouge">current amount</code> includes both what we already have <strong>and</strong> what is currently being produced in other rooms.<br />
This prevents multiple rooms from redundantly producing the same boost.</li>
</ul>

<hr />

<h2 id="handling-resource-overflow">Handling Resource Overflow</h2>

<p>Because my bot doesn’t equalize resources between rooms, some rooms occasionally overflow with resources.<br />
When that happens:</p>

<ol>
  <li>If <strong>energy stockpile is above a certain threshold</strong>, push out energy.</li>
  <li>Otherwise, push out whichever resource the room has the most of(Other than energy), to the <strong>nearest room with enough space</strong>.</li>
</ol>

<p>This keeps rooms from stalling due to full storage.</p>

<hr />

<h2 id="handling-resource-requests">Handling Resource Requests</h2>

<p>There are several situations where a room may require resources it doesn’t currently have.<br />
In such cases, my bot allows targeted <code class="language-plaintext highlighter-rouge">terminal.send()</code> operations. The guiding rule is: <strong>only send when a room explicitly needs something.</strong></p>

<h3 id="typical-scenarios">Typical Scenarios</h3>

<ol>
  <li><strong>Lab ingredient requests:</strong>
    <ul>
      <li>When a room wants to make a boost but lacks ingredients.</li>
      <li>Other rooms must have the ingredients (since the target was chosen with that assumption).</li>
    </ul>
  </li>
  <li><strong>Creep boost preparation:</strong>
    <ul>
      <li>When a room wants to boost a creep but lacks the boosts.</li>
      <li>It requests them from rooms that have the boosts.</li>
      <li>Since a full creep spawn takes ~150 ticks, usually there’s plenty of time to prepare.</li>
    </ul>
  </li>
  <li><strong>Funneling for RCL growth:</strong>
    <ul>
      <li>Extra energy is sent to the room where I want to <strong>raise the RCL as quickly as possible</strong>.</li>
    </ul>
  </li>
  <li><strong>Low energy recovery:</strong>
    <ul>
      <li>When a room’s energy drops too low to sustain operations, other rooms send emergency energy.</li>
    </ul>
  </li>
  <li><strong>Power processing:</strong>
    <ul>
      <li>When the bot wants to process power, usually some rooms hold most of the power (often close to highways where power banks occur).</li>
      <li>In this case, the bot distributes power to other rooms so that multiple rooms can process it simultaneously, increasing the speed.</li>
    </ul>
  </li>
  <li><strong>Nuker preparation:</strong>
    <ul>
      <li>When a room wants to <strong>fill a nuker</strong> and needs ghodium, it requests it from other rooms.</li>
    </ul>
  </li>
</ol>

<hr />

<p>In all of these scenarios, the system selects the <strong>closest suitable room</strong> to minimize transfer cost and avoid resource ping-pong.</p>

<hr />

<h2 id="closing-thoughts">Closing Thoughts</h2>

<p>By shifting logistics to the <strong>bot-level</strong>, I avoid constant rebalancing and keep resource movement purposeful.<br />
This approach reduces CPU overhead, prevents resource ping-pong, and ensures that logistics always serve empire-wide goals rather than per-room symmetry.</p>]]></content><author><name>Harabi</name></author><summary type="html"><![CDATA[Logistics – How My Bot Distributes Resources Across Rooms]]></summary></entry><entry><title type="html">Quad Tutorial: Attack the Level 1 Stronghold!</title><link href="https://sy-harabi.github.io/Quad-Tutorial/" rel="alternate" type="text/html" title="Quad Tutorial: Attack the Level 1 Stronghold!" /><published>2025-07-24T00:00:00+00:00</published><updated>2025-07-24T00:00:00+00:00</updated><id>https://sy-harabi.github.io/Quad-Tutorial</id><content type="html" xml:base="https://sy-harabi.github.io/Quad-Tutorial/"><![CDATA[<h1 id="quad-tutorial-attack-the-level-1-stronghold">Quad Tutorial: Attack the Level 1 Stronghold!</h1>

<p>In the <a href="https://sy-harabi.github.io/Quad-Movement-Basics/">last post</a>, we talked about basic quad movement. You’re probably eager to attack an enemy room with your quad—but before that, there are some important things to learn.</p>

<p>Today, we’ll use a Level 1 Stronghold as an example to show how quads can be used in real combat. Strongholds are the bases of NPC Invaders that spawn in the central rooms of each sector. They’re great for testing and improving your attack code: they appear regularly, exist in every sector, and reward you when destroyed.</p>

<p>Once a stronghold is destroyed, Invaders and lesser Invader Cores stop spawning in that sector until the next stronghold spawns (around 75,000 ticks later). So even a low-level stronghold is worth attacking—especially as a beginner practice target.</p>

<p>Let’s dive in!</p>

<ul>
  <li>This is a tutorial, so I’ll keep things as simple and easy to follow as possible. Once you understand the basics, you can add more features and refine your logic. I’ll post more tips about using quads soon—stay tuned!</li>
</ul>

<hr />

<h2 id="-what-to-spawn">🚧 What to Spawn</h2>

<p>A Level 1 Stronghold has only <strong>one tower</strong> and <strong>no creeps</strong>, but that tower can deal up to <strong>600 damage per tick</strong> if you’re close enough. Since each <code class="language-plaintext highlighter-rouge">HEAL</code> part can heal <strong>12 hits per tick</strong>, you need at least <strong>50 HEAL parts</strong> in total just to survive.</p>

<p>To be safe, we’ll use <strong>60 HEAL parts</strong> across the quad. That means each creep should have:</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">10 RANGED_ATTACK</code></li>
  <li><code class="language-plaintext highlighter-rouge">25 MOVE</code></li>
  <li><code class="language-plaintext highlighter-rouge">15 HEAL</code></li>
</ul>

<p>That gives your quad enough healing, mobility, and firepower to survive and take down the stronghold.</p>

<ul>
  <li>Please note: This is not an optimal strategy for destroying a stronghold—I’m simply using it for practice.</li>
</ul>

<hr />

<h2 id="overview-of-the-logic">Overview of the Logic</h2>

<p>Here’s the general structure of our quad attack logic:</p>

<ol>
  <li>Each creep attacks nearby structures or enemies.</li>
  <li>Creeps heal each other effectively.</li>
  <li>Creeps move as a quad:
    <ul>
      <li>A. If in danger, retreat.</li>
      <li>B. If safe, find a target and move toward it.</li>
    </ul>
  </li>
</ol>

<p>Sounds simple, right? Let’s go through each part in detail.</p>

<hr />

<h2 id="️-attack-logic">🗡️ Attack Logic</h2>

<p>To keep it simple for now, I’ll just make each creep attack any enemy or structure within range 3. If you have your own better logic, use that!</p>

<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">for</span> <span class="p">(</span><span class="kd">const</span> <span class="nx">creep</span> <span class="k">of</span> <span class="nx">creeps</span><span class="p">)</span> <span class="p">{</span>
    <span class="kd">const</span> <span class="nx">targets</span> <span class="o">=</span> <span class="nx">creep</span><span class="p">.</span><span class="nx">pos</span><span class="p">.</span><span class="nx">findInRange</span><span class="p">(</span><span class="nx">FIND_HOSTILE_CREEPS</span><span class="p">,</span> <span class="mi">3</span><span class="p">)</span>
        <span class="p">.</span><span class="nx">concat</span><span class="p">(</span><span class="nx">creep</span><span class="p">.</span><span class="nx">pos</span><span class="p">.</span><span class="nx">findInRange</span><span class="p">(</span><span class="nx">FIND_HOSTILE_STRUCTURES</span><span class="p">,</span> <span class="mi">3</span><span class="p">));</span>

    <span class="k">if</span> <span class="p">(</span><span class="nx">targets</span><span class="p">.</span><span class="nx">length</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
        <span class="nx">creep</span><span class="p">.</span><span class="nx">rangedAttack</span><span class="p">(</span><span class="nx">targets</span><span class="p">[</span><span class="mi">0</span><span class="p">]);</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<hr />

<h2 id="️-getting-damage">🛡️ Getting Damage</h2>

<p>Before handling healing, we need to know how much damage each creep is expected to take.</p>

<ol>
  <li>Scan all enemy towers.</li>
  <li>For each tile, calculate and store the total incoming damage from towers.</li>
</ol>

<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">function</span> <span class="nx">getDamageAt</span><span class="p">(</span><span class="nx">room</span><span class="p">,</span> <span class="nx">pos</span><span class="p">)</span> <span class="p">{</span>

    <span class="kd">const</span> <span class="nx">towers</span> <span class="o">=</span> <span class="nx">room</span><span class="p">.</span><span class="nx">find</span><span class="p">(</span><span class="nx">FIND_HOSTILE_STRUCTURES</span><span class="p">,</span> <span class="p">{</span>
        <span class="na">filter</span><span class="p">:</span> <span class="nx">s</span> <span class="o">=&gt;</span> <span class="nx">s</span><span class="p">.</span><span class="nx">structureType</span> <span class="o">===</span> <span class="nx">STRUCTURE_TOWER</span>
    <span class="p">});</span>

    <span class="kd">let</span> <span class="nx">damage</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>

    <span class="k">for</span> <span class="p">(</span><span class="kd">const</span> <span class="nx">tower</span> <span class="k">of</span> <span class="nx">towers</span><span class="p">)</span> <span class="p">{</span>
        <span class="kd">const</span> <span class="nx">dist</span> <span class="o">=</span> <span class="nx">tower</span><span class="p">.</span><span class="nx">pos</span><span class="p">.</span><span class="nx">getRangeTo</span><span class="p">(</span><span class="nx">x</span><span class="p">,</span> <span class="nx">y</span><span class="p">);</span>
        <span class="nx">damage</span> <span class="o">+=</span> <span class="nx">getTowerDamage</span><span class="p">(</span><span class="nx">dist</span><span class="p">)</span>
    <span class="p">}</span>

    <span class="k">return</span> <span class="nx">damage</span><span class="p">;</span>
<span class="p">}</span>

<span class="kd">function</span> <span class="nx">getTowerDamage</span><span class="p">(</span><span class="nx">range</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">if</span> <span class="p">(</span><span class="nx">range</span> <span class="o">&lt;=</span> <span class="nx">TOWER_OPTIMAL_RANGE</span><span class="p">)</span> <span class="k">return</span> <span class="nx">TOWER_POWER_ATTACK</span>

    <span class="k">if</span> <span class="p">(</span><span class="nx">range</span> <span class="o">&gt;</span> <span class="nx">TOWER_FALLOFF_RANGE</span><span class="p">)</span> <span class="p">{</span>
        <span class="nx">range</span> <span class="o">=</span> <span class="nx">TOWER_FALLOFF_RANGE</span>
    <span class="p">}</span>

    <span class="k">return</span> <span class="nx">TOWER_POWER_ATTACK</span> <span class="o">*</span> <span class="nx">TOWER_FALLOFF</span> <span class="o">*</span> <span class="p">(</span><span class="nx">range</span> <span class="o">-</span> <span class="nx">TOWER_OPTIMAL_RANGE</span><span class="p">)</span> <span class="o">/</span> <span class="p">(</span><span class="nx">TOWER_FALLOF_RANGE</span> <span class="o">-</span> <span class="nx">TOWER_OPTIMAL_RANGE</span><span class="p">)</span>
<span class="p">}</span>
</code></pre></div></div>

<hr />

<h2 id="️-heal-logic">❤️ Heal Logic</h2>

<p>There are many healing strategies, but I recommend a simple one that <strong>maximizes the lowest expected health</strong> among your creeps:</p>

<ol>
  <li>For each creep, calculate <code class="language-plaintext highlighter-rouge">expectedHits = hits - incomingDamage</code></li>
  <li>Each creep should heal the friendly creep with the lowest expected hits.</li>
  <li>After healing, update that creep’s expected hits by adding the heal amount.</li>
</ol>

<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">function</span> <span class="nx">healCreeps</span><span class="p">(</span><span class="nx">room</span><span class="p">,</span> <span class="nx">creeps</span><span class="p">)</span> <span class="p">{</span>
    <span class="kd">const</span> <span class="nx">expectedHits</span> <span class="o">=</span> <span class="p">{};</span>

    <span class="k">for</span> <span class="p">(</span><span class="kd">const</span> <span class="nx">creep</span> <span class="k">of</span> <span class="nx">creeps</span><span class="p">)</span> <span class="p">{</span>
        <span class="kd">const</span> <span class="nx">dmg</span> <span class="o">=</span> <span class="nx">getDamageAt</span><span class="p">(</span><span class="nx">room</span><span class="p">,</span> <span class="nx">creep</span><span class="p">.</span><span class="nx">pos</span><span class="p">)</span> <span class="o">||</span> <span class="mi">0</span><span class="p">;</span>
        <span class="nx">expectedHits</span><span class="p">[</span><span class="nx">creep</span><span class="p">.</span><span class="nx">name</span><span class="p">]</span> <span class="o">=</span> <span class="nx">creep</span><span class="p">.</span><span class="nx">hits</span> <span class="o">-</span> <span class="nx">dmg</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="k">for</span> <span class="p">(</span><span class="kd">const</span> <span class="nx">healer</span> <span class="k">of</span> <span class="nx">creeps</span><span class="p">)</span> <span class="p">{</span>
        <span class="kd">let</span> <span class="nx">target</span> <span class="o">=</span> <span class="kc">null</span><span class="p">;</span>
        <span class="kd">let</span> <span class="nx">minExpected</span> <span class="o">=</span> <span class="kc">Infinity</span><span class="p">;</span>

        <span class="k">for</span> <span class="p">(</span><span class="kd">const</span> <span class="nx">other</span> <span class="k">of</span> <span class="nx">creeps</span><span class="p">)</span> <span class="p">{</span>
            <span class="k">if</span> <span class="p">(</span><span class="nx">expectedHits</span><span class="p">[</span><span class="nx">other</span><span class="p">.</span><span class="nx">name</span><span class="p">]</span> <span class="o">&lt;</span> <span class="nx">minExpected</span><span class="p">)</span> <span class="p">{</span>
                <span class="nx">minExpected</span> <span class="o">=</span> <span class="nx">expectedHits</span><span class="p">[</span><span class="nx">other</span><span class="p">.</span><span class="nx">name</span><span class="p">];</span>
                <span class="nx">target</span> <span class="o">=</span> <span class="nx">other</span><span class="p">;</span>
            <span class="p">}</span>
        <span class="p">}</span>

        <span class="k">if</span> <span class="p">(</span><span class="nx">target</span><span class="p">)</span> <span class="p">{</span>
            <span class="nx">healer</span><span class="p">.</span><span class="nx">heal</span><span class="p">(</span><span class="nx">target</span><span class="p">);</span>
            <span class="nx">expectedHits</span><span class="p">[</span><span class="nx">target</span><span class="p">.</span><span class="nx">name</span><span class="p">]</span> <span class="o">+=</span> <span class="nx">creep</span><span class="p">.</span><span class="nx">getActiveBodyparts</span><span class="p">(</span><span class="nx">HEAL</span><span class="p">)</span> <span class="o">*</span> <span class="nx">HEAL_POWER</span><span class="p">;</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<hr />

<h2 id="-movement-logic">🧭 Movement Logic</h2>

<h3 id="1-danger-detection">1. Danger Detection</h3>

<p>Before moving toward your target (usually the <code class="language-plaintext highlighter-rouge">invaderCore</code>), check whether the quad is in danger:</p>

<ul>
  <li>Use the damage map.</li>
  <li>Compare each creep’s expected damage to the total healing your quad can provide.</li>
  <li>If any creep is expected to take more damage than can be healed, <strong>retreat</strong>.</li>
</ul>

<p>A simple retreat logic:</p>
<ul>
  <li>Remember which direction you entered the room from. If in danger, move back to that exit.</li>
</ul>

<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">function</span> <span class="nx">shouldRetreat</span><span class="p">(</span><span class="nx">room</span><span class="p">,</span> <span class="nx">creeps</span><span class="p">,</span> <span class="nx">totalHealPower</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">for</span> <span class="p">(</span><span class="kd">const</span> <span class="nx">creep</span> <span class="k">of</span> <span class="nx">creeps</span><span class="p">)</span> <span class="p">{</span>
        <span class="kd">const</span> <span class="nx">damage</span> <span class="o">=</span> <span class="nx">getDamageAt</span><span class="p">(</span><span class="nx">room</span><span class="p">,</span> <span class="nx">creep</span><span class="p">.</span><span class="nx">pos</span><span class="p">)</span> <span class="o">||</span> <span class="mi">0</span><span class="p">;</span>
        <span class="k">if</span> <span class="p">(</span><span class="nx">damage</span> <span class="o">&gt;</span> <span class="nx">totalHealPower</span><span class="p">)</span> <span class="p">{</span>
            <span class="k">return</span> <span class="kc">true</span><span class="p">;</span>
        <span class="p">}</span>
    <span class="p">}</span>
    <span class="k">return</span> <span class="kc">false</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<hr />

<h3 id="2-obstacle-map">2. Obstacle Map</h3>

<p>To plan movement, we need an <strong>obstacle map</strong>, which shows how hard it is to destroy the obstacles on each tile.</p>

<p>Here’s how to build it:</p>

<ol>
  <li>First, scan <strong>all structures in the room</strong> to find the maximum hits among them. We’ll call this <code class="language-plaintext highlighter-rouge">maxHits</code>.</li>
  <li>Choose a maximum cost value (e.g. <code class="language-plaintext highlighter-rouge">100</code>) and compute <code class="language-plaintext highlighter-rouge">unitHits = Math.ceil(maxHits / 100)</code></li>
  <li>For each tile in the room:
    <ul>
      <li>Use <code class="language-plaintext highlighter-rouge">room.lookForAt(LOOK_STRUCTURES, x, y)</code> to get all structures on that tile.</li>
      <li>Sum up their hit points.</li>
      <li>Compute <code class="language-plaintext highlighter-rouge">cost = Math.min(100, Math.ceil(hitsSum / unitHits))</code></li>
      <li>Store that value in a <code class="language-plaintext highlighter-rouge">CostMatrix</code>.</li>
    </ul>
  </li>
</ol>

<p>Here’s the example code:</p>

<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">function</span> <span class="nx">getObstacleMap</span><span class="p">(</span><span class="nx">room</span><span class="p">)</span> <span class="p">{</span>
    <span class="kd">const</span> <span class="nx">costMatrix</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">PathFinder</span><span class="p">.</span><span class="nx">CostMatrix</span><span class="p">();</span>
    <span class="kd">let</span> <span class="nx">maxHits</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>

    <span class="c1">// Step 1: Find maxHits</span>
    <span class="kd">const</span> <span class="nx">allStructures</span> <span class="o">=</span> <span class="nx">room</span><span class="p">.</span><span class="nx">find</span><span class="p">(</span><span class="nx">FIND_STRUCTURES</span><span class="p">);</span>
    <span class="k">for</span> <span class="p">(</span><span class="kd">const</span> <span class="nx">s</span> <span class="k">of</span> <span class="nx">allStructures</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">if</span> <span class="p">(</span><span class="nx">s</span><span class="p">.</span><span class="nx">hits</span> <span class="o">&amp;&amp;</span> <span class="nx">s</span><span class="p">.</span><span class="nx">hits</span> <span class="o">&gt;</span> <span class="nx">maxHits</span><span class="p">)</span> <span class="p">{</span>
            <span class="nx">maxHits</span> <span class="o">=</span> <span class="nx">s</span><span class="p">.</span><span class="nx">hits</span><span class="p">;</span>
        <span class="p">}</span>
    <span class="p">}</span>

    <span class="c1">// Step 2: Compute cost per tile</span>
    <span class="kd">const</span> <span class="nx">unitHits</span> <span class="o">=</span> <span class="nb">Math</span><span class="p">.</span><span class="nx">ceil</span><span class="p">(</span><span class="nx">maxHits</span> <span class="o">/</span> <span class="mi">100</span><span class="p">);</span>

    <span class="k">for</span> <span class="p">(</span><span class="kd">let</span> <span class="nx">x</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="nx">x</span> <span class="o">&lt;</span> <span class="mi">50</span><span class="p">;</span> <span class="nx">x</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">for</span> <span class="p">(</span><span class="kd">let</span> <span class="nx">y</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="nx">y</span> <span class="o">&lt;</span> <span class="mi">50</span><span class="p">;</span> <span class="nx">y</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
            <span class="kd">const</span> <span class="nx">structs</span> <span class="o">=</span> <span class="nx">room</span><span class="p">.</span><span class="nx">lookForAt</span><span class="p">(</span><span class="nx">LOOK_STRUCTURES</span><span class="p">,</span> <span class="nx">x</span><span class="p">,</span> <span class="nx">y</span><span class="p">);</span>
            <span class="kd">let</span> <span class="nx">hitsSum</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>

            <span class="k">for</span> <span class="p">(</span><span class="kd">const</span> <span class="nx">s</span> <span class="k">of</span> <span class="nx">structs</span><span class="p">)</span> <span class="p">{</span>
                <span class="k">if</span> <span class="p">(</span><span class="nx">s</span><span class="p">.</span><span class="nx">hits</span> <span class="p">)</span> <span class="p">{</span>
                    <span class="nx">hitsSum</span> <span class="o">+=</span> <span class="nx">s</span><span class="p">.</span><span class="nx">hits</span><span class="p">;</span>
                <span class="p">}</span>
            <span class="p">}</span>

            <span class="k">if</span> <span class="p">(</span><span class="nx">hitsSum</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
                <span class="kd">const</span> <span class="nx">cost</span> <span class="o">=</span> <span class="nb">Math</span><span class="p">.</span><span class="nx">min</span><span class="p">(</span><span class="mi">100</span><span class="p">,</span> <span class="nb">Math</span><span class="p">.</span><span class="nx">ceil</span><span class="p">(</span><span class="nx">hitsSum</span> <span class="o">/</span> <span class="nx">unitHits</span><span class="p">));</span>
                <span class="nx">costMatrix</span><span class="p">.</span><span class="kd">set</span><span class="p">(</span><span class="nx">x</span><span class="p">,</span> <span class="nx">y</span><span class="p">,</span> <span class="nx">cost</span><span class="p">);</span>
            <span class="p">}</span>
        <span class="p">}</span>
    <span class="p">}</span>

    <span class="k">return</span> <span class="nx">costMatrix</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>
<hr />

<h3 id="3-destruction-cost-matrix">3. Destruction Cost Matrix</h3>

<p>Since your creeps move as a 2x2 quad, convert your <code class="language-plaintext highlighter-rouge">CostMatrix</code>:</p>

<ul>
  <li>For each tile <code class="language-plaintext highlighter-rouge">(x, y)</code>, take the max cost of the following 2x2 block:
    <ul>
      <li><code class="language-plaintext highlighter-rouge">(x, y)</code></li>
      <li><code class="language-plaintext highlighter-rouge">(x+1, y)</code></li>
      <li><code class="language-plaintext highlighter-rouge">(x, y+1)</code></li>
      <li><code class="language-plaintext highlighter-rouge">(x+1, y+1)</code></li>
    </ul>
  </li>
  <li>Store that value in the new matrix.</li>
</ul>

<hr />

<h3 id="4-move-to-target">4. Move to Target</h3>

<p>Now, use the destruction cost matrix to find a path to the invader core.</p>

<ul>
  <li>Identify the first structure the quad will encounter on this path—that’s your current target.</li>
  <li>Move toward it using quad movement logic from <a href="https://sy-harabi.github.io/Quad-Movement-Basics/">my previous post</a>.</li>
</ul>

<hr />

<h2 id="-thats-it">✅ That’s It!</h2>

<p>With this setup, you should be able to take down a Level 1 Stronghold using a basic quad. But this is just the beginning. Here are some ideas to take your system further:</p>

<ol>
  <li>Boost your creeps for higher damage output and durability.</li>
  <li>Detect danger more precisely and proactively, considering enemy creeps.</li>
  <li>Improve retreat logic.</li>
  <li>Change targets if something goes wrong.</li>
  <li>Use <code class="language-plaintext highlighter-rouge">RMA</code> (Ranged Mass Attack) to destroy enemy structures more effectively.</li>
  <li>Create smarter healing strategies.</li>
  <li>Use multiple quads together without them getting stuck.</li>
  <li>Improve CPU efficiency by caching and reusing previously computed results.</li>
</ol>

<p>I’ll cover these advanced topics in future posts!</p>

<p>Stay tuned, and happy coding!</p>]]></content><author><name>Harabi</name></author><summary type="html"><![CDATA[Quad Tutorial: Attack the Level 1 Stronghold!]]></summary></entry><entry><title type="html">8 Pro Tips to Supercharge Your Energy Income in Screeps</title><link href="https://sy-harabi.github.io/8-Pro-Tips-To-Supercharge-Your-Energy-Income-In-Screeps/" rel="alternate" type="text/html" title="8 Pro Tips to Supercharge Your Energy Income in Screeps" /><published>2025-07-22T00:00:00+00:00</published><updated>2025-07-22T00:00:00+00:00</updated><id>https://sy-harabi.github.io/8-Pro-Tips-To-Supercharge-Your-Energy-Income-In-Screeps</id><content type="html" xml:base="https://sy-harabi.github.io/8-Pro-Tips-To-Supercharge-Your-Energy-Income-In-Screeps/"><![CDATA[<h1 id="8-pro-tips-to-supercharge-your-energy-income-in-screeps">8 Pro Tips to Supercharge Your Energy Income in Screeps</h1>

<p>Energy is the lifeblood of your Screeps empire. It fuels every action, from spawning creeps and building structures to defending your territory and upgrading your Controller. Hitting an energy income ceiling is one of the most common roadblocks players face. If you feel like your growth has stalled, it’s time to optimize your economy.</p>

<p>This guide covers 8 essential tips, from fundamental principles to advanced strategies, to help you dramatically boost your energy income.</p>

<hr />

<h3 id="1-specialize-with-static-miners-and-haulers">1. Specialize with Static Miners and Haulers</h3>

<p><img src="https://github.com/user-attachments/assets/3356785f-b309-4f0c-8d71-a967d822de71" alt="1  Miners and Haulers" /></p>

<p>One of the first and most impactful changes you can make is to stop using general-purpose worker creeps. A single creep with <code class="language-plaintext highlighter-rouge">WORK</code>, <code class="language-plaintext highlighter-rouge">CARRY</code>, and <code class="language-plaintext highlighter-rouge">MOVE</code> parts is inherently inefficient. When it’s mining, its <code class="language-plaintext highlighter-rouge">CARRY</code> parts are idle. When it’s hauling, its <code class="language-plaintext highlighter-rouge">WORK</code> parts are useless. You’re paying for parts that aren’t being used half the time.</p>

<p>The solution is to specialize your creeps into two distinct roles:</p>

<ul>
  <li><strong>Static Miners:</strong> These creeps are designed with <code class="language-plaintext highlighter-rouge">WORK</code> parts to harvest source and <code class="language-plaintext highlighter-rouge">MOVE</code> parts to get into position. They sit directly on an energy source and do nothing but mine continuously. Some players put one ‘CARRY’ part on them to let them repair its own container.</li>
  <li><strong>Haulers:</strong> These are logistics creeps, built with <code class="language-plaintext highlighter-rouge">CARRY</code> and <code class="language-plaintext highlighter-rouge">MOVE</code> parts. Their only job is to pick up the energy dropped by miners and transport it.</li>
</ul>

<p>This division of labor is the foundation of a scalable economy.</p>

<h3 id="2-expand-with-remote-mining">2. Expand with Remote Mining</h3>

<p><img src="https://github.com/user-attachments/assets/c98345c9-5892-4717-8191-9445f8069e62" alt="2  Remotes" /></p>

<p>Once you’ve optimized harvesting in your home room, you’ll quickly hit a hard cap. A standard room has at most two energy sources, limiting your income to 20 energy per tick. To grow beyond this, you must look to near, neutral rooms.</p>

<p><strong>Remote mining</strong>—sending your miners and haulers to harvest sources in nearby rooms—is the single most effective way to boost your early-game energy income. More sources harvested means more energy for your empire.</p>

<h3 id="3-build-infrastructure-containers-and-roads">3. Build Infrastructure: Containers and Roads</h3>

<p><img src="https://github.com/user-attachments/assets/ab9228e8-0e32-4762-b97a-9e08f88654da" alt="3  Building roads" /></p>

<p>To support your specialized creeps, you need infrastructure. <strong>Containers and roads</strong> are non-negotiable for an efficient operation.</p>

<p>First, build a container next to each energy source. Your static miner can drop energy directly into it, which prevents the energy from decaying on the ground and creates a large buffer for your haulers to draw from.</p>

<p>Next, build roads connecting your sources to your storage. Roads make the fatigue generated by movement by half. This is a critical mechanic, as it allows you to build more efficient haulers. On a road, a creep only needs one <code class="language-plaintext highlighter-rouge">MOVE</code> part for every two <code class="language-plaintext highlighter-rouge">CARRY</code> parts (<code class="language-plaintext highlighter-rouge">2:1</code>) to move effectively, compared to the <code class="language-plaintext highlighter-rouge">1:1</code> ratio required on plain. This translates into massive savings across all three major resources: energy, spawn time, and CPU.</p>

<h3 id="4-optimize-your-logistics-dont-over-spawn-haulers">4. Optimize Your Logistics: Don’t Over-spawn Haulers</h3>

<p>A common mistake is to think more haulers is always better. In reality, you should <strong>not spawn more haulers than you absolutely need.</strong></p>

<p>Haulers are expensive. They cost a significant amount of energy and spawn time, and they consume CPU for their entire lifetime. An idle hauler waiting for energy is a drain on the very resources you’re trying to accumulate. Precision is key. Calculate the exact number of hauler <code class="language-plaintext highlighter-rouge">CARRY</code> parts required to service your sources based on distance and output, and spawn just enough to meet that demand.</p>

<h3 id="5-choose-remotes-wisely">5. Choose Remotes Wisely</h3>

<p>The single most important factor in choosing which room to harvest is <strong>proximity</strong>.</p>

<p>Your miners are relatively cheap, but the cost of hauling energy over long distances is significant. The farther your haulers have to travel, the more energy, spawn time, and CPU they consume. Always prioritize harvesting from the closest remote rooms first, expanding outwards until you’re capped by spawn time or CPU.</p>

<h3 id="6-advanced-harvest-source-keeper-rooms">6. (Advanced) Harvest Source Keeper Rooms</h3>

<p><img src="https://github.com/user-attachments/assets/6413af27-0038-4724-8793-f7c9025662b8" alt="4  Source keeper" /></p>

<p>Once one of your rooms reaches <strong>Room Controller Level 7 (RCL 7)</strong>, you can unlock a new tier of energy income: <strong>Source Keeper (SK) rooms</strong>.</p>

<p>Sources in these hostile rooms are 33% richer, regenerating 4,000 energy every 300 ticks instead of the standard 3,000. As an added bonus, the hostile Source Keeper NPCs that guard these sources drop energy in their tombstones when killed.</p>

<p>To operate here, you’ll need to spawn a dedicated combat creep from your RCL 7 room, typically with <code class="language-plaintext highlighter-rouge">ATTACK</code>, <code class="language-plaintext highlighter-rouge">MOVE</code>, and <code class="language-plaintext highlighter-rouge">HEAL</code> parts, to roam the SK room and keep it clear.</p>

<h3 id="7-advanced-implement-a-hauler-pool">7. (Advanced) Implement a Hauler Pool</h3>

<p>As your logistics network grows, assigning dedicated haulers to a single source becomes inefficient. You can’t perfectly match supply and demand (e.g., a source might need 2.5 haulers), and creeps often waste their final ticks when they lack enough TTL for a final round trip.</p>

<p>The solution is a <strong>hauler pool</strong>. Instead of dedicated assignments, you treat all your haulers as a single, uniform group. A central system dynamically assigns any available hauler to any container that needs servicing. This provides incredible flexibility, reduces the total number of haulers needed, and minimizes waste. While more complex to code, the efficiency gains are enormous.</p>

<h3 id="8-monitor-everything-with-visuals">8. Monitor Everything with Visuals</h3>

<p><img src="https://github.com/user-attachments/assets/5771ae69-77b9-429f-aec7-582895ce81b3" alt="5  visuals" /></p>

<p>You can’t optimize what you can’t see. Screeps provides excellent tools for monitoring your economy at a glance.</p>

<ul>
  <li><strong><code class="language-plaintext highlighter-rouge">RoomVisual</code>:</strong> Use this to draw information directly in your rooms. Create a dashboard showing the status of each source, assigned miners and haulers, and more.</li>
  <li><strong><code class="language-plaintext highlighter-rouge">MapVisual</code>:</strong> Get a global overview of your remote harvesting operations.</li>
  <li><strong><code class="language-plaintext highlighter-rouge">creep.say()</code>:</strong> Have your creeps report their current task or status. This is invaluable for debugging issues with history.</li>
</ul>

<p>Good monitoring allows you to spot inefficiencies and fix them before they become major problems.</p>

<hr />

<p>By implementing these strategies, you can transform your economy from a bottleneck into a powerhouse. What are your favorite tips for boosting energy income? Share them in the comments below!</p>]]></content><author><name>Harabi</name></author><summary type="html"><![CDATA[8 Pro Tips to Supercharge Your Energy Income in Screeps]]></summary></entry><entry><title type="html">Quad Movement Basics</title><link href="https://sy-harabi.github.io/Quad-Movement-Basics/" rel="alternate" type="text/html" title="Quad Movement Basics" /><published>2025-02-19T00:00:00+00:00</published><updated>2025-02-19T00:00:00+00:00</updated><id>https://sy-harabi.github.io/Quad-Movement-Basics</id><content type="html" xml:base="https://sy-harabi.github.io/Quad-Movement-Basics/"><![CDATA[<h2 id="quad-movement-basics">Quad Movement basics</h2>

<p><img src="https://github.com/user-attachments/assets/73121e2f-593e-4146-b4f0-d7e3f05d3362" alt="Desktop 2025 02 19 - 14 11 26 02 DVR_5" /></p>

<p>In Screeps, quads play a crucial role, especially when attacking rooms with high RCL. Using only duos can make it really challenging to take on an RCL8 room. Today, I’ll introduce the basics of quad movement.</p>

<p>The rough idea is simple:</p>

<ol>
  <li>Get four creeps.</li>
  <li>Find a wide enough area for them to be packed as a square.</li>
  <li>Pack them into that area.</li>
  <li>Adjust the cost matrix for quads.</li>
  <li>Make sure the quad is packed before finding the path.</li>
  <li>Find a path to the goal.</li>
  <li>Make the quad follow the path.</li>
</ol>

<p>The most tricky part is adjusting the cost matrix, but it’s not as hard as it sounds. Let’s dive into it!</p>

<hr />

<h3 id="step-1-spawn-four-creeps">Step 1: Spawn Four Creeps</h3>

<p>First, spawn four creeps.</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">Game</span><span class="p">.</span><span class="nx">spawns</span><span class="p">[</span><span class="dl">"</span><span class="s2">Spawn1</span><span class="dl">"</span><span class="p">].</span><span class="nx">spawnCreep</span><span class="p">([</span><span class="nx">MOVE</span><span class="p">],</span> <span class="dl">"</span><span class="s2">Quad1</span><span class="dl">"</span><span class="p">)</span>
<span class="nx">Game</span><span class="p">.</span><span class="nx">spawns</span><span class="p">[</span><span class="dl">"</span><span class="s2">Spawn1</span><span class="dl">"</span><span class="p">].</span><span class="nx">spawnCreep</span><span class="p">([</span><span class="nx">MOVE</span><span class="p">],</span> <span class="dl">"</span><span class="s2">Quad2</span><span class="dl">"</span><span class="p">)</span>
<span class="nx">Game</span><span class="p">.</span><span class="nx">spawns</span><span class="p">[</span><span class="dl">"</span><span class="s2">Spawn1</span><span class="dl">"</span><span class="p">].</span><span class="nx">spawnCreep</span><span class="p">([</span><span class="nx">MOVE</span><span class="p">],</span> <span class="dl">"</span><span class="s2">Quad3</span><span class="dl">"</span><span class="p">)</span>
<span class="nx">Game</span><span class="p">.</span><span class="nx">spawns</span><span class="p">[</span><span class="dl">"</span><span class="s2">Spawn1</span><span class="dl">"</span><span class="p">].</span><span class="nx">spawnCreep</span><span class="p">([</span><span class="nx">MOVE</span><span class="p">],</span> <span class="dl">"</span><span class="s2">Quad4</span><span class="dl">"</span><span class="p">)</span>
</code></pre></div></div>

<p><img src="https://github.com/user-attachments/assets/e1dc3ea0-e6dc-4c2f-afe1-6a30425e4db5" alt="3  spawn 4 creeps" /></p>

<p>Now you have four creeps!</p>

<hr />

<h3 id="step-2-find-a-square-area-to-pack-creeps">Step 2: Find a Square Area to Pack Creeps</h3>

<p>Next, you need to find some square area to pack those creeps. This can be done by searching RoomPosition objects near your creeps to find a position A such that:</p>

<ul>
  <li>A</li>
  <li>Right of A</li>
  <li>Bottom of A</li>
  <li>Bottom-right of A</li>
</ul>

<p>…are all empty.</p>

<p><img src="https://github.com/user-attachments/assets/cfec820d-8b30-4be1-8db4-936b34b41883" alt="4  find area to form" /></p>

<h4 id="important">Important:</h4>

<p>You should remember that area until the creeps are all packed together. Searching for a new area every tick could make your quad fall into an infinite loop.</p>

<p>Once you find the area, assign each creep to a specific position and make them go there.</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// Example: Assign formation positions relative to the top-left corner</span>
<span class="nx">creep1</span><span class="p">.</span><span class="nx">moveTo</span><span class="p">(</span><span class="nx">topLeftPos</span><span class="p">)</span>
<span class="nx">creep2</span><span class="p">.</span><span class="nx">moveTo</span><span class="p">(</span><span class="k">new</span> <span class="nx">RoomPosition</span><span class="p">(</span><span class="nx">topLeftPos</span><span class="p">.</span><span class="nx">x</span> <span class="o">+</span> <span class="mi">1</span><span class="p">,</span> <span class="nx">topLeftPos</span><span class="p">.</span><span class="nx">y</span><span class="p">,</span> <span class="nx">roomName</span><span class="p">))</span>
<span class="nx">creep3</span><span class="p">.</span><span class="nx">moveTo</span><span class="p">(</span><span class="k">new</span> <span class="nx">RoomPosition</span><span class="p">(</span><span class="nx">topLeftPos</span><span class="p">.</span><span class="nx">x</span><span class="p">,</span> <span class="nx">topLeftPos</span><span class="p">.</span><span class="nx">y</span> <span class="o">+</span> <span class="mi">1</span><span class="p">,</span> <span class="nx">roomName</span><span class="p">))</span>
<span class="nx">creep4</span><span class="p">.</span><span class="nx">moveTo</span><span class="p">(</span><span class="k">new</span> <span class="nx">RoomPosition</span><span class="p">(</span><span class="nx">topLeftPos</span><span class="p">.</span><span class="nx">x</span> <span class="o">+</span> <span class="mi">1</span><span class="p">,</span> <span class="nx">topLeftPos</span><span class="p">.</span><span class="nx">y</span> <span class="o">+</span> <span class="mi">1</span><span class="p">,</span> <span class="nx">roomName</span><span class="p">))</span>
</code></pre></div></div>

<p><img src="https://github.com/user-attachments/assets/2110fd30-6346-4f4f-befc-a068606eb9ff" alt="5  gather creeps" /></p>

<p>Now you have four creeps perfectly packed into a square!</p>

<p>To ensure your creeps are packed, you can create a helper function:</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">function</span> <span class="nx">isQuadPacked</span><span class="p">(</span><span class="nx">creeps</span><span class="p">)</span> <span class="p">{</span>
  <span class="k">if</span> <span class="p">(</span><span class="nx">creeps</span><span class="p">.</span><span class="nx">length</span> <span class="o">!==</span> <span class="mi">4</span><span class="p">)</span> <span class="k">return</span> <span class="kc">false</span>
  <span class="k">for</span> <span class="p">(</span><span class="kd">let</span> <span class="nx">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="nx">i</span> <span class="o">&lt;</span> <span class="nx">creeps</span><span class="p">.</span><span class="nx">length</span><span class="p">;</span> <span class="nx">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">for</span> <span class="p">(</span><span class="kd">let</span> <span class="nx">j</span> <span class="o">=</span> <span class="nx">i</span> <span class="o">+</span> <span class="mi">1</span><span class="p">;</span> <span class="nx">j</span> <span class="o">&lt;</span> <span class="nx">creeps</span><span class="p">.</span><span class="nx">length</span><span class="p">;</span> <span class="nx">j</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
      <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nx">creeps</span><span class="p">[</span><span class="nx">i</span><span class="p">].</span><span class="nx">pos</span><span class="p">.</span><span class="nx">isNearTo</span><span class="p">(</span><span class="nx">creeps</span><span class="p">[</span><span class="nx">j</span><span class="p">].</span><span class="nx">pos</span><span class="p">))</span> <span class="k">return</span> <span class="kc">false</span>
    <span class="p">}</span>
  <span class="p">}</span>
  <span class="k">return</span> <span class="kc">true</span>
<span class="p">}</span>
</code></pre></div></div>

<p>This function checks that every creep is adjacent to every other creep.</p>

<hr />

<h3 id="step-3-adjust-the-cost-matrix">Step 3: Adjust the Cost Matrix</h3>

<p>Now, it’s time to adjust the cost matrix for quad movement.</p>

<h4 id="concept">Concept:</h4>

<ul>
  <li>Assume the top-left creep in the formation is your “leader.”</li>
  <li>Create a modified cost matrix that accounts for the fact that the quad occupies a 2x2 area, not a single tile.</li>
</ul>

<hr />

<p><img src="https://github.com/user-attachments/assets/06278438-3933-433d-9819-ed91c227b95a" alt="Adjust costs" /></p>

<p>See how the cost in the red circle has changed!</p>

<h4 id="example-cost-matrix-transformation">Example: Cost Matrix Transformation</h4>

<p>Here’s how you can transform your existing room cost matrix for quad movement:</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">function</span> <span class="nx">transformCosts</span><span class="p">(</span><span class="nx">costs</span><span class="p">,</span> <span class="nx">roomName</span><span class="p">,</span> <span class="nx">swampCost</span> <span class="o">=</span> <span class="mi">5</span><span class="p">,</span> <span class="nx">plainCost</span> <span class="o">=</span> <span class="mi">1</span><span class="p">)</span> <span class="p">{</span>
  <span class="kd">const</span> <span class="nx">terrain</span> <span class="o">=</span> <span class="nx">Game</span><span class="p">.</span><span class="nx">map</span><span class="p">.</span><span class="nx">getRoomTerrain</span><span class="p">(</span><span class="nx">roomName</span><span class="p">)</span>
  <span class="kd">const</span> <span class="nx">result</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">PathFinder</span><span class="p">.</span><span class="nx">CostMatrix</span><span class="p">()</span>
  <span class="kd">const</span> <span class="nx">formationVectors</span> <span class="o">=</span> <span class="p">[</span>
    <span class="p">{</span> <span class="na">x</span><span class="p">:</span> <span class="mi">0</span><span class="p">,</span> <span class="na">y</span><span class="p">:</span> <span class="mi">0</span> <span class="p">},</span> <span class="c1">// top-left</span>
    <span class="p">{</span> <span class="na">x</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span> <span class="na">y</span><span class="p">:</span> <span class="mi">0</span> <span class="p">},</span> <span class="c1">// top-right</span>
    <span class="p">{</span> <span class="na">x</span><span class="p">:</span> <span class="mi">0</span><span class="p">,</span> <span class="na">y</span><span class="p">:</span> <span class="mi">1</span> <span class="p">},</span> <span class="c1">// bottom-left</span>
    <span class="p">{</span> <span class="na">x</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span> <span class="na">y</span><span class="p">:</span> <span class="mi">1</span> <span class="p">},</span> <span class="c1">// bottom-right</span>
  <span class="p">]</span>

  <span class="k">for</span> <span class="p">(</span><span class="kd">let</span> <span class="nx">x</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="nx">x</span> <span class="o">&lt;</span> <span class="mi">50</span><span class="p">;</span> <span class="nx">x</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">for</span> <span class="p">(</span><span class="kd">let</span> <span class="nx">y</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="nx">y</span> <span class="o">&lt;</span> <span class="mi">50</span><span class="p">;</span> <span class="nx">y</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
      <span class="kd">let</span> <span class="nx">cost</span> <span class="o">=</span> <span class="kc">undefined</span>

      <span class="k">for</span> <span class="p">(</span><span class="kd">let</span> <span class="nx">vector</span> <span class="k">of</span> <span class="nx">formationVectors</span><span class="p">)</span> <span class="p">{</span>
        <span class="kd">const</span> <span class="nx">newX</span> <span class="o">=</span> <span class="nx">x</span> <span class="o">+</span> <span class="nx">vector</span><span class="p">.</span><span class="nx">x</span>
        <span class="kd">const</span> <span class="nx">newY</span> <span class="o">=</span> <span class="nx">y</span> <span class="o">+</span> <span class="nx">vector</span><span class="p">.</span><span class="nx">y</span>

        <span class="k">if</span> <span class="p">(</span><span class="nx">newX</span> <span class="o">&lt;</span> <span class="mi">0</span> <span class="o">||</span> <span class="nx">newX</span> <span class="o">&gt;</span> <span class="mi">49</span> <span class="o">||</span> <span class="nx">newY</span> <span class="o">&lt;</span> <span class="mi">0</span> <span class="o">||</span> <span class="nx">newY</span> <span class="o">&gt;</span> <span class="mi">49</span><span class="p">)</span> <span class="p">{</span>
          <span class="k">continue</span>
        <span class="p">}</span>

        <span class="kd">let</span> <span class="nx">newCost</span> <span class="o">=</span> <span class="nx">costs</span><span class="p">.</span><span class="kd">get</span><span class="p">(</span><span class="nx">newX</span><span class="p">,</span> <span class="nx">newY</span><span class="p">)</span>

        <span class="k">if</span> <span class="p">(</span><span class="nx">newCost</span> <span class="o">===</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
          <span class="kd">const</span> <span class="nx">terrainMask</span> <span class="o">=</span> <span class="nx">terrain</span><span class="p">.</span><span class="kd">get</span><span class="p">(</span><span class="nx">newX</span><span class="p">,</span> <span class="nx">newY</span><span class="p">)</span>
          <span class="k">if</span> <span class="p">(</span><span class="nx">terrainMask</span> <span class="o">===</span> <span class="nx">TERRAIN_MASK_WALL</span><span class="p">)</span> <span class="p">{</span>
            <span class="nx">newCost</span> <span class="o">=</span> <span class="mi">255</span>
          <span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="nx">terrainMask</span> <span class="o">===</span> <span class="nx">TERRAIN_MASK_SWAMP</span><span class="p">)</span> <span class="p">{</span>
            <span class="nx">newCost</span> <span class="o">=</span> <span class="nx">swampCost</span>
          <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
            <span class="nx">newCost</span> <span class="o">=</span> <span class="nx">plainCost</span>
          <span class="p">}</span>
        <span class="p">}</span>

        <span class="k">if</span> <span class="p">(</span><span class="nx">cost</span> <span class="o">===</span> <span class="kc">undefined</span><span class="p">)</span> <span class="p">{</span>
          <span class="nx">cost</span> <span class="o">=</span> <span class="nx">newCost</span>
        <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
          <span class="nx">cost</span> <span class="o">=</span> <span class="nb">Math</span><span class="p">.</span><span class="nx">max</span><span class="p">(</span><span class="nx">cost</span><span class="p">,</span> <span class="nx">newCost</span><span class="p">)</span>
        <span class="p">}</span>
      <span class="p">}</span>

      <span class="nx">result</span><span class="p">.</span><span class="kd">set</span><span class="p">(</span><span class="nx">x</span><span class="p">,</span> <span class="nx">y</span><span class="p">,</span> <span class="nx">cost</span><span class="p">)</span>
    <span class="p">}</span>
  <span class="p">}</span>
  <span class="k">return</span> <span class="nx">result</span>
<span class="p">}</span>
</code></pre></div></div>

<hr />

<h3 id="step-4-pathfinding-with-quad-formation">Step 4: Pathfinding with Quad Formation</h3>

<p>Use the transformed cost matrix in your PathFinder.search call, and make sure to use the top-left creep’s position as the startPos.</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">const</span> <span class="nx">costMatrix</span> <span class="o">=</span> <span class="nx">transformCosts</span><span class="p">(</span><span class="nx">existingCostMatrix</span><span class="p">,</span> <span class="nx">roomName</span><span class="p">)</span>
<span class="kd">const</span> <span class="nx">path</span> <span class="o">=</span> <span class="nx">PathFinder</span><span class="p">.</span><span class="nx">search</span><span class="p">(</span>
  <span class="nx">topLeftPos</span><span class="p">,</span>
  <span class="p">{</span> <span class="na">pos</span><span class="p">:</span> <span class="nx">targetPos</span><span class="p">,</span> <span class="na">range</span><span class="p">:</span> <span class="mi">1</span> <span class="p">},</span>
  <span class="p">{</span>
    <span class="na">plainCost</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span>
    <span class="na">swampCost</span><span class="p">:</span> <span class="mi">5</span><span class="p">,</span>
    <span class="na">roomCallback</span><span class="p">:</span> <span class="p">()</span> <span class="o">=&gt;</span> <span class="nx">costMatrix</span><span class="p">,</span>
  <span class="p">},</span>
<span class="p">)</span>
</code></pre></div></div>

<hr />

<h3 id="step-5-move-the-quad">Step 5: Move the Quad</h3>

<p><img src="https://github.com/user-attachments/assets/56d97fd6-788d-416b-bf2e-382580b7c957" alt="Desktop 2025 02 19 - 14 11 26 02 DVR_4" /></p>

<p>Once you have a path, make each creep follow the path, staying in formation. A simple way is to find the direction from the path and move all creeps in that direction:</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">const</span> <span class="nx">direction</span> <span class="o">=</span> <span class="nx">topLeftPos</span><span class="p">.</span><span class="nx">getDirectionTo</span><span class="p">(</span><span class="nx">path</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span>
<span class="nx">creeps</span><span class="p">.</span><span class="nx">forEach</span><span class="p">((</span><span class="nx">creep</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="nx">creep</span><span class="p">.</span><span class="nx">move</span><span class="p">(</span><span class="nx">direction</span><span class="p">))</span>
</code></pre></div></div>

<hr />

<h3 id="pseudocode-for-overall-quad-movement">Pseudocode for Overall Quad Movement</h3>

<pre><code class="language-pseudocode">// 1. Spawn four creeps, each with one MOVE part.
spawnCreep([MOVE], 'Quad1')
spawnCreep([MOVE], 'Quad2')
spawnCreep([MOVE], 'Quad3')
spawnCreep([MOVE], 'Quad4')

// 2. Check if the quad is properly packed.
if isQuadPacked(creeps) is false:
    // 2a. Find a square area (topLeftPos) where a 2x2 area is empty.
    topLeftPos = findEmptySquareAreaAroundCreeps(creeps)

    // 2b. Move each creep to its designated position to form a quad.
    creep1.moveTo(topLeftPos)
    creep2.moveTo(position at (topLeftPos.x + 1, topLeftPos.y))
    creep3.moveTo(position at (topLeftPos.x, topLeftPos.y + 1))
    creep4.moveTo(position at (topLeftPos.x + 1, topLeftPos.y + 1))

// 3. Transform the room's cost matrix to account for the quad formation.
transformedCosts = transformCosts(existingCostMatrix, roomName, swampCost=5, plainCost=1)

// 4. Use the top-left position (from the quad formation) as the starting point and search for a path to the target.
path = PathFinder.search(topLeftPos, targetPos, { costMatrix: transformedCosts })

// 5. Determine movement direction from the path.
direction = getDirectionFrom(topLeftPos to next step in path)

// 6. Move all creeps in the determined direction.
for each creep in creeps:
    creep.move(direction)

// 7. Continue pathfinding and moving until the target is reached.
</code></pre>

<hr />

<h3 id="challenges-to-improve-quad-movement">Challenges to Improve Quad Movement</h3>

<p>Now that you’ve mastered the basics of quad movement, it’s time to tackle some more advanced challenges. Try these out and feel free to reach out if you encounter any issues or want to share your solutions! You can ping me (Harabi) on the official Screeps Discord.</p>

<ul>
  <li>Path caching to avoid redundant calculations.</li>
  <li>More efficient methods for packing creeps into formation.</li>
  <li>Avoiding collisions with enemy creeps.</li>
  <li>Temporarily breaking formation to slip through narrow passages.</li>
  <li>Inter-room traveling for entering and retreating.</li>
  <li>Room edge handling to prevent getting stuck at exits.</li>
</ul>

<hr />

<p>Happy Screeping!</p>]]></content><author><name>Harabi</name></author><summary type="html"><![CDATA[Quad Movement basics]]></summary></entry><entry><title type="html">How I Wrote Active Defender Code</title><link href="https://sy-harabi.github.io/How-I-Wrote-Active-Defender-Code/" rel="alternate" type="text/html" title="How I Wrote Active Defender Code" /><published>2024-08-18T00:00:00+00:00</published><updated>2024-08-18T00:00:00+00:00</updated><id>https://sy-harabi.github.io/How-I-Wrote-Active-Defender-Code</id><content type="html" xml:base="https://sy-harabi.github.io/How-I-Wrote-Active-Defender-Code/"><![CDATA[<h2 id="1-todays-subject">1. Today’s Subject</h2>

<p>In the past few posts, I’ve primarily focused on the economy. A robust economy enables rapid growth, but to thrive, you must also defend your rooms effectively. This time, let’s delve into room defense.</p>

<p>Basic room defense comprises three main components: strong enough towers, repairers, and active defenders. Among these, active defenders are the most challenging to manage. Today, I’ll break down the process of implementing active defenders, focusing primarily on melee defenders.</p>

<p>To effectively use active defenders, we need to answer three key questions:</p>

<ol>
  <li>How much damage do we need?</li>
  <li>How should we assign or spawn active defenders?</li>
  <li>How can we move them smoothly?</li>
</ol>

<p>Let’s tackle each of these questions one by one.</p>

<h2 id="2-how-much-damage-do-we-need">2. How Much Damage Do We Need?</h2>

<p>The first question we need to answer is, “How many active defenders do we need?” To do this, we must first determine how much damage is necessary to deal effective damage to each enemy creep and how to group enemies.</p>

<h3 id="21-estimating-tower-damage">2.1. Estimating Tower Damage</h3>

<p>The first step is to understand how much damage we can expect from our towers. I use the minimum tower damage for all the outermost ramparts, as this is the most conservative estimate for enemy creeps.</p>

<p>You can calculate this using <code class="language-plaintext highlighter-rouge">floodFill</code>. If you’re unfamiliar with it, refer to the 5th paragraph of the “The Process” section in <a href="https://sy-harabi.github.io/Automating-base-planning-in-screeps/#the-process">this post</a>. Start from the room exits, collect the outermost ramparts, and then determine the minimum tower damage among them. This will serve as your tower damage expectation.</p>

<h3 id="22-calculating-required-damage">2.2. Calculating Required Damage</h3>

<p>To calculate the required damage, I wrote a script based on the Screeps engine code, which you can view <a href="https://github.com/sy-harabi/screeps-utils/blob/017105e9540ae5bfde34b0e307da1a588b85e9fb/utils.js#L7">here</a>. The key point is that you must deal more than 100 damage to destroy one boosted tough part while considering the heal power of enemy creeps. Here’s how you can approach this:</p>

<ol>
  <li>
    <p><strong>Calculate Total Heal:</strong> For each enemy creep, calculate the total healing potential (including both regular and ranged heal). Let’s call this the total heal for that creep.</p>
  </li>
  <li>
    <p><strong>Calculate Required Damage:</strong> For each enemy creep, determine how much damage is needed to overcome a set amount of damage plus the total heal for that creep. I typically use 100 as the base amount, though this value is somewhat arbitrary.</p>
  </li>
  <li>
    <p><strong>Adjust for Tower Damage:</strong> Subtract the expected tower damage from the required damage calculated in step 2.</p>
  </li>
</ol>

<p>With this, we have determined the additional damage required beyond what the towers can deliver. We’ll use this information to decide how many active defenders to spawn later.</p>

<h2 id="3-how-should-we-assignspawn-active-defenders">3. How Should We Assign/Spawn Active Defenders?</h2>

<p>Spawning active defenders for each enemy creep is inefficient because enemies usually form groups like duos or quads. To manage this, we need to group them effectively. Here’s how I solved this problem:</p>

<h3 id="31-grouping-enemy-creeps">3.1. Grouping Enemy Creeps</h3>

<ol>
  <li>
    <p><strong>Flow Field Setup:</strong> Start by generating a flow field from our outermost ramparts (collected in step 2.1). This involves running a full Dijkstra and caching the results. This method allows us to quickly determine the closest outermost rampart for each enemy without performing costly pathfinding for every enemy.
  <img src="https://github.com/user-attachments/assets/cb17acb0-4e64-4d73-b78f-507d0d05e238" alt="FloodFill Example" /></p>
  </li>
  <li>
    <p><strong>Initialize a Damage Map:</strong> Create an empty object to store the expected damage for each outermost rampart position. You can use a two-dimensional object or calculate keys using the formula <code class="language-plaintext highlighter-rouge">50*y+x</code>.</p>
  </li>
  <li>
    <p><strong>Assign Enemies to Ramparts:</strong> For each enemy, determine the closest rampart (based on path length) using the flow field. Minimize diagonal moves, as these are less effective for blocking enemies from reaching the ramparts.
  <img src="https://github.com/user-attachments/assets/dad9f6b4-d5ca-47bf-8947-9aa53e5ccf0a" alt="Finding Closest Rampart" />
  This is good enough
  <img src="https://github.com/user-attachments/assets/888e5b15-3c6f-43a0-8ad5-6e3d3c81f519" alt="Prefer Straight Paths" />
  But this is better</p>
  </li>
  <li>
    <p><strong>Collect Adjacent Ramparts:</strong> Gather all ramparts adjacent to the closest one (using Manhattan distance). Typically, this involves three ramparts. For each position, add the enemy creep’s attack power to the damage map.</p>
  </li>
  <li>
    <p><strong>Group Enemies:</strong> Identify the outermost rampart position with the highest expected damage. Group all the enemy creeps that contributed to this rampart. Repeat steps 3.1.3 through 3.1.4 until no enemy creeps remain ungrouped.</p>
  </li>
</ol>

<p>After grouping, you should see something like this:</p>

<p><img src="https://github.com/user-attachments/assets/4350c389-f83c-4d84-8651-0b176af89366" alt="Grouping Enemies" /></p>

<h3 id="32-assigning-and-spawning-defenders">3.2. Assigning and Spawning Defenders</h3>

<p>For each group, find the creep with the highest required damage calculated in step 2.2. Assign active defenders until their combined damage surpasses this requirement. If there aren’t enough defenders, spawn more. This method ensures that you efficiently assign and spawn enough active defenders.</p>

<h2 id="4-how-should-we-move-active-defenders-smoothly">4. How Should We Move Active Defenders Smoothly?</h2>

<p>The final challenge is moving and allocating your defenders effectively. Movement is a complex aspect of Screeps, but I’ve found a solution that works well.</p>
<video controls="" width="100%">
  <source src="https://github.com/user-attachments/assets/fb17d13c-21de-4198-a15b-5dc030221dce" type="video/mp4" />
  Your browser does not support the video tag.
</video>
<p>Pretty elegant, right?</p>

<h3 id="41-movement-strategy">4.1. Movement Strategy</h3>

<ol>
  <li>
    <p><strong>Identify Key Positions:</strong> For each enemy group, find the enemy closest to the outermost ramparts. Use the cached rampart positions to determine where your creeps should stand.</p>
  </li>
  <li>
    <p><strong>Move Creeps:</strong> The cyan squares in the video represent the positions defenders should occupy. Here’s how to move them:</p>

    <p>a. <strong>Approach the Tiles:</strong> For each creep more than one tile away from all the desired tiles, move it closer until it’s adjacent to one of the desired tiles.</p>

    <p>b. <strong>Pathfinding:</strong> For creeps adjacent to one of the desired tiles, find a path to an empty tile using only other defenders.</p>

    <p>c. <strong>Chain Movement:</strong> If a path is found, move each creep one step forward along the path, ultimately positioning the first creep inside the desired area.</p>
  </li>
</ol>

<p>This method allows you to allocate your defender creeps smoothly and effectively.</p>

<h2 id="conclusion">Conclusion</h2>

<p>We’ve covered how to manage active defenders in Screeps, from calculating damage needs to moving them efficiently. With these strategies, your established rooms should be well-defended against most threats. If you have any questions, feel free to ping me on the official Discord or leave a comment on this post.</p>

<p>Thank you for reading!</p>]]></content><author><name>Harabi</name></author><summary type="html"><![CDATA[1. Today’s Subject]]></summary></entry><entry><title type="html">Optimizing Early Game Economy – Part 2: Spawn Management and Hauler Pool</title><link href="https://sy-harabi.github.io/Optimizing-Early-Game-Part-Two-spawn-management-and-hauler-pool/" rel="alternate" type="text/html" title="Optimizing Early Game Economy – Part 2: Spawn Management and Hauler Pool" /><published>2024-08-12T00:00:00+00:00</published><updated>2024-08-12T00:00:00+00:00</updated><id>https://sy-harabi.github.io/Optimizing-Early-Game-Part-Two-spawn-management-and-hauler-pool</id><content type="html" xml:base="https://sy-harabi.github.io/Optimizing-Early-Game-Part-Two-spawn-management-and-hauler-pool/"><![CDATA[<p>Hello everyone! In my <a href="https://sy-harabi.github.io/Optimizing-Early-Game-Part-One-Selecting-Remotes/">previous article</a>  , I discussed how to effectively select remotes to optimize the early game economy. Now that we’ve covered that, it’s time to dive into spawn management and hauler pool optimization. With the right strategy, we can streamline the spawning process and ensure our haulers are operating at peak efficiency.</p>

<p><img src="https://github.com/user-attachments/assets/38943367-abe4-4c88-9a9a-4b6ced12e785" style="width:100%" /></p>

<h2 id="1-spawning-creeps">1. Spawning Creeps</h2>

<h3 id="a-spawn-management-system-overview">A. Spawn Management System Overview</h3>

<p>To manage the spawning of creeps efficiently, I’ve developed a spawn management system that organizes and prioritizes spawn requests. While it may not be the ultimate solution, this system has greatly improved my clarity and coding efficiency.</p>

<ol>
  <li>
    <p><strong>Queue Initialization:</strong> At the start of the main loop, I iterate through all the rooms I control and check if there is available spawn and prepare a spawn queue if there is. I use a <strong>min-max heap</strong> for this queue, which simplifies the sorting process. You can read more about min-max heaps <a href="https://en.wikipedia.org/wiki/Min-max_heap">here</a>.</p>
  </li>
  <li>
    <p><strong>Requesting Creeps:</strong> During the logic phase for each room, whenever there is available spawn and a new creep is needed, I insert a spawn request into the queue. Each request includes crucial details like the creep’s name, body composition, memory, role, and other necessary information.</p>
  </li>
  <li>
    <p><strong>Processing the Queue:</strong> After all the logic has been executed, I iterate through all the rooms I control and review the spawn queue and spawn the creeps with the highest priority.</p>
  </li>
</ol>

<p>So, my main loop looks like this.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>for room of myRooms
    spawnManager.resetSpawnQueue(room)

for room of myRooms
    roomManager.run(room) // during run, request creep if there is available spawn and a new creep is needed.
    
for room of myRooms
    spawnManager.run(room)
</code></pre></div></div>

<h3 id="b-spawning-order-for-earning-creeps">B. Spawning Order for Earning Creeps</h3>

<p>When spawning earning creeps like miners, haulers, and reservers (or source keeper killers), it’s important to prioritize sources strategically:</p>

<ol>
  <li><strong>Close Sources First:</strong> Focus on the closest sources first as they are the most profitable.</li>
  <li><strong>Energy Production:</strong> Within each source, prioritize increasing the energy harvested before spawning the necessary haulers.</li>
  <li><strong>Sequential Completion:</strong> Complete one source before moving on to the next.</li>
</ol>

<p><strong>Detailed Spawning Logic:</strong></p>

<ol>
  <li><strong>Iterate Through Sources:</strong> Start with the closest or most profitable source.</li>
  <li><strong>Check for Special Units:</strong> If a reserver or source keeper killer is needed, spawn them and stop iterating.</li>
  <li><strong>Spawn Miners:</strong> If a miner is needed, spawn it and stop iterating.</li>
  <li><strong>Spawn Haulers:</strong> If the current haulers are insufficient, spawn additional haulers and stop iterating.</li>
  <li><strong>Update Hauler Count:</strong> Reduce the remaining hauler count by the number required for the current source.</li>
  <li><strong>Proceed to the Next Source:</strong> Continue to the next source until all are adequately serviced.</li>
</ol>

<p><img src="https://github.com/user-attachments/assets/a6159625-8a0e-4bc2-ad96-1ec259b3820b" /></p>

<p>(Iterate from source number 1 to source number 9)</p>

<h2 id="2-balancing-earning-vs-using-creeps">2. Balancing Earning vs. Using Creeps</h2>

<p>Balancing the spawning of earning creeps (miners and haulers) with using creeps (upgraders and builders) is critical, but the strategy differs depending on whether you have storage.</p>

<h3 id="a-with-storage">A. With Storage</h3>

<p>When storage is available, the strategy is straightforward:</p>

<ul>
  <li><strong>Energy-Based Decision:</strong> The priority between earning and using creeps is based on the energy amount in storage. If the energy in storage exceeds a certain threshold, prioritize spawning using creeps. If it falls below that threshold, focus on earning creeps.</li>
</ul>

<h3 id="b-without-storage">B. Without Storage</h3>

<p>Without storage, the balance requires more delicate management:</p>

<ul>
  <li><strong>Adaptive Metric:</strong> I use a metric that adjusts the priority dynamically. This metric ranges from -1 to 1 and naturally decays to zero over time.
    <ul>
      <li><strong>Priority Shift:</strong> If haulers are unable to find a place to deposit energy (indicating an overflow), the metric increases, shifting the priority to using creeps.</li>
      <li><strong>Energy Shortage:</strong> Conversely, if using creeps are running out of energy, the metric decreases, and the focus shifts back to earning creeps.</li>
    </ul>
  </li>
</ul>

<p>This adaptive strategy helps maintain a balance between energy production and consumption when storage is not available.</p>

<p><img src="https://github.com/user-attachments/assets/9a509e86-3b4e-47da-a55f-9b844ca8c0d9" style="width:100%" /></p>

<p>(I visualized this metric using in-game methods.)</p>

<h2 id="3-hauler-pool-management">3. Hauler Pool Management</h2>

<p>Once haulers are spawned, the challenge is to manage them efficiently. The goal is to ensure that every hauler’s capacity is utilized without wasting travel time or energy.</p>

<h3 id="a-strategy-overview">A. Strategy Overview</h3>

<ul>
  <li><strong>Maximize Carry Capacity:</strong> Avoid sending haulers to sources where there won’t be enough energy to fill their capacity.</li>
  <li><strong>Prioritize Proximity:</strong> Favor closer sources since they yield the same amount of energy with less travel time.</li>
</ul>

<h3 id="b-calculating-expected-energy">B. Calculating Expected Energy</h3>

<p>To decide where a hauler should go, we need to estimate the energy available at each source, considering other haulers that might be heading there.</p>

<ol>
  <li><strong>Energy Piled Up:</strong> Calculate the sum of energy in containers and any dropped energy near the source.</li>
  <li><strong>Expected Energy Gain:</strong> Determine the expected energy gain based on travel distance:
    <ul>
      <li>
        <p><strong>If the distance is less than or equal to the ticks left for regeneration:</strong></p>

        <p><code class="language-plaintext highlighter-rouge">Expected Energy Gain = min(energy piled, harvest power * distance)</code></p>
      </li>
      <li>
        <p><strong>If the distance is greater than the ticks left for regeneration:</strong></p>

        <p><code class="language-plaintext highlighter-rouge">Expected Energy Gain = min(energy piled, harvest power * distance) + (harvest power) * (distance – ticks to regeneration)</code></p>
      </li>
    </ul>
  </li>
  <li><strong>Adjust for Hauler Traffic:</strong> Reduce the expected energy by the amount likely to be taken by other haulers heading to the source.</li>
  <li><strong>Select the Optimal Source:</strong> Choose the closest source with enough expected energy.</li>
</ol>

<p><img src="https://github.com/user-attachments/assets/7fe1813a-1c67-4b3e-acdc-19221d7094f3" />
(While monitoring, visualized table can be really helpful)</p>

<hr />

<p><strong>Conclusion:</strong></p>

<p>In this article, we’ve covered the essentials of spawn management and hauler pool optimization. By strategically managing the spawning process and ensuring your haulers are efficiently assigned, you can significantly boost your early game economy. Stay tuned for the next part of this series, where we’ll dive into defense techniques!</p>]]></content><author><name>Harabi</name></author><summary type="html"><![CDATA[Hello everyone! In my previous article , I discussed how to effectively select remotes to optimize the early game economy. Now that we’ve covered that, it’s time to dive into spawn management and hauler pool optimization. With the right strategy, we can streamline the spawning process and ensure our haulers are operating at peak efficiency.]]></summary></entry></feed>