archive by month
Skip to content

Steamhammer 3.5.11 change list

According to tradition, a new Steamhammer version drops in elo on BASIL at first. It takes around 2 months for changes to settle into the learning data before the elo reaches a new equilibrium. The new AIIDE tournament version has broken tradition and started out with an elo rise instead. It’s an early sign that I may have a successful version.

Last night I uploaded the “bug fix” version 3.5.11 to SSCAIT and SCHNAIL. It has 9 small changes over the tournament version of Steamhammer, a lot more than I planned. Only 3 changes are proper bug fixes. All of them are meant to prevent bad behavior or use resources more efficiently, so they fix play bugs if not code bugs. For debug flags, this time I turned on drawing of not only the clusters but also the combat sim info (drawn alongside the cluster info and in combat areas) and the static defense plan. It makes for a busy display.

operations

Estimate when one of our bases is doomed to be destroyed, so that we can stop spending resources on it. Any code that wants to know can call base->isDoomed(). For this first pass, I made it conservative; it checks a few conditions and does a quick comparison of defenders to attackers to see if the fight is very lopsided. If it says the base is doomed, then it is under attack and there truly is little chance that it can be saved (though you never know, maybe the opponent will do something else). The feature has many uses that I’m sure I’ll get to, but for now only one is implemented (keep reading).

static defense

Don’t add more sunkens or spores at a doomed base. They’ll die too and accomplish nothing. The weakness was glaring; now it should be only staring.

• Limit front-line sunkens versus terran to 6 at most, 5 at other bases. (Against bots, rather than humans, Steamhammer makes at most 1 sunken at other bases, to prevent casual raids. Almost all bots concentrate on attacking the main with its front line.)

• The plan/execute loop runs more often, to reduce the delay in adding defenses when in a hurry.

• The controller could mistakenly order multiple copies of a prerequisite building, like a forge for cannons or an evolution chamber for spore colonies. Fixed.

• There was one last place where a building was posted directly to the building manager instead of queued for production: The prerequisite building. Fixed. It caused no known bug, but queueing the building likely avoids rare problems.

zerg

Fixed a production freeze that was possible when the enemy went mass air. This was an interesting one, because it was a completely different mechanism than any other production freeze I’ve seen. In the unit mix calculation, if the best unit for the mix was devourers and we already had as many devourers as we should, then the code rejected the choice it had committed to. The unit mix fell back on the default, drones as the only unit to make. By the time this happens, it is late in the game and Steamhammer already has as many drones as it wants. So it replaces lost or used drones, makes urgent units like scourge, keeps up with its upgrades... and produces no other units. The fix was to reject devourers up front in that case, so that the calculation finds a different best unit.

• If we have excess minerals and gas, make a lair and/or research burrow solely to use up some of the excess. It happens occasionally, and if the game continues we’ll want both eventually.

• If air carapace has reached +3 and we still have many mutalisks and/or guardians, start getting air attack upgrades too. Might as well, I figured. I uncommented a snippet of code that I wrote years ago, back when Steamhammer’s air upgrades never went beyond +2.

Steamhammer 3.5.10 change list

Steamhammer 3.5.10 is the AIIDE 2021 tournament version. The current version on SSCAIT and BASIL is 3.5.2. The change list covers everything in between. I’ll upload the new version shortly, and source before long.

I wanted to improve lurker play to the point of having working lurker contain skills, but it was too ambitious for the time available. Even so, the improvements to lurker play should be easy to see. I soon decided it would be more effective to work on smaller fixes. There are always many short to-dos that each make a difference... because they accumulate faster than I can retire them.

tournament preparation

• Special preparation against 9 prospective AIIDE 2021 opponents—the ones it might make a difference against, plus Stardust where Steamhammer is at risk of scoring zero. I followed the same preparation plan as last year: For each opponent, choose a small number of builds that have historically won, or that seem to have good chances, and enter them into history as fictional single winning games. Let learning do the rest.

It amounts to giving hints “try this a few times before giving it up.” Steamhammer has a better chance of finding good builds early, and is not weighed down with masses of outdated learning data if the opponent brings surprises.

information

• Remember whether the enemy has used psionic storm this game. I wanted to feed the information into lurker spacing decisions, but ended up not implementing lurker spacing, so the feature is unused for now. There are other potential uses.

static defense

Changes to static defense include tuning to make the right amount in different situations—zerg static defense is expensive, and needs to be worth it. I think the tuning is improved versus terran, fairly good versus protoss, and still weak versus zerg.

• Fixed a crash due to division by zero. The bug fix does not affect strength, because the crash only happened when Steamhammer had no bases left. Yes, it was dividing by the number of bases. How easy it is to forget that you may already be dead! For my part, I forget that nearly every day.

Morph forgotten creep colonies into sunkens or spores, if and when they happen to be needed. The building manager sometimes slips up and forgets to morph a creep colony that was intended to become static defense. If defense is not needed, it will remain a creep for the time being. When the static defense planner decides that it is needed, it may turn into either a sunken or a spore. At some point I’ll implement tactical analysis and Steamhammer will have an idea of when the enemy might attack in strength. Then it will be able to leave all colonies until they are needed.

Try to place spore colonies in the mineral line, rather than somewhere vaguely near the hatchery. This helps ZvZ the most.

• Make one sunken colony less per base, compared to before.

• If the enemy has many tanks with siege mode, sharply limit the number of sunkens. They become a waste of minerals.

• Make more spores versus mass wraiths and mass scouts.

buildings

Anti-cannon sunken reaction failed due to errors in building placement introduced in a recent version. Fixed.

• Other attempted improvements to anti-cannon sunken placement.

• Added configuration option Config::Skills::UseSunkenRangeBug so that I can turn the feature off when it’s not allowed. It’s part of building placement; see BuildingPlacer::getAntiCannonSunkenPosition(). It’s off for AIIDE, where use of the bug is not allowed. It’s on for SCHNAIL, since it’s allowed in human games.

Steamhammer might try to build a macro hatchery directly on top of the main hatchery in the opening. The hatchery failed to build and the drone assigned to build it was left idle for a time, a serious breakdown. Fixed.

• In rare cases, a building might be placed invalidly so that it could not be built. Fixed.

squad orders

• Each squad keeps track of the last time its order was changed to a different target. It also remembers the most recent frame that any cluster of the squad attacked, and the most recent frame of a retreat. (“Attack” usually means that the combat sim said “go attack”, not that any unit fired a shot.)

• The above info is used by the air squad in deciding whether to keep attacking its current target, or seek an undefended target of opportunity. If the last attack was a long time ago and the last retreat was just now, then the mutas are sitting around and should try another target. They look for the closest undefended thing and try that instead. Unfortunately, the closest undefended target is often as inaccessible as the original target—it can be attacked in theory, but Steamhammer doesn’t have the smarts to do it in practice. So far, the feature is not worth the effort I put into it. I think it will become worth it when I implement more pathing and harassing skills.

• In defense, defeat enemy proxy pylons when nothing more dangerous threatens. There was always code to do this, but it was broken in a subtle way. The method for assigning units to squads is too complicated; I’ve got to find a better idea.

• In defense, count an enemy proxy creep colony as 2 units, not 1. When pulling drones to defeat the proxy before it can finish morphing into a sunken, Steamhammer will pull 4 drones and win the fight instead of 2 drones and lose. (3 drones would be ideal, if no other unit interferes.)

recon squad

The Recon squad has been a valuable feature ever since I implemented it. But lately Steamhammer has become strong enough that Recon’s weaknesses are hurting. For example, classically the Recon squad only pays attention to units that it can see, ignoring the remembered positions of enemy units, because its purpose is to see what’s going on. But suppose the squad consists of 1 zergling and it wants to scout an area defended by a sieged tank. The ling approaches to see, gets splatted by the tank. Another ling is assigned, approaches, splatted, etc., until the target times out. The process is, as people say nowadays, unsustainable.

I made 3 changes. None is critical in itself, but together they make the Recon squad safer and more effective and count as an important improvement.

• Combat sim attends to all enemy units, as for other squads, not only visible enemy units.

• When the squad is restored after it has become empty (for any reason, not only losing all units to the enemy), reset its target to somewhere else.

• Don’t assign the squad a target that is already in view. If the Watch squad or an overlord can see the target, the Recon squad doesn’t need to. As always, if no targets need scouting, disband the squad.

irradiated squad

I improved the behavior of irradiated units, but it still doesn’t work as intended. I’m convinced that bugs are hidden somewhere in the infrastructure code, not in the top-level decision code.

• The code was already clean, but I simplified it a little more.

• An irradiated unit keeps farther away from its friends than before. This is the most important change, even though the old distance was already outside the irradiation splash range.

• Flying units seek in a wider radius to find enemy units to splash radiation onto. Mutas are fast and may get there in time to do a little splashing.

• A slight change to burrow decisions.

scouting

• Release the scout worker early in a few special cases: If there is an overlord nearby to continue the scouting work; if the scout runs into a completed enemy bunker or photon cannon. There are details to the conditions; for example, if no enemy unit type has been seen yet beyond those the enemy had at the start of the game, then the scout stays on the job. Steamhammer usually scouts early, and returning the scout is economically good. An enemy bunker or cannon (if not a proxy) means on the one hand that the scout cannot advance, and on the other that the enemy has no intention of attacking right away, so Steamhammer can return the scout now and wait for zerglings to arrive to keep watch.

squad tactics

Don’t retreat forward if the enemy is near at all. The feature was meant to fix the case where one cluster of units is attacking the enemy, while a smaller cluster farther away was afraid to approach because it could not win on its own. But if an enemy was between the two clusters, which could happen despite a triangle-inequality test to try to prevent it, the cluster retreating forward would walk through the enemy and get shredded. Instead, a Regroup cluster close to an Attack cluster is itself changed to Attack in a second pass through the cluster status decisions before they are executed. The failure cases are non-horrible, and the change fixes one of Steamhammer’s biggest tactical weaknesses. At some point I’ll rewrite it so that clusters fighting the same enemies are treated together, not separately, but that’s for the future.

Enemy unit clustering is turned on, so that known enemy units are grouped into clusters just as Steamhammer’s units are. The config option Config::Debug::DrawClusters draws the enemy clusters in red circles to contrast with Steamhammer’s clusters in white circles. The enemy clusters are used in various decisions at the cluster and unit level.

An unhandled case led to poor lurker retreat decisions. I rewrote the code to simplify it and fix the bug.

When retreated all the way to the retreat point, lurkers burrow and tanks siege. Formerly, both remained ready to move, which meant that they were unready if the enemy advanced. It may not sound important, but it’s a big improvement. Indecision between advancing and retreating is common, which causes the familiar burrow/unburrow frenzy, but it’s a net gain by a wide margin.

• When retreating, count a sieged tank or a burrowed lurker as immobile defense, an option to retreat toward. Formerly, Steamhammer only looked for static defense.

• When seeking a cluster ahead to join this cluster with, use the squad’s order distance instead of the air distance. The order distance is the ground distance for ground clusters or the air distance for air clusters. This fixes some poor decisions made by ground units near terrain features.

• The code to retreat behind static defense was rewritten to be correct for a change. The actual behavior doesn’t change much, though.

• Be a little quicker to declare overlord danger at a base, so that new overlords are not spawned there to die uselessly.

combat sim

• The configuration option Config::Debug::DrawCombatSimInfo now draws information for each cluster, rather than for the most recent cluster simulated. It shows both the raw and the smoothed attack/regroup results, so you can see how the raw results flip-flop more. Combat sim is that much more debuggable—still not very.

A bug could leave the combat sim in an out-of-date state. Fixed. The bug (mentioned earlier in Steamhammer is progressing) is responsible for most or all of the 50-100 elo strength loss on BASIL in version 3.5.2. It’s what caused units to sit back instead of, say, attacking an undefended base.

• The radius to look for enemy units to include in the combat sim is altered to match what the Squad code does. I think this is a no-op; the enemy units that end up included are those in range to fire into the combat radius, which is different. But it looks tidy.

micro

Cancel a dying egg, cocoon, or unfinished building 1 second before it is predicted to die, not 5 seconds as previously. Lurker eggs were being canceled almost the moment they came under attack, which was bad. The gain of canceling items later outweighs the loss of a few units that come under sudden massive attack and die before they can be canceled.

• In figuring out which direction to kite a hydralisk, Steamhammer knows not to kite back into its own ground units—they are in the way. But it did not check whether the units were burrowed. Hydras had trouble kiting when near burrowed lurkers, because escape paths appeared to be blocked. Fixed.

terran

• Slightly improve the stim calculation, so that marines overstim a little less. It’s a change made in passing while I was working on other stuff, under the rule “if you see it now, fix it now.” (If it were possible to follow this rule all the time, there would be no such thing as technical debt.)

zerg

Macro: Steamhammer did not always make enough macro hatcheries due to a bug. That hurt a lot. Fixed.

• Macro: Make no macro hatchery unless there are at least 3 drones per base. Yeesh. It sounds basic, but the drone count never entered into Steamhammer’s calculation of whether it needed a macro hatch. This is a lenient limit that prevents rare egregious blunders (which I have seen happen). I expect I’ll tighten it in the future, one way or another.

• Macro: I noticed that Steamhammer sometimes became briefly supply blocked in the early middle game. I tweaked an overlord timing parameter by 1 point of supply, which fixed it.

• Macro: Fixed a potential production freeze related to air upgrades. This is a rare freeze; I'm not sure it has ever happened. When I fixed it, I thought it was a less-rare freeze that can happen when the enemy goes mass air. Then I discovered I was wrong. I have fixed the more important freeze, but not in time to get it into this version.

• Queue sunkens ordered by the strategy boss (as well as those ordered by the static defense boss, a change made in version 3.5.2), rather than posting them directly to the building manager. I never saw the old code cause a problem, but it’s likely that the change fixes rare misbehaviors.

• Queens: Be more flexible about parasiting high-priority targets instead of waiting for a good ensnare or broodling. If there is no tank in sight and the queen suddenly notices an enemy dropship, it should know what to do. A parasited dropship cannot surprise you.

• Queens: Get ensnare much less often versus terran, and a little less often versus protoss. I find the improvement in terran play to be visible.

• Defilers: A defiler that is about to die wants to cast a last spell. It’s done in part by a hit point test. Formerly, if the HP were too low but the enemy was gone, the defiler might (say) swarm itself, then consume, then swarm again nearby because the HP were still low, etc. There was often little or no gain, and the consumed zerglings did not appreciate it. Now the defiler only casts its low-HP Hail Mary spell if the enemy is around to shoot at it. (Being irradiated, stormed, or plagued also brings a Hail Mary.)

Lurkers: Avoid burrowing in tank or cannon range unless friends are along to help. This reduces the tendency of lurkers to rush in where angels fear to tread, though they’re still pretty foolish.

• Lurkers: Undetected lurkers look around harder for dangerous enemies nearby before unburrowing.

• Unit mix: Discourage guardians more overall. Discourage ultralisks and encourage hydralisks versus battlecruisers more. Favor hydras a little more versus wraiths. I think guardians may finally be tuned almost acceptably for Steamhammer’s current poor skill with them.

• Unit mix: When seeing 2 or more starports and no other air units, assume wraiths are likely and nudge the unit mix toward countering them. Steamhammer doesn’t make many predictions, but this one seemed important.

• Unit mix: Dark archons discourage queen production, though they don’t always eliminate it.

• I found that some urgent defensive reactions were happening too slowly. Therefore, first, call makeUrgentReaction() twice as often. Second, when making an anti-cannon sunken, it is allowed to start the creep colony before the spawning pool finishes. (Starting the creep before the prerequisite finishes for the final morph to a sunken or spore was already supported in other cases.)

Upgrades: Better code for ground upgrades. Historically, in long games Steamhammer went for ultra-ling in all matchups, and I wrote rigid upgrade code to match. It got carapace and then melee attack upgrade, and that’s all, correct preparation for the ultra-ling unit mix, with an exception added later for ZvZ to get melee attack first. Today Steamhammer varies its unit mix more sensitively depending on the situation, and may stick with or switch to hydralisks in the late game if they’re called for. I rewrote the code to be simpler and more flexible. In the planning phase, code puts any or all of melee attack, missile attack, and carapace into priority order depending on the matchup and game situation. In the execution phase, code assigns the top priorities to available evolution chambers.

In ZvT, Steamhammer gets missile attack if it is making hydras to fight goliaths or battlecruisers, because the terran is likely to stick with them. In ZvP, Steamhammer likes hydras and usually gets missile attack first and carapace next, though it depends. In ZvZ, with less variety, upgrades are about the same as before, except that there are extra rules if hive tech is reached. To my eye, play is clearly improved, especially in ZvP. Though the behavior is a lot more complicated, the total code size is small and about the same as the old rigid code.

• Upgrades: Fixed a minor bug where Steamhammer thought it could upgrade in an uncompleted evolution chamber. The worst case result was that the bot might slightly underspend its money on this production round.

openings

Overgas+1 build added to use more of that fast gas. Only one new opening! Is it a record low?

Tomorrow: What’s next for Steamhammer?

Steamhammer 3.5.2 change list

I uploaded Steamhammer 3.5.2 to SCHNAIL today. The version fixes the worst of the problems in the static defense code that was new in the previous version 3.5.1. They were problematic problems; Steamhammer dropped 200 to 300 elo. The change list is short.

• Added a new macro location MacroLocation::Tile for placing buildings at an exact position. Now code that knows how to place buildings can post those buildings to the production queue.

• Taking advantage of that, now the static defense code queues buildings to produce instead of dropping them directly into the building manager, as before. The old static defense code never had a problem doing that, but the new code is more capable and hits failure cases. The production manager that reads the queue already does all the work needed to cover those cases, though.

• Zerg more carefully limits the number of static defense buildings it makes. Sometimes it wanted to put down more than the drone count could support.

Meanwhile, for CoG 2021 my parsing code needs updates to read the detailed results file perfectly. This happens every year. It won’t take long.

Steamhammer 3.5.1 change list

Yesterday I uploaded Steamhammer 3.5.1 to SCHNAIL, as Steamhammer, Randomhammer, and Crazyhammer. At least some games today still seem to be running the old version, though. I’m not sure how the details of update work.

This version concentrates on changes to improve play against humans, though I expect some of the changes to help against bot opponents too. The headline skill is new static defense analysis, which should help Randomhammer’s terran and protoss against all opponents, and zerg against humans. If performance is as good as I hope, I’ll soon upload to SSCAIT too. But I expect real games to look different from my test games.

static defense

New StaticDefense module makes decisions about static defense timing and placement for all races. (Special zerg reactions to events like rushes and proxy bunkers still exist, so the new code doesn’t handle all static defense.) The former code was only for zerg. The new code is more general and capable, and simpler in key aspects. It should be easier to work with. Like the old code, it understands that ground defenses at a natural base also protect the main base behind it, and it understands that drops bypass those defenses.

One frame it examines the situation and makes a plan for what anti-ground and anti-air static defense is needed. The next frame it starts to carry out the plan, including building prerequisite tech like an engineering bay for turrets if needed. After a fixed delay, the cycle repeats. The terran plan only calls for turrets; it’s easily extended to make bunkers, but Steamhammer doesn’t have the skills to use bunkers properly as static defense (its only skill is to put marines that it already has into a nearby bunker if the enemy is nearby too). The protoss plan calls for cannons at all necessary places to defend against cloaked units, vultures, drops, and air attack. The zerg plan is comprehensive. It makes one spore at one or two selected bases to preserve overlords if needed, or the required number of spores at all bases to defend against air attack. Steamhammer should do better against mass wraiths and mass scouts, which human players occasionally go for, and better in ZvZ when far behind in mutalisks. Sunkens are concentrated at the front line base versus bots, because nearly all bots go straight there, and spread to all exposed bases versus humans, because humans like to wipe out unprotected bases first. (At some point I want to add a SkillKit skill to remember the opponent’s past behavior, so that Steamhammer doesn’t have to rely on a blanket heuristic.)

The overall effect should be that zerg is resilient in a slightly wider range of situations, while terran and protoss become better able to survive common attacks like DT rushes, mutalisks, and drops.

Detailed building placement is not improved. I did nothing with the building placer to ensure that that defenses cover approaches or buildings or the mineral line, etc. Sometimes turrets are in a tight line, so that half the mineral line is overprotected and half is open. One step at a time.

• To support this, I moved getMySpireTiming() from the zerg strategy boss to the information manager. I also updated it to work in the case where the bot is making more than one spire simultaneously (which it could do if the opening build explicitly codes it). In ZvZ, if your mutas are far enough behind then you have to start preparations for a spore colony before the enemy spire finishes.

• I moved the “front point” for defense from 7 tiles away from the hatchery to 5 tiles away. It helps zerg place sunkens in a tighter group, and should not hurt terran or protoss.

squad orders

• Assign more anti-air defenders when under attack by protoss scout air units. 2 hydras per scout were not reliably enough; 3 should do it.

• Watch squad: In ZvZ, don’t watch as many bases. Expansions are few in the matchup, and the zerglings are more valuable in combat.

• Watch squad: Don’t waste a ling trying to watch a base which is covered by enemy defense, such as a sieged tank or a cannon.

• Watch squad: Smaller combat sim radius—let the enemy get closer before fleeing.

• Watch squad: An unburrowed zergling watching a base tended to oscillate around the base position, rather than sitting still, churning useless commands. When originally implemented, the Watch squad did not misbehave like that. I found 2 bugs born since then, each of which independently caused oscillation: 1. Being at the order point automatically made a unit “near the enemy,” so that it might run away a short distance though not actually near the enemy. 2. In the distances grid used for pathfinding, the grid 0 point could be slightly offset from the true goal position. I decided to allow some tolerance.

micro

Diagonal movement, lack of which I noted as a disadvantage in Steamhammer’s pathfinding. Units often get where they are going faster, which should help in all matchups versus humans or bots. On the other hand, I’ve noticed that the orthogonal movement can sometimes sneak past the opponent’s army and let Steamhammer make a surprise attack. There is always a tradeoff.

Try to stay out of tank range when not actively attacking. Steamhammer mostly keeps retreated units out of enemy fire, but there are exceptions. The worst was leaving ground units nearly, but not quite, outside of tank range; given time, one enemy tank could destroy an entire ground army (common versus humans who benefit from zero-APM passive defense, rare versus bots). I made 2 changes to fix it. 1. A retreating unit checks an attack map to make sure it is out of range; if not, it hasn’t retreated far enough. 2. The combat sim seeks enemies in a wider circle if there is a risk of sieged tanks, so that it doesn’t overlook the enemy and wander back into range “because it’s safe.”

Canceling buildings under construction, as well as unhatched eggs and cocoons, when they are under attack and about to die, works again. I introduced bugs when I “improved” it, causing it to nearly always fail. Now it is both improved and reliable, which (surprising though it may be) is better than either alone. It also cancels earlier, at a predicted 5 seconds left to live, which may be too soon. I’m guessing 2 or 3 seconds might be best; it depends on how accurate the predictions are.

• Bug fix in handling irradiated units: They feared splashing their radiation onto zerg buildings, though radiation does not affect buildings. Buildings apparently have rad shielding. This was a minor bug with trivial effects. I found the bug while searching for known serious bugs in handling irradiated units, bugs that regularly cause severe mistakes in games, but I could not pinpoint any of them. Except for its deadly flaws, the code appears flawless.

queens

Queens are surprisingly valuable against turtling human terrans, so I put effort into improving them. But not much; these are all simple changes. Big improvements need more complicated work (but will happen in time).

• Configured to make up to 8 queens, up from the previous limit of 6.

• Get the queen’s nest a little earlier if we have reason to want queens or defilers, or a little later if we don’t. This should help Steamhammer get queens and/or hive tech sooner when needed, and delay the expense otherwise.

• Get ensnare less often in ZvT. The combat sim understands ensnare reasonably well, but the queens cast it at inappropriate times when it does no good. Broodling is more valuable with Steamhammer’s skills.

• Don’t get broodling if the enemy has too much air-to-air strength. Wraiths and corsairs love to shoot down queens.

• Versus both terran and protoss, a higher threshold to get broodling in the first place, but once the threshold is crossed, a greater number of queens to use broodling. It’s an efficiency improvement.

• Changes to the scoring for queen broodling targets: A bigger bonus for a target which is defense matrixed. A discount for a plagued target. A bonus for a target under dark swarm. A slight increase to the bonus for already being in range, so that the queen doesn’t have to move in.

zerg

Defense against proxy cannons: Attempt to exploit the sunken range bug. This is one of 2 main expert defenses against cannons behind the minerals (the other is to push workers through the minerals to fight). If it can, Steamhammer will place a sunken which is in range of a pylon and out of range of the cannon or cannons that the pylon powers. When the cannon fires on the hatchery (or on anything else), the Brood War bug will cause the sunken to target the cannon even though the cannon is out of range and cannot fire back at the sunken. Use of this bug seems to be universally legal. If it works as intended, it should stop many tries to put cannons behind the minerals (if the cannons are too early, the hatchery will instead be canceled, or never started, and Steamhammer will have to destroy or play around the cannons).

No bot yet has tried to cannon behind Steamhammer’s minerals. Human protoss players do it often. It doesn’t always win, but with the right followup it’s effective.

• Defense against proxy cannon pushes: More often place multiple sunkens versus surrounding cannons. Opponents, both humans and MadMixP, are increasingly creeping cannons around the edges of the defense zone of Steamhammer’s single anti-cannon sunken.

• A high score for a defiler to place dark swarm over burrowed lurkers, and a lower score over unburrowed lurkers. A minor change.

• Adjust defilerScore higher against protoss dragoons. That will make Steamhammer get defilers earlier—see the item about the queen’s nest timing above under queens.

• The remaining zerg items are adjustments to the unit mix scoring. I adjusted existing scoring terms to reflect results against humans on SCHNAIL, adding only one new term. Human players pose unit mix problems that bots do not. ZvT unit mix adjustments: Wraiths more encourage hydras. Valkyries more strongly discourage guardians and encourage devourers.

• ZvP unit mix adjustments: Lower global bias toward ultralisks. All protoss air encourages hydras. Corsairs and scouts more discourage guardians and encourage devourers. Carriers discourage devourers. The new scoring term is that merely having a stargate (which could be an inferred stargate; it doesn’t have to be directly scouted) discourages guardians. Steamhammer has been making too many guardians against protoss, and uses them in a way that’s strong enough against bots, but fatally weak against humans.

• ZvZ unit mix adjustment: Guardians and devourers are both more discouraged in general. They should be rare.

openings

• In many terran and protoss openings, replaced go scout once around with go scout, meaning that the early worker scout stays inside the enemy base if it can. Compared to zerg, terran and protoss have more workers and can better afford to dedicate one to looking at stuff.

Steamhammer 3.5 change list

Steamhammer 3.5 is uploaded to SCHNAIL, and will hit SSCAIT when SSCAIT comes back up. I need to collect more opening data before I can work with it seriously; it is taking longer than I expected. But I still made Steamhammer better.

I have been feeling lazy and haven’t gotten much done, according to me. I’m not sure you’ll be able to tell from this change list, but then again, I haven’t posted to the blog recently or done any of the SCHNAIL analysis that I still want to do. It’s in accordance with my motto: All things in due time, or later.

code

Updated to VS 2019. When I upgraded to BWAPI 4.4.0, I followed the instructions, which said to use VS 2017. I didn’t realize until later that I could go further. This update was worth another 5% reduction in DLL size thanks to better optimization.

• Many files, not all of them, are reformatted with spaces instead of the grotesque mix of spaces and tabs that I’ve been living with out of indolence. Sometimes I think that the inclusion of the TAB character in ASCII in the 1960s has cost more confusion and dismay than the entire Unicode character set has since.

squad orders

• The flying squad has a slight preference to attack the enemy main over other bases. The ground squad continues to prefer to attack the natural, other things being equal.

infrastructure

The ground attack map the.groundAttacks now includes enemy sieged tanks and burrowed lurkers; formerly, it only counted attacks from static defense buildings. The idea is that units which often sit in place should be included in pathfinding for safe paths and minimum-damage paths (which are not implemented yet), while those that move around should be handled by reactive means, at least for many purposes. In the meantime, the attack map does affect other decisions, such as building placement, which will now become smarter (“doh, don’t place a building where it will be in tank range”).

UnitInfo adds a powered flag to keep track of whether a protoss building had pylon power when last seen.

• Unpowered cannons are excluded from the combat sim, using the powered flag. Steamhammer used to be afraid of them, if they happened to be out of sight so that their powerlessness was not apparent.

defense reactions

• Declare that the workers at a base are in danger if the ground attack map says that the command center/nexus/hatchery is in enemy range. This is in response to SCHNAIL games where protoss did the proxy pylon-pylon-cannon trick behind the mineral line (the pylons and minerals block zerglings from the cannon). Steamhammer pulled its workers to safety, but they remained assigned to the base and were not transferred out (they danced behind the hatchery getting in the way). When the workers at a base are in danger, Steamhammer assigns them elsewhere when it can and assigns no new workers to the base until the danger has passed. It should react better now.

• Don’t assign a worker to mine any mineral patch which is in enemy range, according to the ground attack map. It’s common for an enemy proxy to reach part of the mineral line and not the rest. Now Steamhammer will know to abandon the mineral patches that are in danger, releasing workers for elsewhere. If worker self-defense is not triggered, it will continue mining the rest.

• Cancellation of doomed unfinished buildings and units in the egg or cocoon is improved. I originally added this long ago, and it used a simple hitpoint limit because there was no infrastructure for anything better (too low on HP, cancel it). Now it is updated to use ExpectedSurvivalTime(), which adds up the damage rates of the attackers. I expect it to be more accurate at canceling things at the last second.

zerg

AbsoluteMaxWorkers is configured to 65 instead of Steamhammer’s traditional 75. I want to see how big a difference it makes. In the middle game, Steamhammer always aims for its max worker count, which tends to release pressure on the opponent until the late game—watch games and you can’t miss it. It needs the ability to do things like stop drone production at a point where the income and hatchery count are ideal for a given unit mix, and pour on the army production. This change is an experiment to gather some data and help me think about when and how to do that.

Queens are more responsive. Among other points, a queen which is in the process of casting is controlled frame by frame rather than only once every 12 (!) frames. Queens will less often blunder into fire and more often escape after casting. Queens have proved effective in games versus terran with many tanks, so it’s important.

• Defilers are a little more responsive too. The change is smaller. Improving the use of dark swarm would be more important.... Maybe this summer?

If a unit is under dark swarm and no enemy can hit it, it won’t retreat but will keep fighting, even if comrades outside the swarm run away. Units still don’t have the sense to run into dark swarm when they should, but this is a step along the way.

• Fixed: Defilers could repeatedly plague cannons, doing it again as soon as the last plague wore off. They got a constant bonus for plaguing a static defense building. Now they get a proper variable bonus depending on how many HP they expect to wipe off. There is a separate fix to prevent over-plaguing of terran buildings which are already in the red and burning down. Let terran repair it a little first.

Add sunkens or spores in the opening to hold vultures or air attacks. Due to a bug inserted last December, these defensive reactions didn’t happen until Steamhammer got out of its opening book, which could be too late.

• Don’t make scourge at all versus mass corsairs or mass battlecruisers. They’ll shoot down almost all of it, at huge cost in gas and larvas. There are disadvantages to this decision, like loss of drop defense, and I’ll relax it when scourge gets smarter.

• Battlecruisers more strongly call for a hydralisk answer.

• Tanks more strongly contraindicate lurker production. I was still seeing some lurkers even versus mass tanks.

openings

However long it may take, opening selection using data is coming. When it arrives, the advantages of having many builds will increase and the disadvantages will fade. I felt free to add as many ideas as I could come up with.

• Removed 4Scout, which is functionally identical to 5Scout, and added 7Scout 8Scout 8Overscout. 5Scout and 6Scout remain. These are fast scouting builds which leave all decisions to the strategy boss. They can be appropriate when the opponent is unpredictable but tends to play into the strategy boss’s strengths—it does happen.

• Added new 7PoolHarder 7Pool10Hatch 8PoolHard rush builds. Can’t have too many different rushes.

• Updated 8Hatch7Pool 8Hatch7PoolSpeed 8Hatch7PoolBurrow 8Hatch7PoolBurrowB to be more efficient.

Added 9PoolFastLair 9PoolFastSpire 9PoolFastSpireB 9PoolFastLurker, which get the fastest possible lair after a 9 pool. The 9PoolFastSpire variant is more suitable versus zerg, and 9PoolFastSpireB versus protoss forge expand.

Added OverpoolFastLair ZvZ_OverpoolFastMuta, which get the fastest possible lair after an overpool.

• Added Overpool14Hatch, which seems like a good opening stem versus protoss. After the spawning pool it makes 4 drones (not 3) and 2 pairs of zerglings (not 3), then the second hatchery. With appropriate followup, which doesn’t happen yet, it should be fine versus either 1 base or 2 base protoss play. If the strategy boss knew how to adapt properly, I would have marked this as a key improvement.

• Added 11Gas10PoolMutaB 11Gas10PoolLurkerB. When I first added the 11 gas 10 pool build, way back in Steamhammer 1.0, I debated whether to make 2 drones after the spawning pool and before the lair, or 3. I settled on 2, because it seemed safer in ZvZ; the third drone delays zerglings slightly. These minor variants make 3 instead.

• Added 12-11HatchStem, a 3 hatch before pool build which stops after the spawning pool finishes, without making any lings. Steamhammer already has a couple other variants, with specific continuations.

Steamhammer 3.4.8 for AIST S4

I have submitted Steamhammer 3.4.8 to AIST S4. Here is the change list, nice and long considering how long there was to work on it. The deadline isn’t for hours yet, so revealing my Dark Secrets early might theoretically come back to bite me, but... eh, it won’t bite hard. I’m still concealing my specific preparation for these opponents.

I tried for important advances that wouldn’t take long. I think I met my promise that Steamhammer will play a more “lucid” game, but let’s see how many fresh bugs I didn’t notice! The biggest improvements are pathfinding for ground units, smoothing of combat sim results, and more supple lurker behavior. My intention has always, ever since I started Steamhammer in December 2016, been to work on mutalisk micro before lurker micro, because it is more important. But I let it pass for too long, and now other bots have strong muta micro. I’ll get back to mutas (they are still more important), but I always want to do something different from everybody else, and now I want to work on lurkers first.

The irradiated squad is a nice improvement, too. Anyway, read on.

map analysis

• Reject starting bases (as identified by BWAPI::Broodwar->getStartLocations()) which have no minerals; they are no longer considered bases, much less possible starting bases. I think these are always observer slots. The AIST S4 version of Aztec has observer slots. Formerly, Steamhammer accepted whatever BWAPI told it and created a Base object for each one, marked as a starting base. The error had surprisingly little effect on play (Steamhammer is not tempted to expand to valueless “bases”), but it did cause sneaky mistakes. One is that a starting base is assigned a natural if conditions are met, with the result that the center bases on Aztec were considered naturals of some of the observer slots, and that information could be used for certain decisions, like where to make a hidden base. I’m glad I found this by looking at the maps, because the mistaken decisions might have been a nightmare to diagnose!

scouting

• The scout worker is released whenever friendly combat units are near. This is the final relaxation of the originally tight conditions for releasing the scout worker early, which I’ve been progressively relaxing.

• If the enemy has no known anti-air units, send an overlord to each base on the map to keep watch. Formerly, the rule was “if the enemy is not known to have tech to make anti-air units”, which was rarely satisfied outside the early game when there weren’t overlords available to distribute.

squads

An irradiated squad centralizes the code for managing irradiated units and implements fancier behavior. Every irradiated organic unit (the ones harmed by the irradiate spell) goes into the squad, except for queens which have enough energy to cast and defilers after consume is researched—they will try to cast something before dying. Formerly, an irradiated unit that could burrow would, and that was the extent of the reaction (the successful reaction, anyway; mutas had code to separate out an irradiated muta, but it mysteriously broke). Now, an irradiated unit that is near friendly units will burrow if it can, or try to flee from its friends if it cannot. If it is near enemy units, it will approach to expose them to the radiation, and also attack if it can. If neither, it will run and do what scouting it can. Some of the behavior looks questionable, and I suspect bugs, but it’s good enough for now. The reaction of unirradiated units to nearby irradiated units is unchanged—only workers try to protect themselves, others carry on as usual.

• A newly-created squad did not pass along its order to its own micromanagers until it was updated. It was an oversight inherited from UAlbertaBot. The main effect is that a defense squad would not begin to act until exactly 8 frames after it was created, so defense was always a little bit late.

• The debug display for squads now shows two new pieces of information: A # symbol if the squad is using pathfinding, and the squad’s status string. The status string is sometimes unchanging, sometimes informative. For example, the Scourge squad has status Attack or Stand By, depending on whether enemy flyers are targetable.

• There was a minor bug in deciding which enemy unit last-seen location to visit next after all known enemy buildings are destroyed. The fix has little effect.

other ops and tactics

Smooth attack/retreat combat sim decisions over time. I think this is the single most important change. Micro is less jittery and more decisive. I’m leaving out details for today; it’s worth a separate post.

• I found and fixed several more bugs related to spell units. The most important misbehavior was that Steamhammer treated an enemy comsat scan of a base as an attack that needed to be fended off. Every time terran scanned a base, a couple of mutalisks might peel off the flock and head there to defeat the scan. They never failed!

• I added time hysteresis to the defense squads, on top of their existing range hysteresis. After the enemies have been seen off, the squad waits out a time limit before it is disbanded. I was not convinced that the feature helps play, so I set the time limit to only 1 second.

• When a cluster of units is ordered to retreat, it may decide—depending on a simplified geometry calculation involving a risk radius—to “retreat forward” to join with friends. This helps a small cluster join up with a big cluster that is already in a fight. I decreased the risk radius, except in the case where the enemy is terran and has sieged tanks. It should help small clusters retreat forward more often.

• Earlier, I introduced a bug into FAP by adding an incorrect MAX_DISTANCE constant. I had forgotten that the distances are squared. Fixed.

micro

Pathfinding for ground units for calls to the.micro.Move(), the.micro.MoveNear(), and the.micro.MoveSafely(), (but not the.micro.AttackMove()) at the option of the caller. I’ll post details tomorrow or so. It was easy to guess I would do this now, because Medusa is in the AIST S4 map pool, where Starcraft’s built-in pathfinder likes to pile up units at the blocked back doors of the bases.

• A unit trying to move safely (with the.micro.MoveSafely()) does not try to avoid interceptors, only carriers. Trying to avoid swooping interceptors causes erratic movements, not escape movements.

zerg

Lurker behavior is smarter. When I first implemented lurkers in Steamhammer 1.3 in 2017, I found that if they obeyed the combat sim like other squad units, they were nearly useless; they did not understand when to burrow, or where to burrow, or when to unburrow. The SparCraft combat simulator I had at the time did not support lurkers. Steamhammer could not tell when the enemy had detected them. So I gave lurkers spartan hyper-aggressive tactics: Always attack, burrow at max range versus a target that can shoot back and directly next to a target that cannot, and unburrow when no target is in range. I’ve made only minor refinements since, because it worked surprisingly well, especially against terran bots. But the crudeness shows, and hyper-aggressive is often hyper-stupid. A lone lurker would boldly attack a line of cannons. Steamhammer has lost a lot of lurkers for free.

Today Steamhammer is a capable squad commander, and it can judge pretty faithfully when a lurker remains undetected by the enemy and should remain safely burrowed despite (meaning because of) the large enemy force on hand. Lurkers in a defense squad remain hyper-aggressive, so that they do not hesitate to eliminate enemies from the zerg base. Other lurkers now advance or retreat together with the units in their cluster, with some exceptions for retreat (see below) so that lurkers don’t unburrow too often. Lurker play remains clumsy, but it is far more flexible than before, and better overall.

• A lurker that Steamhammer believes is undetected will not retreat as long as it is in range of a target. It will remain burrowed, or it will burrow then and there instead of retreating. I made this change in an earlier version, but it had no effect until now because lurkers did not retreat.

• Failing the above check, if a burrowed lurker is asked to retreat then there is one more check: Will it survive long enough to unburrow? It calculates an expected survival time in frames and compares it to the time to unburrow plus a safety margin. If it won’t live that long, it doesn’t bother unburrowing; maybe it can get a last shot in. I do the same calculation for sieged tanks, with the unsiege time, so that a tank beset by zealots still has a chance for a last shot at some distant dragoon.

• I fixed a bug in the hidden enemies check; it handles an invalid missing ui.unit correctly. I don’t think it makes a practical difference with the existing codebase. The hidden enemies check prevents unburrowing when the lurker is undetected and, if it unburrows, at risk of dying to a cloaked unit, or a known unit out of sight on high ground. This check often (not always) prevents the cycle: Burrow on low ground just in range of a bunker up the ramp -> bunker stops shooting because the lurker is no longer visible -> the bunker is no longer visible to the lurker -> the lurker unburrows -> the bunker starts shooting again and becomes visible -> the lurker burrows....

• When possible, a lurker, guardian, or devourer will morph out of enemy view. When within enemy static defense range, it will not morph at all—at least theoretically; I’ve seen it happen so I think the check is not accurate. Lurkers should more often surprise the enemy, and cocoons should be shot down less often.

An urgent sunken to stop vultures, or an urgent spore to stop wraiths or corsairs, is made quickly, rather than, oh, whenever the bot happens to get around to it, might be any minute now if we’re still alive then. The slowness was due to a bad design decision I made in reworking the code in the SSCAIT tournament version.

Insert a fresh overlord after a spore colony, not before, when making supply and a spore is next in the queue, and similarly for the evolution chamber prerequisite. Formerly, when corsairs ravaged the overlords, Steamhammer gave priority to getting its supply back into the green. The corsairs had only to camp the zerg base for protoss to win.

• When scourge finds that its target is very close, it attacks even if the combat sim says to retreat. Scourge uses a combat simulation, excluding air units, to avoid ground fire. Often it would be on the verge of shooting down a corsair, but a dragoon was a little too close.... Steamhammer has missed a lot of kills that way.

• The defensive sunken versus cannons is tuned slightly.

openings

• There are no new or changed openings, only a change to how one opening is configured to be used. I saw the OverpoolTurtle build, a bot exploit opening that is objectively horrible, played in one game against a human on SCHNAIL, and that was one time too many. I removed it from the matchup and counter configurations, so it should be played very rarely unless it is found to succeed, and almost never against a human.

configuration

• New flag for Crazyhammer. Setting Config::Strategy::Crazyhammer to true causes Steamhammer to choose its openings purely at random from its large library, ignoring anything it may have learned. It’s used for Crazyhammer on SCHNAIL.

• New debug flag Debug::DrawLurkerTactics draws the name of the current default lurker behavior, either “Aggressive” or “With squad”. It doesn’t convey any information at the moment, since whenever there are lurkers they are “With squad”. I plan for lurker behavior to become more varied and complex, and then the debug flag will be useful.

unused stuff

• The movement sim is included and potentially valuable, but unused. There is code in FAP and in CombatSimulation.

• Fixed a primordial crashing bug in enemy unit clustering, making it also potentially valuable. But it’s turned off for now.

Next: Pathfinding.

Steamhammer 3.3.5 change list

Here’s what’s new in Steamhammer 3.3.5, which is the SSCAIT tournament version. Play is visibly improved with this version, and I expected a significant improvement in results, but if so it’s not showing. Santa came by, and Steamhammer’s web page is updated with binary and source downloads.

production

The “build beside the base” bug (mentioned here) is fixed. It’s a damaging bug and the fix is critical, but the issue that learning hides bugs means that damage will be ongoing for a while yet.

Building manager can construct sunkens and spores when ordered, carrying out both steps itself. Formerly, laying down the creep colony, and then morphing it to a sunken or spore, were separate steps that had to be queued as two distinct items. Further, there was no connection between the queue items, so sometimes a creep colony intended to be a sunken instead became a spore, and vice versa. The change ensures that you get the static defense you ordered when and where you want it, and simplifies other code so that future features will be easier. The implementation is not perfect; a game against Stone shows that it can go wrong when the spawning pool is destroyed and has to be replaced.

• Fixed a production bug that prevented research from being done in a hive or greater spire. The result was a production freeze, so this is a critical bug fix, though the bug was rare. When I updated to BWAPI 4.4.0 I ensured that research could be ordered in a hive or greater spire, as newly allowed by the BWAPI version, but since my mind is a steel trap I was not clever enough to verify that the research succeeds.

scouting and information

• A terran scan counts as mobile detection. For some decisions, like how useful it will be to make lurkers, having ever seen an enemy scan counts the same as having seen a science vessel or an observer—it means the enemy has the tech. (The question “does it look as though this location is in range of an enemy detector?” is different and was already answered in version 3.3. See UnitUtil::EnemyDetectorInRange(), which did not need any code change under BWAPI 4.4.0 to notice enemy scans.)

• I was annoyed by games where Steamhammer’s drone scout was stopped by a bunker or cannons at the enemy’s front, and since it was unable to move forward, stuck there for the rest of its life as the game continued around it. Must scout—can’t scout—do nothing—die young after a wasted life. I added a rule to release the worker scout in that situation once friendly combat units arrive to keep an eye on the front. It will help the economy and my mood.

overlords

• Formerly, overlords not needed for any other purpose were assigned to wait at Steamhammer’s front defensive line, where the primary sunkens go if there are any. It turned out they were too vulnerable there; sometimes masses were shot down before they could escape. Now one overlord is assigned to the front line, and leftovers are sent to the current “main” base, where they are less available but safer. Occasionally the main base changes and they undertake a mass migration, but I haven’t seen it cause a problem.

• Assign overlords to watch island bases, when it is safe and with a low priority.

micro

MoveSafely() is smarter. Its purpose is to move a unit to its destination while avoiding enemy attacks. Now a moving unit in danger from enemy mobile attackers seeks nearby friendly units that can defend it—an air unit seeks anti-air defenders, while a ground unit seeks anti-ground defenders. It works by clustering all potential defending units, and looks for a cluster that it can reach. (Clustering is done centrally by the ops boss, on demand, and cached for the frame. A common case is that many overlords are independently moving safely, so that clustering is more efficient than seeking defenders unit by unit. It also provides more information for the decision, like how strong the cluster is.) If it doesn’t find defenders, or if it is in danger from a static building that can’t chase it, then it retains the old behavior of fleeing directly away from the attacker.

MoveSafely() has a safety margin. The margin is wider for a worker, and for a unit that has no regular attack (like a flying detector or a spellcaster). This is a big improvement that makes overlords safer. It has more effect in practice than the above change of seeking defenders. The reason there was no safety margin before is that I forgot it—I let myself be interrupted before I had entirely finished the feature. Concentration is important!

zerg

A bug caused gas mining to go severely wrong in a small proportion of games, persistently mining gas when it needed minerals more, a weakness that I originally fixed in version 1.0. In one game, only 3 drones survived and all of them mined gas the rest of the game even as gas built up to 8000 and minerals were out. I didn’t pin the cause down 100%, but the only code that could have caused it was a check that said “hey, I have too many drones and some are idle, there’s no loss in mining gas whether I need it or not.” I commented out the check, which never worked quite as intended anyway, and I haven’t seen the bug since. The ultimate error is likely in the worker manager.

All-new spore building code fixes further spore placement bugs beyond what the building manager changes fix. It is rather a lot of code change for a small behavior change, but the new code is more general and modifiable and future improvements will be easier.

• Limits on making sunkens and spores are slightly altered. Sunkens to protect against vultures and dark templar are possible minutely later in the game. It is a little more willing to add a spore despite already having a spire to defend with scourge.

• The building placer is a tiny bit smarter about sunken placement to stop cannon rushes and bunker rushes. I don’t notice any practical improvement.

• Steamhammer rarely had more than 1 queen on the map, though it is configured to keep up to 6 and often decided to make more than 1. Something is not right in the strategy boss. I switched it to make queens in batches, as resources allow, rather than one by one on each call “what should I make now?” Now it reaches as many as 2 queens on the map... there is still a bug somewhere. 2 queens are not an efficient number for broodling.

• Minor updates to support multiple defilers. Formerly, Steamhammer never made more than 1 defiler at a time, in part because defiler micro is cpu intensive (it was much more cpu intensive before I fixed its original bugs). I noticed that some opponents were quick to target the defiler, and killed defilers reliably so that little defiling occurred. Making more defilers, currently 2 at a time, is my attempt at a quick fix. It may help, though from games so far I think not much.

There is a small update to the strategy boss, to order more defilers up to a limit. Also, if the enemy is nearly dead, don’t make more than 1 defiler; it won’t be useful. Trivial changes to the micro controller for defilers, MicroDefilers, slightly improve efficiency; it already supported multiple defilers.

• Small adjustments to ZvZ counters in the strategy boss. Nobody will notice.

configuration

Config::Debug::DrawDefenseClusters draws the air defense and ground defense clusters used by MoveSafely() to find defenders to flee toward. A unit that can shoot both air and ground will belong to both an air defense cluster and a ground defense cluster. Static defense buildings are included in the clusters, so that (for example) an overlord fleeing a corsair may take refuge with a spore colony.

Config::Skills::MaxDefilers is added. It’s currently set to 2.

openings

• Added 9PoolSpeedSpire.

• Two related but different openings were named Over10HatchHydra. Oops. I renamed one of them to Over10HatchHydraB.

Steamhammer AIIDE 2020 version change list

Steamhammer 3.2.19 (you did memorize the version number as I required, yes?) is uploaded to SSCAIT. Randomhammer too, since a few quick games did not turn up any new bugs in terran or protoss, untested while I worked on zerg. I worked on basic skills (saving my tricks for later), smoothing some of Steamhammer’s long-standing jagged edges, and the bot is appreciably stronger. I’m excited to see how Newfangled Steamhammer copes with the great variety of opponents on SSCAIT and BASIL. Will the anti-cannon procedures work against Krasi0P? I didn’t test it, that opponent is not in the tournament. This Steamhammer has a lot of new fangling, there is sure to be some surprising interplay with other bots.

The SSCAIT upload is the same code and configuration as the AIIDE version. Since the configuration is the same, none of the debug display options is turned on (don’t want that for a tournament), so there’s no interesting drawing on the screen. However, the learning files that I prepared for AIIDE are not carried over to SSCAIT; I’m leaving the existing learning files in place. From experience, I expect that Steamhammer will perform worse on SSCAIT and BASIL for some weeks until the opening learning adjusts to the new behaviors—and to the opponents’ changed reactions to the changed behaviors.

I divide up the changes by the aspect of Steamhammer they affect, as usual. It may be a mistake, because it conceals how teams of changes are coordinated to meet goals. There are teams of changes which work together to help Steamhammer survive cheese, and teams which work together to reduce wasted units during the midgame. The different changes in each team are in different parts of the code, and I write each one up separately, but the important thing is that each team pulls its oars in synchrony.

Today’s list bundles together all the changes I made in versions 3.2 through 3.2.19 (20 versions in all). The test versions had short lifetimes, some of them a day or less. As usual, the more important items are in bold.

Whew, I needed the extra day to have any hope of writing up this, er, nearly endless list by today. I started it on Tuesday, worked on it all day yesterday, and didn’t finish until now.

safe movement

Micro::MoveSafely() is a drop-in alternative to Micro::Move() for use by units which prefer to never come under enemy fire. It follows the simple method of running away from the nearest dangerous enemy, gaining 80% of the benefit of optimized hazard avoidance with 20% of the effort. If you know what to look for it’s easy to see cases where it makes a worse decision than potential fields would, but you have to look.

Overlords use MoveSafely(), except for squad detector overlords which already have their own way to avoid danger. Formerly, one of Steamhammer’s great weaknesses was that it would generously donate overlords to the enemy cause. Sometimes it would try to transfer an overlord to a distant base when an enemy army happened to be on the path, fail, try again.... In the worst cases, overlords would appear to converge from all sides on a group of marines or dragoons as if they were flying ultralisks closing a surround. That is all gone. Overlords are lost at a reasonable rate and live longer, more fruitful lives.

Workers also move safely using some of the same code, though the implementation is more involved than MoveSafely() because of the special needs of workers. Micro has a suite of helper functions. There is one exception: When moving to construct a building, just go there. The scout worker does rely on MoveSafely(), and it has become more adept at surviving to see what is going on. Overall, it’s a clear benefit. When zealots raid, the workers scatter and have to be chased down, at worst causing delay to the enemy and at best surviving to return to mining.

If burrow is researched, workers burrow to avoid danger instead of running away, unless an enemy detector is seen to be in range. This behavior is a delight to watch. Zealots raid, or a reaver lands—and the enemy sees nothing but puffs of dust as the workers disappear under the ground. After the attack is cleared, the workers pop up and instantly return to work. Steamhammer still loves to transfer workers across the middle of the map where the enemy is roaming, but now the workers realize the risk and burrow for safety. The enemy may like to scan when it sees units burrow (Steamhammer terran does that), or may have an observer which was out of range when the workers burrowed but can be brought over, so it’s not entirely safe, but it’s a breakthrough compared to the former behavior of running willy-nilly into the grinder. Also if the enemy moves away a bit the workers may unburrow, try to continue, come too close again and reburrow—which is funny if nothing else.

Overall, safe movement is a huge gain. There is room to make it far better yet, but that will take incremental refinement over time. There are disadvantages in certain situations. For example, when there is only one base and it is raided, then the workers flee or burrow and there is no mining whatsoever to fuel production and defeat the attack. It might have been better to keep mining and accept the loss of workers. Terran could do something like send 1 wraith to each mineral line and stop all mining, and in fact I have seen Steamhammer lose in similar ways.

scouting and overlord assignments

Every overlord is assigned a location to move to and stay at. These parts are unchanged: One overlord is under the control of the scout manager early in the game. Some overlords are assigned to squads to serve as detectors and provide vision. The remaining overlords belong to the Overlord squad. What is different is that the Overlord squad assigns a location to every overlord it controls. Formerly, the Overlord squad assigned locations to some overlords and left the remainder floating wherever they happened to be, which might be in the middle of the map. It was not efficient scouting, and it was not safe for the overlords (but it was easy and I got it done).

The Overlord squad has gained a general assignment system similar to (but simpler than) what I plan for the deferred Scout Boss. It lists useful overlord destinations in priority order, then assigns the closest available overlord to each destination in order. If there are leftover overlords, as there generally are by the middle of the game, the remainder are sent to the front line of the front base (both “front” ideas are detailed in sections below)—basically, they wait together in a clump near where the enemy is likely to try to attack. It’s a reasonable try because the overlords use MoveSafely() to flee dangers.

• Early in the game, one overlord is assigned to survey the main base for hidden proxies. It uses the new function MapGrid::getLeastExploredNear() to repeatedly find what place inside the starting base has least recently been seen, and goes there. The result is that the overlord flies an irregular, adaptive, hard-to-predict and fairly efficient search pattern (and it takes literally 2 lines of code inside the Overlord squad thanks to the infrastructure). I was inspired to add this by a game versus Ecgberht where the terran built a hidden proxy factory in a far corner of the zerg base, a strategy that has earned it a lot of wins over Steamhammer. Typically Steamhammer has no idea that vultures are appearing in its base because of a proxy and fails to defend effectively, but in this game an overlord accidentally scouted the factory and Steamhammer crushed the proxy brutally. It was a short step to scout on purpose.

• If the enemy has no mobile anti-air units (somewhat uncommon), then an overlord is assigned to watch the enemy natural. Further overlords are assigned to guard our bases against cloaked units, just as formerly. If the enemy has transport and does not have flying overlord hunters, the main base scouting pattern restarts to watch for drops. If the enemy still does not have mobile anti-air units (rare by the point there are enough overlords for it, but possible versus Stone, versus a persistent zealot rush, versus a zerg going zerglings, or very late in the game after the enemy’s army is wiped out) then overlords are assigned to watch every base on the map. As always, if there are flying overlord hunters then overlords congregate at spore colonies instead. There is a lot of room to make strides in overlord deployment; future Steamhammer versions will do things like find overlord perches where they can watch without being seen.

• The scout manager also controls its overlord somewhat differently. If an enemy turret, cannon, or spore colony appears in range of the overlord (generally when it is in the enemy base), then the overlord is immediately released from scouting duty. It is reassigned either to a combat squad or to the Overlord squad, and in either case attempts to safely make its way to a new destination. (I wanted to have it cruise around the edge of the enemy base to keep scouting, but it was too much for now.) Releasing the overlord loses scouting information, but losing the first overlord this early in the game is a severe setback and it was happening too often, so I think it’s the correct trade. If the overlord remains safe in the enemy base, however, it no longer sits still over the enemy resource depot but instead scouts the enemy base in a * pattern: It goes to the depot, then calls MapGrid::getLeastExploredNear() to find another place in the enemy base that it needs to look at, then returns to the depot, etc. That way it regularly revisits the most important spot, but also pokes into the corners of the enemy base so that it sees more.

• Squad overlords, or properly squad detectors since science vessels and observers are handled the same way, are also controlled slightly differently. The flying squad detectors have long had abilities to avoid dangers and seek out cloaked enemies, and they could try to protect themselves from air attackers by seeking friendly units that can shoot air. Now, rounding out their skills, they also try to protect themselves from ground attackers by seeking friendly units that can shoot ground. We’ll see how well it works!

building construction

Critical bug fix: It was possible for the building manager to accept a worker for a construction job while the worker manager believed that the worker was still available for other tasks. Ouchies. The worker was alternately given conflicting commands and achieved nothing. The building it was supposed to construct was hugely delayed or canceled, a game-risking error.

• When choosing a hatchery to morph into a lair, if possible choose a hatchery that is away from enemy units. For example, if there is a scout circling the main, start the lair in the natural where it won’t be seen right away. I wanted this to be a first step in denying and delaying information to the enemy. I wanted to also place other tech buildings out of enemy view when possible and safe (they’re constructed rather than morphed so it takes different code), but I didn’t have time. I did add UnitUtil::IsTechBuildingType() so that Steamhammer can distinguish tech buildings from other buildings (to also eventually be used in prioritizing buildings to destroy in an enemy base).

• Bug fix: When a worker was handed over to production manager or building manager to construct a building, for 1 frame it would be given 2 inconsistent commands, one from worker manager before the reassignment and one from the production manager (to move into position) or building manager (to start construction) after reassignment. I solved it by the simple expedient of running the production manager and building manager before the worker manager, being careful to comment the change so it is not later undone by mistake. The result is that the worker is able to follow its movement or construction command one frame earlier, so the building starts sooner by one Planck time.

• The production manager replaced a worker requisitioned for construction if the worker was locked down, stasised, or maelstrommed before it could be handed off to the building manager. Now that workers often burrow for safety, it also replaces a worker which it finds to be burrowed. The building manager by oversight did not replace a worker which was rendered unable to build (only a worker that was killed). The oversight is fixed; now the building manager also recognizes lockdown and the others. Buildings should construct more reliably in the face of enemy interference.

• The worker manager’s setBuildWorker() no longer takes an unused building type argument. I should have gotten rid of that long ago.

plan recognizer

The plan recognizer work focuses on detecting early shenanigans by the opponent so that Steamhammer can react in time this game, or failing that, choose a safer opening next game.

Recognize an enemy Contain opening plan distinct from the Proxy plan. The details of what counts as Proxy are changed accordingly. The general idea is that a proxy requires an immediate forceful reaction, while a contain should be dealt with more deliberately. This means that the configuration file can include Counter Contain openings which are different from the Counter Proxy openings (see the new openings below). Zerg also reacts somewhat differently in the two cases (see the zerg section).

• The code to recognize a proxy is moved from Bases to OpponentPlan where it belongs, and combined with the code to recognize a contain.

• There was a crashing bug in recognizing a proxy on a map where our starting base had no natural base. Every starting location on every competitive map has a natural, so the bug never occurred. But it’s fixed.

• Do not recognize a gas steal as a proxy. Oops.

• A nearby enemy forge implies that cannons are coming; there is no other reason to build a forge in or near the enemy base. (Well, theoretically it could be part of a wall, but what the wall be for? MadMixP and Steamhammer itself as protoss both do proxy forge into cannons sometimes.) Recognize a proxy forge as a Contain plan. This is not always strictly correct; sometimes the predicted cannons would be better recognized as Proxy. But good enough.

Enemy Fast rush and Worker rush plans are recognized more accurately by using building completion times (see when will that enemy building complete?) and unit travel times (by shortest-distance ground paths—I did mention that Steamhammer has all the parts for pathfinding except actually following paths) to better constrain the true timing of events. I always meant to do this, and now I’ve gotten around to it. The work includes tuning the time limits (“earlier than this is a rush”) based on timing the slowest builds that I want to count as fast rushes, versus the fastest builds that I don’t want to count.

• There was a potential crashing bug in recognizing a rush. I don’t think it ever happened, and now the bug is fixed so it won’t.

Explicitly recognize terran BBS as Fast rush. It was a loophole. Steamhammer might fly its first overlord directly over 2 center barracks... and fail to react, and lose. That won’t happen any more.

Recognize a new Wraith opening plan so that Steamhammer is less often caught off guard by 2-port wraith openings. This gives a chance to react earlier to incoming wraiths and lets you configure Counter Wraith openings. Steamhammer is not reliable at recognizing wraith openings before the wraiths show up, though, because its scouting and plan inference are not good enough. I wanted to improve that, but ran out of time. Steamhammer’s anti-factory hydra-first openings are intended to protect against wraith attack but are not successful in practice because AI-controlled wraiths outmicro the hydras, which don’t have either speed or range yet. A hydralisk needs its range upgrade to equal the weapon range of a wraith.

bases

Always unreserve tiles of a base we failed to take. Formerly, sometimes the base would remain reserved and could never be taken. On the one hand, that was a severe weakness. On the other hand, it created adaptivity in choosing the next base to take; repeatedly failing to take the same base over and over is not a winning plan.

Avoid taking a base where enemy units are thought to be. This is a cheap way to add back some of the adaptivity lost by the previous change. Steamhammer does nevertheless sometimes show perseveration in failing to take a base. The next step, for a future version, is to check the path a worker will take to reach the base, and only accept paths that seem safe.

The “front line” position of each base is smarter. The front line is where static defense is positioned when Steamhammer wants to defend the approaches to the base. (It may also place static defense directly next to the resource depot if it wants to defend the mineral line specifically. It depends on the goal.) The front line is now on the shortest outside ground path toward the base, which I figure is the path an enemy bot is most likely to send its attackers along. Compared to the previous calculation, the new front is much better on some maps (like Benzene and Roadkill) and slightly worse on others (like the top base of Destination, though not the bottom base). It’s a net gain.

A zerg base doesn’t become the “front base” until it completes, because zerg needs creep to build. The front base is where the main approach static defense goes; it is the natural base if the natural is taken. Formerly, Steamhammer might place defenses in the main because there was a hatchery morphing in the natural and the main was where it was able to build—yeesh. For terran and protoss, the natural need only be started.

Don’t try to take an enemy base as a hidden base. If the enemy has not been found yet, and we need to choose an expansion as a hidden base, do not choose any main or natural base (unless that’s all there is), because it might be the enemy’s and that would suck. This is critical if the enemy is following a Contain plan, because then we will try to take a hidden base early without scouting.

• Make a stronger attempt to expand toward the edges, leaving central bases for later. The code proudly flaunts it as a big change, but it is not particularly successful; Steamhammer still likes bases in the open middle on maps like Aztec and Fortress. I probably have to bite the bullet and do the tactical analysis of the ease of approach and the width of the attacking front to figure out how vulnerable a base is.

• Fixed: The global pointer “what is my natural?” and the local pointers “what is the natural of this main base?” might be inconsistent. I don’t know what the effects of that were, but it couldn’t be anything good. As part of correcting it, I simplified and improved the calculation of natural bases. Also, each Base object (each base on the map) now includes a backpointer to its main base if it is the natural of some main (or null if not). It makes some calculations easier.

• Fixed: There was a crashing bug that affected maps on which every base which had minerals was a starting base. That’s very rare, but Crystallis is an example. Though I doubt any bot can play a reasonable game on Crystallis....

squads

Don’t assign base defenders against nearby cannons. This is part of the system to defeat cannon rushes: Combat units should go destroy the enemy base instead, which some of them should be able to do if a zerg hidden base was created as planned. The system doesn’t work perfectly, and sometimes Steamhammer wants to attack the proxy anyway because defenders are still assigned to attack the proxy pylons and any other buildings that may be part of the proxy. But most of the time it works well for a cheap hack.

• The hysteresis in distance for unassigning base defenders is increased. The main visible effect is that an enemy scouting worker has to run farther away before the single zergling assigned to catch it gives up and heads away.

• The Watch squad no longer assigns overlords to watch bases to catch enemy activity. The Overlord squad is responsible for that now; see above.

• I tried adjusting the regroup position (aka retreat point) of Steamhammer units that retreat toward static defense. It didn’t really help.

other infrastructure

• The movement routines in the Micro module check their arguments and drop movement commands for illegal destinations outside the map bounds. After an arduous campaign, I have finally fixed all the diverse callers so that they do not issue those commands in the first place. In long tests, the error checks were never triggered.

InformationManager::getUnitInfo() fetches the UnitInfo for a single unit (recording where and when an enemy was last seen, among other data). I never needed it before; in the past, Steamhammer only wanted to iterate through all unit info records.

• Due to an error in interpreting the configuration file, AbsoluteMaxWorkers always had its default value of 75, ignoring what the config file said. Fixed.

• The code for UnitUtil::GetUncompletedUnitCount() is simplified. Now it simply subtracts the already-computed completed unit count from the already-computed total unit count.

other worker behaviors

When a worker is posted to a location, it remembers not only its macro location as it used to, but its actual map location, and stays there. This is part of the system for taking hidden bases: When you go post worker @ hidden the “hidden” location differs depending on where the enemy base is. When we take a hidden base to counter a Contain plan, we may post the worker before the enemy base is found. If we find the enemy base before starting the hidden hatchery, the map location corresponding to the macro location changes, and at first the drone would waste time and take unnecessary risk moving across the map. Now the worker stays put at the original map location and the hidden base is taken safely and on time.

• When a worker is posted to a location using go post worker @ it first returns any minerals or gas it was carrying. A tiny mining efficiency tweak.

• Steamhammer can mine out blocking mineral patches with non-zero mineral amounts. Not many maps have those, but it was a two-line change that makes more maps playable. The code to mine out the more common zero-amount blocking mineral patches, as seen on Destination and Heartbreak Ridge, has been in there for a while. (There is still no code to break down blocking buildings as on Benzene.)

ranged unit kiting

In my mind this is one change with several parts to the code, but the effects vary depending on the ranged unit. For one thing, air units and ground units kite differently because ground units have to worry about terrain or other units getting in the way. For another, Steamhammer kites what it calls “AlwaysKite” units (not a good name since they don’t in fact always kite) with different code than others. The AlwaysKite unit types are set by Micro::AlwaysKite() and are vultures, wraiths, and mutalisks—fast units with instant acceleration—plus guardians. (By the way, the rate of change of acceleration is called “jerk” so instant acceleration means infinite jerk: those units are infinite jerks.) The AlwaysKite units use “muta dance” kiting code which pays closer attention to timing and latency than the regular kiting code, so that kiting is more precise and takes advantage of the instant acceleration.

• A suite of new routines appeared in the Micro module, for use both in kiting handled inside Micro and by other unit control code as needed. For kiting, the key ones are kiteBack() for kiting regular units, and the more generic fleeEnemy() used for AlwaysKite units.

kiteBack() for regular units considers alternate kiting destinations if the first try doesn’t pan out, according to checks I list below. The effect is that if a unit cannot or should not kite directly backward, it may go diagonally backward or sideways. A unit that is unable to kite away will realize it and keep shooting in place.

• Regular units, air or ground, don’t kite into enemy static defense range. If they’re already in range, they don’t kite deeper into enemy static defense range—the check counts the number of attacks on a prospective kiting destination and rejects it if the prospective count is higher than the current count. It’s relatively rare to fail this check; units are not often backed up against enemy static defense.

• Regular ground units do not kite into terrain.

• Regular ground units do not kite into a tile occupied by any other ground unit, whether a mobile unit or a building. The check is conservative: You might be able to squeeze in there if it fails, but if it succeeds you can definitely go there.

For zerg, the changes primarily affect hydralisks. Hydras used to kite into terrain or into each other as an everyday matter, with the result that they would turn away from the enemy, fail to move because they were blocked, fail to shoot because they were trying to move, and generally be useless and die in vain. To me it was a raging unmissable micro blunder that left hydralisk potential bleeding on the ground. Sideways kiting helps hydras keep moving and spread out so that more of them can fire. Hydras still often get backed up to where they can’t kite, but now they know that they can’t kite and they keep shooting. Hydras do more firing and less dying in battles of every scale, for battles in which kiting happens (Steamhammer units kite only when they expect a benefit). To me it is particularly obvious in small-scale hydra versus zealot fights, which are visibly more efficient.

• The AlwaysKite units don’t do the above checks, but call fleeEnemy() which unconditionally moves away, making sure only that it stays within the map bounds. Slightly complicated unimportant details follow. The muta dance code inherited from UAlbertaBot figures where to kite back to using a function called GetKiteVector() which starts with a point to move away from and calculates the destination by trigonometry. It returns an offset from the kiting unit; add the offset to the kiting unit’s position to get the destination. At some point I apparently mistook the offset for an absolute position and clipped the offset to the map bounds, a teeny-tiny gargantuan boo-boo (the effects on kiting were not severe in practice). More recently, Steamhammer added a function DistanceAndDirection() which, though I didn’t notice it at the time, does the same calculation by the mathematically equivalent method of normalizing the offset vector to length 1 then multiplying it by a scalar. Though it doesn’t make a practical difference in games, the vector math runs much faster than the trig functions, so here is an example of the optimization technique of strength reduction. In working on kiting I noticed the overlap. After undoing the mistaken clipping, I verified by test that the two routines returned identical results to the pixel. Following the motto that strength reduction makes you stronger, I removed GetKiteVector() in favor of fleeEnemy() with the same behavior and less code. By the way, it could be that kiteBack() would be more effective, especially for vultures. It does support air units. I didn’t try it yet.

zerg

Place a sunken to stop a cannon push. If photon cannons are dangerously near one of our bases, place exactly one sunken to prevent them from creeping closer; set it as close as possible outside the range of already completed cannons. This stops most approaching cannon pushes in their tracks. It may be possible for the cannons to circle around outside the sunken’s range and push in regardless, but I’ve only seen that once. The calculation of the cannon’s range is not exact, and on rare occasions the sunken is placed too close, which leads to suicidal placing of the same sunken over and over.

Place a sunken to combat a bunker attempt. If the enemy has built a bunker near a base of ours, try to set a sunken where it can hit the bunker and the bunker cannot hit it. Again, the calculation is not exact and occasionally the sunken is too close (it’s usually good, and I’ve never seen it too far to hit). Also, by the time the sunken is up generally the terran has marines on site, and with good play the marines may kill the drone, or may kill the sunken before it can finish. It won’t just happen; terran has to play well, and zerg should smash clumsy bunker attempts. If the sunken does finish, the bunker play will normally fail and terran will be behind; even if terran kills the natural hatchery, zerg will be comfortably ahead because of the cost of the early barracks plus bunker. (Seriously! I’ve seen it repeatedly versus Halo by Hao Pan.) I concluded that the old school sunken is Steamhammer’s best defense for now, though it’s not the best possible defense. The modern standard way to defeat an early offensive bunker is to pull drones to prevent the bunker from finishing, or prevent marines from getting in. Steamhammer doesn’t have the micro skills yet.

• When placing its one-sunken-per-base to defend against raids by vultures or dark templar, Steamhammer normally places the sunken next to the hatchery to defend the mineral line. In a change, if the base is the natural of some main base, it places the sunken at the front line position instead. That way the sunken provides some protection to both the natural and the main behind it, and if later sunkens are placed then they will also be at the front line and reinforce each other.

Hide a drone on the map versus Contain or Proxy plans by the enemy, and when it is next time to make a hatchery, let it be a hatchery at a hidden base. This is a reaction to a recognized plan: The openings for Counter Contain make a hidden base while the openings for Counter Proxy do not, but the reactions to both call for a hidden base. If there is a scout drone out at the time, then it abandons its scouting mission and hides on the map; otherwise a fresh drone is sent out (which is riskier because it may be caught by, say, containing cannons). Versus Contain, Steamhammer continues its planned opening; versus Proxy it breaks out of the opening unless an early pool is already queued, so that it can react decisively. There remains a weakness versus early bunkers: If Steamhammer scouts the barracks first, it may recognize the plan as a fast rush, in which case it will not update the recognized plan after the bunker starts, and will react differently than intended.

Scourge no longer attack floating buildings. This is a fix for a regression. Wasting gas to set a floating ebay afire is an effective way to suffer.

• If an enemy Wraith plan is recognized, make an evolution chamber right away. Before the Wraith plan was added, Steamhammer waited until it actually saw a wraith. Now it at least has a chance to react in time to 2-port wraiths.

• Unit mix adjustments: If the enemy cannoned us in, favor hydras much more. Vultures more strongly contraindicate zerglings. Versus protoss, favor mutas more; Steamhammer was barely making any after the opening, sometimes building a spire and never using it. Protoss air units more strongly discourage guardians; it was too common to see the guardians countered by corsairs.

• Unit mix in the cleanup phase of the game: If all enemy buildings are unreachable by ground, prefer air units. This could mean the enemy has an island base, or it dropped buildings on a plateau, or its buildings are floating over water. This rule doesn’t outright require air units, because the enemy may still have an army in play.

• Be slightly slower in some cases to take the second gas. It’s a tiny step.

• A regression prevented Spawn Broodlings from being researched, so the skill was never used. Fixed. Tanks or high templar may find themselves abruptly dead.

• In a rare ZvZ where the enemy has lurkers or ultralisks, be quicker with broodling research and prefer a higher number of queens. Queens versus ultralisks = advantage queens. It’s fun to be ready with a correct reaction to a rare situation. Steamhammer has played some successful and entertaining games by being more ready than its opponents for unusual events like hive-tech ZvZ.

• If the enemy is attacking on the ground and you happen to have extra minerals and larvas on hand, then maybe, just maybe, you should make zerglings instead of drones. In fact, I insist on it. You probably didn’t scout the full size of the enemy army. Make zerglings, dammit!

• If we’re in the opening and we have reacted to the enemy’s build by adding more drones than planned, and we’re nevertheless in a situation where there is a mineral shortage and a gas excess, then do not spend one of the extra drones to make an extra extractor. That normal Steamhammer reaction does not make sense in context. This improvement may prevent only a few mistakes over the course of the tournament, but some mistakes are too ridiculous and have to be prevented.

• Steamhammer zerg normally breaks out of its opening if it faces a fast rush that the chosen opening does not already counter. Steamhammer now considers that its 7- and 8-drone dawn hydra rushes counter an enemy fast rush. The change has saved games in test versions.

• If there aren’t “enough” drones, then when adding static defense Steamhammer zerg replaces each drone as it is used up. It’s necessary to prevent emergency defenses from wiping out the economy. I decreased the limit of “enough drones” so that Steamhammer can bring up defenses faster in some midgame situations.

• When looking around a base to see whether it is adequately defended by sunkens, the radius is decreased for considering a sunken as defending the base. It’s a tweak.

• Steamhammer is slightly more cautious about morphing a sunken that will be weak when it is finished. Another tweak.

• The code to place a sunken to defend against vulture or DT raids forgot to check whether we have a spawning pool. Fixed. Other checks in the code would have prevented the error from causing incorrect commands if it ever came up, but it could have caused inefficient play during an emergency.

openings

I made 3 Counter Contain builds to defeat cannon contains and other early containment attempts. They work by starting a hidden base elsewhere on the map, so that units can be produced outside the contain: 6PoolHide 9PoolHide OverpoolHide. Contains still cause Steamhammer to misbehave because it assumes that units can safely walk past (they can’t fight their way past, but walking is different), so the openings don’t work perfectly. But combat units produced outside do usually prefer to find and attack the enemy main first, so it’s a great advance over former behavior.

• The openings I hoped would have a chance against Stardust are 10HatchLing+1, Over10Hatch+1, and Over10HatchHydra. They are all-in builds. The few Steamhammer wins over Stardust so far are due to zergling attacks after Stardust messes up, so I made 2 zergling openings with what I guessed to be good timing. Every Steamhammer win so far has been by a different opening, and neither of these was able to score—they might be as good as anything. The hydra build is one suggested by Jealous in an SSCAIT weekly broadcast. I didn’t really expect it to work and it didn’t, but it was worth a try, and besides, the opening has value for other purposes.

AntiWraith_2Hatch is configured as a Counter Wraith build. It makes an evolution chamber in time to get spores, and goes 2 hatch muta.

AntiFact_Overpool11Hatch is an additional anti-factory mutalisk opening. By opening with overpool it hopes to intimidate the terran into playing too defensively against possible early zerglings. In fact, it makes few lings and aims for 2 hatch muta.

2.5HatchMutaExpo is a variation of the existing 2.5 hatch muta build (2 hatch muta plus a later third hatchery), which adds the third hatchery at an expansion rather than in the main. The original version stuck to 2 bases because it struggled to place the third base on the 2-player SSCAIT maps. That weakness is mostly solved, so it’s time to play the build right.

• Steamhammer doesn’t defeat ZZZKBot as consistently as it should, because Steamhammer is weak at defense. (Microwave is good at defense and wipes the floor with ZZZKBot. “You are my mop!”) Falling back on a quick fix, I tried writing openings. 9PoolHatchSpeedSpire2 as written is too slow to beat the 4 pool. 9PoolHatchSpire is good and should beat all ZZZKBot builds, but Steamhammer still isn’t consistent, only getting about 80% wins in the latest test. A quick fix is not enough, Steamhammer needs the actual skills.

debugging

• Clarified the wording in the building manager’s debug display. The construction status strings were kind of cryptic.

• A meaningless yellow square is no longer drawn in the upper left of the map. It was a leftover code snippet from old debugging. It took me a couple searches through the code to find it.

Next: About Steamhammer’s tournament prep learning files.

Steamhammer 3.1 change list

I uploaded Steamhammer 3.1 to the Starcraft AI Ladder. Not to SSCAIT, since it is down. The update is a small one, there’s not much new stuff and no major new features; my rate of work has been low. It should be stronger than version 3.0.2, but not by a wide margin (of course I predicted the same about that version, which made a big gain). Steamhammer’s weakest race terran got the most additions. In a startling break with tradition, I wrote no new openings.

I expect that the next released version will be Steamhammer 3.2, which I will put out after the AIIDE 2020 submission deadline. My to-do list includes a deep bag of tricks that I can select from....

expansion order

Take bases in a better order. Reading the code that chooses the next expansion showed me a few gross bugs, which I fixed. I also adjusted values to be a little less wrong. It’s still none too smart; for example, it doesn’t understand that zerg base order versus terran should be much different than versus protoss. The worst remaining problem, though, is caused by a bug in the building manager: When workers repeatedly die before reaching the building site, the building manager may cancel the building without unreserving the tiles, so that the base can never be taken for the rest of the game. That’s bad, but I intentionally left it unfixed for now because some of the bug’s effects are good. If you repeatedly fail at taking a base, then, well, maybe you shouldn’t try to take that base. Steamhammer’s base-taking behavior becomes adaptive. I don’t want to fix the bug until I can provide that adaptivity on purpose rather than by mistake. Failing to expand to the same unsafe base over and over is not a winning plan.

• I added a debug option to the configuration file, DrawExpoScores, which draws Steamhammer’s idea of the value of taking each base. It’s generally a positive number for bases near Steamhammer’s main and a negative number elsewhere on the map (which doesn’t matter, it simply picks the highest value). If the base cannot be taken, it draws the reason instead.

micro

• Ranged units give higher priority to targeting tanks. This was inspired by games in which Steamhammer’s hydralisks saw a factory with a tank on the other side, and decided to shoot at... the factory.

• Bug fix: A worker that had just mined out a mineral block might go idle. When it happened, the worker not only wasted its life doing nothing for the rest of the game (not even watching cat videos), it also blocked the path that it had been given the task of clearing. Now that’s some powerful laziness!

terran

The terran changes are related to repair of buildings and to lifting of buildings.

• Bug fix: It understands that it can’t repair a building which is not completed. I believe the effect of this aboriginal bug in the code is that an SCV is assigned to repair, can’t start because the building is not repairable, and gets reassigned the next frame. I didn’t verify it, but it must slow down mining.

Mass-repair a bunker or turret. The response time is slow, so it doesn’t work as well as it should. A simplified calculation makes a rough guess at the right number of SCVs to assign (it does get the correct answer in the case of repairing a bunker under attack from dragoons).

• It can repair multiple buildings at once. The original code, inherited from UAlbertaBot and little changed until now, could repair one building at a time. For buildings other than bunkers and turrets, it assigns one SCV each. Only a fixed proportion of the total SCV force is allowed to repair at a given time, so that mining is not impeded too much.

• It repairs buildings other than bunkers and turrets only after they fall to half health. If it’s only a hurt a little, it’s not worth it. Mining is the priority.

• In a build order, the command "go lift [terran building type]" lifts all buildings of that type which are able to lift. For example, "go lift engineering bay" lifts all engineering bays that can lift. If a building is producing a unit or researching, it is not able to lift and ignores the command.

I originally wrote up lifting while working on the scout boss. Since the scout boss is deferred, there is currently no code to tell the lifted building to do anything. It can’t land and it doesn’t move, it just floats in place. Lifting is limited, but it does free room in the base for other buildings.

• The strategy manager automatically lifts any barracks and engineering bays when the opening is complete and the build calls for factory production only. So you should rarely need to use the lift command in a build.

zerg

• In build orders in the config file, some upgrades used to require the race name, like "zerg flyer attacks". That still works, but now if you prefer you can leave out the race and write only "flyer attacks". It was a missing case in the parser.

Build sunkens at outlying bases to provide some defense against vulture raids, sneaky dark templar, and small drops. If Steamhammer suspects that one of those specific things may be coming, it builds a single sunken colony at each base that it expects may be in danger—for drops, that means every base, while for ground raids it skips the sunken at main bases in the hope that a sunken at the natural will be enough. The aim is to add the minimum of static defense. ZvZ is not affected. I expect this to be most effective against terran vulture raids, reducing drone losses and giving the zerg main army time to react.

• Against valkyries or corsairs, get air armor a little earlier. It will help for the rest of the game.

• If we have gas-heavy hive tech, make extractors more freely. I keep telling Steamhammer, “Hey, this is late game already, what’s the holdup? Why haven’t you taken gas at every base?” Somehow I can never accelerate the late-game extractors enough.

Steamhammer 3.0 change list

I’ve uploaded Steamhammer 3.0 to SSCAIT. Expect source tomorrow. Here’s the change list. Some items I already wrote up, so I only link to the posts here.

There’s a ton of new stuff. This is an infrastructure version, aiming to set the stage for future progress. The new features mean there is a high risk of arthropod vermin. If the new bugs are not too deadly, I expect this version to be only slightly stronger than the current Steamhammer 2.4.2 (which plays identically to the SSCAIT tournament version). Watchers may not be able to tell the difference, except when there is more than one queen on the screen, when it will be obvious. I expect only occasional proxy openings.

skill kit

The skill kit makes it possible to extend the opponent model with any kind of game data, so that in principle Steamhammer can adapt any aspect of its play to the opponent based on experience. To implement a new skill under the skill kit, write a subclass of the abstract class Skill. You need to set a name for the subclass (_name) and implement methods enabled() (should the skill be loaded for this game?), update() (which may carry out the actual skill, or may only collect information), and putData() and getData() (write or parse your data for the game record). You also have to implement feasible() (check quickly, is it possible to execute the skill?), good() (is it a good idea to execute the skill?), and execute() (carry out the skill when feasible and good), but if you prefer you can let update() do all the work, just have feasible() return false, and supply trivial implementations for the others.

• There is a new game record format that records modestly different information about each game, and includes skill kit data. Steamhammer can read records in the old format or the new format, so existing data can be kept.

• The updated gas steal skill uses the skill kit and knows a lot more about Starcraft than the original gas steal skill.

• There is a new enemy unit timing skill. All it does it record data.

• Base ID numbers from the map analysis are now constant across games, so that the numbers can be stored in the opponent model and used to remember the initial base positions.

proxy skills

Steamhammer now has basic proxy skills so that you can write a wide variety of proxy openings. There are new macro locations such as @ enemy natural and new things that you can do with macro locations, like send workers there ahead of time.

It is also possible to use the skill kit to write more sophisticated proxy openings which make dynamic decisions.

production

Fixed: A bug caused distant buildings to start later than necessary because of an error in figuring out when to send the worker.

• Improvements to the handling of production jams: Don’t declare a jam when we are out of resources. Don’t declare a jam when we are maxed on supply. Also, clearing a jam correctly resets the timer so we don’t loop on declaring production jams. The changes correct occasional minor problems, nothing serious.

• If a worker sent to build gets locked down or maelstromed, we immediately assign a new worker. For some reason, Steamhammer used to assign new workers only for stasis.

• If we’re protoss, and we’re constructing a building with a worker from the same base as the building, it’s OK to assign a worker that is carrying minerals or gas. It will barely delay our income. Terran and zerg continue to insist on builders with empty hands.

• Some production code is slightly simplified.

other infrastructure

Mine out blocking minerals on maps that have blocking mineral patches. In the SSCAIT map set, that is Destination and Heartbreak Ridge. WorkerManager sends a worker to mine out the minerals once there are 2 bases and at least 18 workers total. The implementation is not complete and works only for mineral patches with 0 minerals; it doesn’t work on maps where blocking minerals actually contain minerals (mostly quite old maps).

Resource tracking: Keep track of the remaining minerals and gas on the map, as information allows. Since writing those two posts, I extended the code to also keep track of whether a mineral patch is mined out; formerly, the code could not tell the difference between a 0 amount mineral patch and a mineral patch that no longer existed (it’s used in mining out blocking minerals).

• Decide on the value of taking a base, possibly a base that is partially mined out, based in part on the remaining count of mineral patches and the remaining total resources. To get this tuned right I had to retune other aspects of expansion decisions too, or else it would take center bases too soon.

The internal The system to simplify information access is extensively reworked and lets you reach much more information.

Maintain global unit counts every frame. I removed the old UnitUtil::GetAllUnitCount() and UnitUtil::GetCompletedUnitCount() calls. The information is used so often that it’s better to compute the numbers once and for all each frame.

Infer the existence of enemy buildings that we haven’t seen if the buildings are prerequisites of things we have seen. When we see a dark templar, we know there is a templar archives, among other buildings.

Accurately predict enemy building completion times in the UnitInfo system that tracks enemy units. Steamhammer now knows when enemy static defense that it saw under construction will complete, and uses the information in combat simulation (it formerly used a gross approximation that sometimes caused misbehavior). The info is not yet used in recognizing the enemy plan, but it will be valuable when it is. The info also affects squad targeting sometimes.

• A proxy enemy supply depot, engineering bay, or pylon by itself is not an emergency and doesn’t cause the enemy plan to be recognized as Proxy. Don’t overreact.

InformationManager::enemyGasTiming() remembers the time that the enemy first visibly used gas. For example, if we see a vulture, then we know there’s a factory, so we know that the enemy has spent some vespene. It’s one piece of data that goes into deciding whether to steal gas: It’s recorded in the new format game records, and the gas steal skill looks at the numbers from games with no gas steal to get an idea of the enemy’s usual behavior and decide whether stealing gas now will interfere with it.

• A minor improvement to UnitUtil::EnemyDetectorInRange(), which tries to judge whether a cloaked unit of ours is detected by the enemy: Now it knows that a blinded detector can no longer detect.

• I fixed a bug in InformationManager that could cause it to believe that a destroyed pylon existed for 1 extra frame, a bug with no detectable consequences. There should be a Rammstein song about that.

• I removed the WorkerData::depots data structure and its updating code, which was not only unused, but unusable because it was incorrect. I also removed the MacroAct::_race value, which is redundant and was used only for error checks that have never failed in Steamhammer’s life and would be easy to debug if they did.

• I removed various unnecessary includes.

configuration

New macro location @ gas only makes it possible to take a gas-only base (with no minerals) on those rare maps that have them. The zerg strategy boss knows how to do this and will automatically do it sometimes. This is on top of the new macro locations for proxies.

• I removed the macro location @ macro in favor of @ main, which so far means the same thing. Though I’m thinking of splitting them again in the next version, when they may no longer mean the same....

• Added configuration option Config::Debug::DrawResourceAmounts which draws Steamhammer’s idea of the remaining minerals or gas in each mineral patch or geyser—the amount and, if it’s not current, the frame it was last observed. It’s turned on in the uploaded instance, so you’ll see it on the SSCAIT stream. Also Config::Debug::DrawTerrainHeights which draws a number for the terrain height at each tile, with doodad terrain levels in purple.

• Changed the configuration option Config::Debug::DrawWorkerInfo to draw the worker’s job code on each worker and target lines to show where the worker is going. Formerly it drew the worker jobs in a column, which was hard to relate to the game situation. Updated Config::Debug::DrawStrategyBossInfo to add the target queen count to its display of information.

• Renamed configuration option Config::Skills::AutoGasSteal to Config::Skills::GasSteal; it sets whether the gas steal skill is enabled. Renamed Config::Debug::DrawUnitTargetInfo to Config::Debug::DrawUnitTargets because it is shorter.

• Removed configuration options Config::Debug::DrawResourceInfo which was confusing, Config::Skills::RandomGasStealRate which appears to have never been used by any fork, Config::Debug::DrawMouseCursorPosition which I don’t find value in, and Config::Debug::DrawBOSSStateInfo which is not very informative even when using BOSS.

squads

Fixed reaver stuttering, which was caused by a bug. Reavers are slow enough without spending half their movement time stopped.

InformationManager::getNearbyForce() uses the predicted completion time for enemy buildings. This is how the info gets into combat sim.

• The recon squad: Don’t form it before 6 minutes into the game. Formerly the squad was constituted whenever there were “enough” units, which could cause a zergling rush to be weakened by diverting some lings to reconnaissance.

The watch squad: Even if a watch squad zergling is the last zergling on the map, it will remain on station. Formerly, in an emergency it would rejoin the main army, where it did no good and no longer guarded its base from being taken by the enemy. More importantly, stay above ground when detected and endangered. IceBot dealt successfully with the burrowed zerglings: When the SCV could not start construction, it scanned and attacked. The zergling was forced to the surface but instantly reburrowed again and soon died. Oops.

• Squad targeting in the cleanup phase of the game: Don’t send a squad after enemy units that the squad can’t attack. This prevents some cases of zerglings following a floating ebay and the like. There are advantages to following, but I hope this way Steamhammer will be less often distracted from finishing the game.

• Be willing to pull workers a longer distance versus an enemy proxy than versus zerglings. Keeping the workers near their minerals saved many games against zergling attacks, but prevented the workers from engaging proxy buildings. That’s fixed.

• I made changes to try to retreat behind static defense instead of retreating to around static defense, but it didn’t work. Also unsuccessful were changes to cluster regrouping to get late-arriving units to join the fight as they should. The changes are still in the code, though; they’re no worse.

queens

• The maximum count of queens is configured to 6. The previous Steamhammer was already able to handle that, but I didn’t have time to test it before the tournament so I kept it configured to 1 queen max. When 2 or more queens are near each other, they fly in wacky looping patterns to keep away from each other so that they don’t all engage the same target at the same time. That’s a pre-existing behavior, but with 1 queen you don’t get to see it.

• Queens are better at avoiding danger. I widened the safety margin by 1 tile, which made a bigger difference than I expected. Also, queens now recognize science vessels and dark archons as dangers and try to stay away from them.

• I fixed a bug (introduced in tournament version 2.4.1 in December) that made queens less likely to succeed in infesting a command center. Moving around was taking priority over infesting.

• The strategy boss knows how to make higher numbers of queens. It decides how many, and what research to do in the queen’s nest, by looking at enemy unit counts. It used to get the queen energy upgrade too early; now it only gets the energy upgrade if there are many queens to benefit from it, or if the economy is so booming that the expense is negligible.

• The top priority broodling target is a nuking ghost. That brings queens in line with other attacking units.

• Be willing to broodling a less important enemy unit if the enemy doesn’t seem to have any of the most important ones. For example, if you make a lot of tanks Steamhammer may make queens to broodling them. Later in the game, if there are no tanks to be found the queens will be happy to broodling goliaths instead; formerly it would insist on tanks no matter what. Broodling becomes more valuable.

• If there is high total queen energy (because there are a lot of queens), be more willing to use ensnare and parasite instead of broodling when more than one spell is available. Formerly the broodling > ensnare > parasite hierarchy was more rigid. The more flexible queen behavior is better.

• Steamhammer is able to make infested terrans. I fixed the production system bug that prevented it. It uses them very weakly, so I set it to make only 1 at a time and leave time between them.

zerg

Emergency reaction: If too many drones are lost, or a hatchery is lost, break out of the opening. Steamhammer as zerg is too inclined to stick to its opening when it is busted.

Fixed a bug in spellcaster micro that could cause a queen or defiler to go idle. That was painful when it happened; a potentially valuable unit would stop on the map and do nothing for the rest of its life.

Lurker micro improvement: A lurker will not unburrow if an unseen or undetected enemy is thought to be in range to attack it. Formerly, a lurker with no target would unburrow immediately to seek a target, then die to the bunker it could not see at the top of the ramp, or to an untargetable dark templar that was standing next to it. The ramp misbehavior especially caused a lot of unnecessary lurker losses (we saw an example of the same misbehavior from PurpleSwarm in a recent broadcast), but the DT misbehavior is also a key blunder in some games. There is a bug that will still cause a bad unburrow below a ramp sometimes, but at least it’s less common.

• In ZvZ, be less eager to make a defensive evolution chamber right away. Steamhammer has made a lot of unnecessary evos.

• In ZvT and ZvZ, when adding spore colonies, place the first spore in the location closest to the enemy, considering Steamhammer’s main base, natural, and any proxy it may have. (In ZvP, the first spore goes into the natural as DT defense.) There were cases where Steamhammer would place the spore in its main when the natural was closer to the enemy base, and it became impossible to protect the natural from wraiths. At least force them to fly around to a more distant target!

• Drones may burrow for safety when an irradiated unit comes near. This protects them against the eraser trick and other irradiate hazards. I expect that by the time irradiate is researched, burrow will usually be available.

• If the opening book says it wants a hatchery (and no drones have been lost), trust it and make the hatchery. This is to accomodate rare openings which deliberately make hatcheries early. Formerly a safety rule might fire and say “No, you don’t need that hatchery yet.”

• The unit mix versus battlecruisers is adjusted slightly. I hope it will perform better against MadMix’s battlecruisers.

• Don’t make more devourers than needed to counter enemy air. There was already an overall max devourer limit, and a limit depending on how many mutalisks there are. I hope that now, with all factors accounted for, Steamhammer will finally stop overdoing it.

• If Steamhammer is maxed and rich, get overlord sight range.

• Plaguing a cloaked ghost gets a high value, even compared to plague on other cloaked units. It’s to help defend against nukes. Steamhammer really, really does not want to get nuked.

openings

A lot of new openings mysteriously appeared. Where do they come from?

Steamhammer 2.4.2 change list

Steamhammer 2.4.2 is available as source from Steamhammer’s web page. The documentation is updated too. As far as game play goes, it is identical to version 2.4.1 in the SSCAIT annual tournament. The main difference is that Steamhammer can automatically recognize when it is running under SCHNAIL and treat its opponent as a human.

I hope SCHNAIL testers will let me know how it goes, so I can adjust the behavior against human players.

Here is what’s new.

configuration

  "Skills" :
  {
    "SCHNAILMeansHuman"       : true,
    "HumanOpponent"           : false,
    "SurrenderWhenHopeIsLost" : true,

    "ScoutHarassEnemy"   : false,
    "AutoGasSteal"       : true,
    "RandomGasStealRate" : 0.0,

    "Burrow"             : true,
    "MaxQueens"          : 1,
    "MaxInfestedTerrans" : 0
  },

• The SurrenderWhenHopeIsLost, ScoutHarassEnemy, AutoGasSteal and RandomGasStealRate items are moved from the Strategy section to the Skills section of the configuration file.

• An internal flag Config::Skills::UnderSCHNAIL is added. It does not appear in the configuration file but is set by code. It is true when Steamhammer detects SCHNAIL’s schnail.env file in the read directory. Code can use this to do something different when running under SCHNAIL; it may be useful someday.

• A flag SCHNAILMeansHuman is added. If UnderSCHNAIL and SCHNAILMeansHuman are both true, then Steamhammer overrides the configured value of the HumanOpponent flag and sets it to true.

In other words, if you set SCHNAILMeansHuman to true, then whenever Steamhammer is running under SCHNAIL, it will assume that its opponent is a human. That should almost always be what you want. If it’s not what you want, you can turn off SCHNAILMeansHuman and set the HumanOpponent flag by hand.

• Steamhammer messages “gl hf” at the start of the game if it thinks the opponent is human. It actually wishes the human to have bad luck and suffer torment (BLAST), but it doesn’t mind lying. The real purpose of the message is so you can tell whether the HumanOpponent flag is turned on when it should be.

• The game message was formerly messed up. I think I finally fixed it.

• In the IO section of the config file, I separated Config::IO::PreparedDataDirectory (bwapi-data/AI/om/ for prepared opponent model files) from Config::IO::StaticDirectory (bwapi-data/AI/) for reasons of what I prefer to call clarity. The change doesn’t affect anything but a name in the code.

Steamhammer 2.4.1 change list

Steamhammer 2.4.1 is the version for the SSCAIT 2019 tournament. Version 2.4.2 with source release should follow shortly with only one significant change, SCHNAIL recognition.

For the tournament, I replaced the SSCAIT learning data with data from BASIL, because BASIL has more games that are recent. There are downsides; it could be that it was a mistake. I made a small number of hand edits to the learning data. For example, for StyxZ, I deleted games from before Styx was updated and suddenly became strong. I edited data for 7 opponents in total, usually just altering one game record.

First an explanation of my supposed Killer Feature, then the change list proper.

the Killer Feature

The “Killer Feature,” which is no more deadly than your average killer app, is to burrow zerglings at bases that the opponent is likely to want to take soon. CherryPi did this a couple of years ago, and I was surprised that bots which know how to cope with spider mines laid to block base locations were often unprepared for burrowed zerglings doing the same thing. Two years later, bots which remain unprepared may get into trouble. Burrow has many many uses, and Steamhammer will take advantage of more of them in the future; in choosing a burrow skill, I am looking ahead. There are 3 parts to the system.

The strategy boss by default researches burrow after Steamhammer takes its third base. If the opening build takes three or more bases, it starts the research shortly after the opening. This is late enough in the game that the research is not a major expense, but it does lose the opportunity to exploit burrow early on.

The 9PoolHatchBurrow opening researches burrow much earlier. It is for use against opponents which may be vulnerable. 9PoolHatchBurrow is a variant of the Styx opening which collects 200 gas instead of 100 and researches burrow immediately after zergling speed, trading some of the zergling punch for the burrow ability. The two upgrades finish at almost the same time, because burrow (1200 frames) doesn’t take as long as speed (1500 frames). The aim is to get burrow early while pressuring with zerglings, and try to burrow a zergling in the enemy’s natural to delay or displace the expansion and mess up the enemy’s build. Burrow normally finishes before the enemy has scan or observers, so even an opponent which knows how to react may be delayed.

I tweaked the learning data so that this build will be given a try against a few opponents.

The Watch squads are for scouting and base denial. The design attempts to gain the most impact with the least investment. The combat commander creates from 0 to 4 Watch squads (depending on Steamhammer’s ground strength and other factors) of 1 zergling each, and assigns the squads to watch the bases closest by ground to the enemy main. It may also assign overlords to watch further bases, but usually by the time there are overlords to spare, it is not safe to assign them. A Watch squad behaves like any other squad, except that if a squad member finds itself at the order position and is able to burrow, it does. (It’s literally a few lines of code.) Once at least one zergling is under the ground, the combat commander attempts to keep the most important Watch squad on station despite any reverses, because to disband it would throw away the investment.

When Steamhammer decides to expand to a base, any Watch squad stationed there is disbanded immediately. The zergling unburrows and joins the ground army long before the drone trundles in to make the hatchery. The disbanding is 1 line of code in a condition in the combat commander, and the unburrowing and leaving is standard behavior that was written into the squad long ago. The whole Watch implementation is as simple as I could make it.

I’m eager to see how the Watch implementation works in practice. When Steamhammer faces a full range of opponents, the results of a new feature are always more complicated than I see in my testing.

configuration

• I added a new configuration section Skills which is intended to separate out some items from the long Strategy section. For now, it has Burrow, MaxQueens and MaxInfestedTerrans items. Later I’ll move some items over from Strategy.

For this SSCAIT, Burrow is true, MaxQueens is 1, and MaxInfestedTerrans is 0. The strategy boss is willing to make up to 2 queens, but I decided that the second one probably costs more than it is worth for now. Steamhammer has a bug in the production system that prevents it from making infested terrans, so it’s better not to try.

infrastructure

UnitInfo keeps track of whether a terran building was lifted when it was last seen. For some reason I resisted doing this earlier, but it’s important information. The first use is in squad targeting, when checking whether an enemy building is a good target for a given squad.

• Another use of the terran lifted building info is a new skill: If all known enemy buildings are lifted and all known enemy units are air units, Steamhammer will only include anti-air units in its unit mix. It sounds obvious, but ultra-ling is a potent way to finish off a zerg or protoss which has only air units left, and is only weak versus terran that has lifted buildings. This skill is intended to solve a rare difficulty in finishing off a terran—I have seen it happen in only 2 games.

• Don’t try to expand to a base which is known to be blocked by an enemy building or burrowed unit. There’s no point in sending a drone to build on top of a spider mine which has been scouted. This also, of course, checks whether the building is lifted.

• Efficiency fix: Use base->getTileDistance() precalculated ground distances in some places instead of recalculating the distances.

Config::Debug::DrawMapDistances now draws tile distances from its current main base rather than from its starting base. You can see what Steamhammer considers to be its current main base, which may change during the game.

• I removed the unfinished and unused Region and Regions classes. I had forgotten they were there.

zerg

Research Burrow, if enabled in the configuration, usually just after the third base is taken. The strategy boss will delay the research for some emergencies or if the economy doesn’t justify it.

The Watch squad scouts and denies bases. It is implemented for zerg only. Other races don’t have enough cheap units to dedicate some to sitting around, and are better off with the Recon squad alone.

A critical bug in upgrade checking could cause production freezes. Ouch. Fixed.

• In ZvZ, get +1 melee attack instead of +1 ground carapace as the first ground upgrade. It’s cheaper, and it’s what humans usually do. I think the theory is that killing drones faster is more important than a small edge in resisting mutalisk bounce attacks.

openings

The 9PoolHatchBurrow opening is added. See above.

• Minor tweak to ZvP_3BaseSpire+Den. It gets 1 more drone.

Steamhammer 2.4 change list

Steamhammer 2.4 is uploaded. Since I never got around to releasing the source of the previous version, I’ll release source shortly.

This version has 2 points of focus: First, fixing critical bugs that are responsible for many of the losses against weaker opponents, and second, coping with the deadly Styx opening. I wrote 18 new openings, 10 of which are connected to the Styx opening.

configuration

Added the Config::Strategy::HumanOpponent flag for games against humans. It’s false by default, since almost all games are versus bots.

critical bugs

Cancelling mutalisks just before making them is fixed. It happened intermittently in some openings. A spire takes 1800 frames to build, and Steamhammer is configured to conclude that production is jammed if there are 1440 frames without production. In some cases, the opening build might pause production for longer than the limit while saving up for mutalisks; a jam clears the queue and drops out of the opening, so the mutalisks were never made. I fixed it with a special case test, since only this one case was failing.

Gas deadlock is an emergency that happens when Steamhammer needs gas for the next item, and has the extractors for it, but finds itself unable to collect the gas for some reason (for example, the base is under attack so the drones ran away). It clears the queue to try again. The condition for recognizing gas deadlock was too loose, and sometimes declared deadlock falsely. I tightened it up.

Tracking of geysers and refinery buildings seemed to be wrong in some cases. I was not able to pin down any bad behavior it caused, but the code looked confused and I’ll be surprised if nothing is corrected.

Combat sim is more fixed. In the previous version I fixed bugs in setting up the combat sim, related to short-circuit judgments when facing cloaked units. There was still a bug, and I traced it to... checking whether a unit’s air weapon was unequal to BWAPI::UnitTypes::None rather than BWAPI::WeaponTypes::None. Thank you C++ for your “helpful” type checking. This fix will make mutalisks more aggressive, as they should be, in certain situations.

macro

• Restored the setting of 2 workers per mineral patch for terran and protoss. It had been accidentally set to the zerg value of 1.6.

operations

• Against certain stronger enemy units, send more defenders. If an archon is in your base wreaking havoc, 2 marines will not stop it.

• The natural expansion cannot be one of the map’s starting bases. This fixes a problem that came up on the map Baekmagoji.

StrategyBossZerg::enemySeemsToBeDead() works more nearly as intended. There was a minor bug. The enemy is considered to be dead and ready to be buried when all these conditions are met: 1. The enemy starting base has been found (so it can’t happen immediately when the game starts). 2. The enemy has no known surviving bases. 3. The known enemy ground army is not strong enough to threaten to win. 4. The enemy has no known anti-air units or anti-air static defense. When the enemy looks dead, Steamhammer techs to mutas and switches to a unit mix of drone + mutalisk. The mutalisks can efficiently hunt down any hidden or floating buildings.

unit control

The micro system drops positional orders for which the position is “close enough” to the previous order. If code orders a move to (x, y) and then on a later frame a move to (x, y+1), the second order is dropped. The tolerance is a few pixels for short-range moves, larger for long moves. This reduces command spamming and smooths unit flow. In the long run, I ideally want to reduce Steamhammer’s APM to human levels.

• Targeting priority for enemy buildings is factored out and more nearly standardized across unit controllers. Streamhammer should destroy enemy bases a little more purposefully, with fewer cases of zerglings tearing down the spire while mutalisks tackle the spawning pool.

• Enemy observers are a higher priority target for ranged units and scourge, depending on the situation.

zerg

• When in book, if we have no zerglings, do not change a planned zergling into a drone. Steamhammer likes to skip zerglings when it foresees no danger. A similar change was already made for the case when it was out of the opening.

• Queen bug: The queen believed it could infest an unfinished command center. “It has few enough HP, let me fly across the map and take it.” When the building SCV was killed, the queen might sit over the unfinished command center forever. “This infestation sure is taking a long time. Oh well, stick with it!”

• Queen bug: When using broodling, the previous version was intended to be willing to make 2 queens, not the usual 1. After testing the feature, I introduced a typo that prevented it from working. Fixed.

Prevent production freezes related to queen upgrades. Rare but painful.

• Allow air upgrades in any order, using 1 or 2 spires. Formerly, air carapace had to be first (or else production freezes were possible) and Steamhammer could upgrade in only 1 spire. This any-order-is-OK improvement was made earlier for ground upgrades.

openings

ZvZ_Overgas8Pool fills a small gap in the repertoire. A very small gap.

973HydraBust is a precise modern build versus protoss forge expand. The name is because you are supposed to end up with 9 drones in your main, 7 in your natural, and 3 at a third base. Steamhammer does not have the skills to distribute the drones efficiently as intended, but it does get the right total count.

2HatchMutaForever covers a weakness in the zerg strategy boss: There are times when growing the mutalisk flock is best, but the strategy boss doesn’t understand the value of stacking air units and prefers to switch into a different unit mix. The opening doesn’t really make mutalisks indefinitely, only for a long time. It also gets air upgrades.

2HatchFakeHydra and 2HatchFakeMuta are deceptive openings that make both hydralisk den and spire. The fake hydra opening makes a hydralisk den when the enemy scout should see it, chases the scout away, and adds the spire later. The enemy may predict hydra play or lurkers. The fake muta opening is similar but in reverse.

5HatchPool makes 5 hatcheries before spawning pool, an extremely greedy opening for use against opponents that move out late. (See my mention of Locutus in what Steamhammer learned. I’ve seen 6 hatch before pool work against a bot.) ZvP_5HatchPoolHydra is a specialized version that follows up with mass hydralisks. 5HatchPoolLing gets an evolution chamber before the spawning pool, so that when the first zerglings hatch, melee attack +1 is already half finished. The flood of lings is late but massive.

The powerful Styx build. The openings 9PoolHatchSpeed7Drone, 9PoolHatchSpeed7DroneB, 9PoolHatchSpeed, 9PoolHatchSpeedAllIn, 9PoolHatchSpeedAllInB are variations on the Styx build of 9 pool, 3 pairs of zerglings, hatchery, extractor (leaving yourself with 7 drones), zergling speed, and deluge the enemy with zerglings (7 drones are enough). That exact build is 9PoolHatchSpeed7DroneB. The versions without a B have the extractor before the second hatchery, which gets faster zergling speed and a slightly slower hatchery. The versions without 7Drone use the extractor trick to end up with an 8th drone without losing time. The 8th drone does not make the zergling attack stronger, because 7 drones are enough to keep the 2 hatcheries completely busy producing, but it does establish leeway to lose a drone to accidents, make an emergency sunken, or transition into another plan. The plain version 9PoolHatchSpeed makes fewer zerglings and leaves the followup to the strategy boss, which is not too helpful because the strategy boss doesn’t understand the idea.

Anti-Styx openings. If you know your opponent’s exact build order, you can always choose your own build to gain an advantage. (Don’t be predictable!) If the opponent is too greedy, you can clobber them with a rush or a bust before they’re ready. The Styx opening is not greedy; 9 pool is what you play to be safe against cheese. When the opponent is not greedy, you gain an advantage by being greedier, to a calculated extent. AntiStyx_9Pool is the simplest try. It uses the extractor trick for the 8th drone, and turns the drone into a sunken. The zergling wars are about equal, but the sunken at home is safer and allows more freedom of action because there is less need to hang back in defense. At Steamhammer’s level of play, the advantage is slight. However, this anti-Styx build is valuable as a general-purpose anti-cheese build; I configured it for that too. AntiStyx_3Hatch and AntiStyx_Muta are more successful at defending against the Styx opening. They open with overpool rather than 9 pool, gaining a lead in drones. Both make 1 sunken and use the safety it provides to scrape out more drones. The 3 hatch followup adds a third hatchery to eventually win the zergling wars, while the muta followup techs instead. The safe path is narrow; I’m curious to see how well the openings perform in practice.

Turtle openings can also cross the river Styx. Some turtles swim well, and they do not have the same weakness as Achilles. See wins over StyxZ by ZurZurZur, by Simplicity, and by Microwave with its turtle build.

9PoolHatchSpeedSpire and 9PoolHatchSpeedLurker are my try to pre-empt bot authors who may add a recognizer for the dangerous Styx opening so they can counter it. These builds start out with the Styx opening stem but transition into tech.

• I made tweaks to AntiZeal_12Hatch and 12HatchTurtle. They should be a trifle stronger.