archive by month
Skip to content

a Steamhammer versus PurpleTickles game

PurpleTickles of Dan Gant’s purple family is a bot that plays exclusively worker rush builds. It’s not highly ranked; it is #50 on BASIL, well below average. Steamhammer’s score against it is 29-1 on BASIL, and the rest of the BASIL top 10 have similar scores. But I thought this one Steamhammer-PurpleTickles game was fun and instructive.

Steamhammer’s counter to worker rush is spawning pool at 9 drones (sometimes less if drones are lost) followed by creep colony. The intention is that when the spawning pool finishes, the combination of zerglings and a morphing sunken colony will be insuperable. If the sunken completes, zerg is safe against almost any number of workers, so the opponent must prevent that at all costs.

Tickles selected a late worker rush this game, starting its attack when it had 8 probes. It left 1 probe mining and attacked with 7. The late rushes are more effective against Steamhammer, and I assume that Tickles has figured that out (it has won 1 game, after all). At the time of the picture, 1 further probe has been manufactured and is now crossing the map to join the attack.

probe rush!

Tickles does not have perfect worker micro, but it does know how to coordinate its probes so they attack together. Steamhammer has inferior worker micro, because each drone defends itself individually and the drones don’t work together. Its forces can be defeated “in detail,” as the military jargon goes. Also Steamhammer has sent a drone to scout, a questionable decision, so its mining workers barely outnumber the attackers. In general, when Tickles attacks the mineral line from one end, it is very successful in killing drones. When it approaches from a different direction, the probes do not coordinate as nicely and Steamhammer has less trouble. Tickles is not smart enough to figure out the right angle of attack, so the outcome of the battle can depend on the orientation of the mineral line relative to the base entrance.

probe victory?

The probes destroyed all mining drones with 5 surviving attackers (and 1 probe still mining at home). Steamhammer gave priority to zerglings, so 2 pairs of zerglings are about to hatch, but there is no money to morph the sunken. Vanquishing 4 zerglings with 5 probes is a tall order, but protoss is still mining and it’s definitely worth a try.

probe defeat

Well, the probes didn’t stand a chance, though it’s hard to tell with the overlord blocking the view. They held their ground and fought instead of trying to maneuver, a fatal mistake. Steamhammer’s scouting drone canceled its mission and returned immediately to mine, so zerg did not find the protoss base yet. The 4 victorious zerglings aimed for the wrong base at first, and also returned home to clear followup probes, but they were able to win by themselves after these little delays.

I see lessons in the game. 1. Coordinated micro is a key skill. PurpleTickles has it. 2. Steamhammer covered for its lack of that skill with a belt-and-suspenders strategy. It works. In games where the sunken starts to morph, PurpleTickles must stop it with the probes, but then mining continues and zerglings win anyway. One skill can often substitute for another. 3. When you have an advantage, try to fight head on, as Tickles did probe versus drone. A probe is a stronger fighting unit than a drone. When you have a disadvantage, go guerilla. Probes are not bad at fighting zerglings, but they have to avoid head-to-head combat, unlike Tickles. A probe can attack at will as long as it is taking only shield damage, then run away; protoss shields regenerate faster than zerglings heal. Use drills (the minerals are right there), or maneuver to separate one zergling and gang up on it. If the purple probe-versus-zergling micro were as superior as the probe-versus-drone micro, the probes might well have won.

I’m pretty sure it’s possible to defeat Steamhammer most of the time with a worker rush, though no bot has shown it yet. As in this game, gather your attacking workers at one end of Steamhammer’s mineral line and coordinate them to defeat the uncoordinated mining drones, sweeping down to the other end of the mineral line. I believe it can be done more efficiently than in this game, and if it’s quick enough then after wiping the drones there should be no minerals for zerglings, or to morph the sunken—Steamhammer tries to replace drones and doesn’t save up for future needs.

If some bot proves my theory, then I’ll have to update Steamhammer’s worker defense.

next for Steamhammer: a scout boss

The major feature for Steamhammer 3.1 will be a new scout boss which will take care of scouting, detection, and providing vision. It’s next because it meets 2 needs: First, scouting must be improved for strategy adaption. You can only predict the opponent’s moves from what you have seen, and the current scouting does not see enough. As one example, the initial scouting overlord hovers in a fixed position over the enemy base, and some protoss bots are smart enough to hide buildings from it. Second, a major weakness in current Steamhammer is that it loses overlords at a high rate. Today, overlords for different purposes are controlled by different code, and only some of the code knows about avoiding dangers. An overlord being sent to watch over a distant base goes there in a straight line, and then so does its replacement and so on, and sometimes an overlord is unassigned from a task and simply stops in a random location. With unified control, overlords will both see more and expose themselves to fewer risks.

The scout boss will also simplify the codebase. It will centralize the functions of the current scout manager and the overlord squad, and of scattered code that controls squad detectors. I expect the 3.1 version to have less total code even though it will be more capable. It will definitely have simpler interfaces with the rest of the program, I have already implemented most of that aspect.

The current scout manager that handles early game scouting knows how to control one worker and one overlord, and that’s all. The scout boss will take command of all flying detectors (including overlords) and floating buildings (I want to add this feature soon), plus whatever units you assign to it. In the opening it will automatically send the second overlord to scout a different base. If you do BBS in the center of the map, you’ll be able to scout with both SCVs to find the enemy faster, as Liquipedia recommends. Many bots already have these skills, Steamhammer has lagged behind.

3.1 should not take as long as 3.0. Unless I fall to temptation and add more features.

sudden Steamhammer 3.0.2

Another day, another fatal bug. I just replaced Steamhammer 3.0.1 with 3.0.2 to fix an infinite recursion that caused a stack overflow. It could happen if Steamhammer was facing a random opponent, depending on the order in which enemy unit types were encountered. Gotta love conditions like that. That’s 2 bugs down, who’s keeping score?

Source is updated too. Only a few lines changed.

Steamhammer 3.0.1 source

Source code for Steamhammer 3.0.1 is now up on Steamhammer’s web page. It will take a little longer to update the documentation, since I made a passel of changes to the configuration stuff.

Part of putting up a new version is calculating the win rate for the previous version. Based on that, the SSCAIT 2019 tournament version 2.4.1 (which plays the same as version 2.4.2) was the strongest relative to the field since version 2.3 from summer 2019. Both are unequalled in Steamhammer history since version 1.2 from early days. In absolute terms, the latest version is of course the strongest.

ack, Steamhammer 3.0.1

First deadly bug eradicated! Only n more to go!

Steamhammer 3.0 has a crashing bug. It’s a null pointer dereference that can happen on startup when the gas steal skill analyzes past game records. Fixed, now I’m on Steamhammer 3.0.1. Next please!

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 3.0’s new gas steal

Steamhammer’s existing gas steal skill works by UCB, like the opening selection of many bots. It has a bias toward not stealing gas, but the basic behavior is that it will steal gas if that wins more games than not stealing, or if it hasn’t tried a gas steal in a while and it’s time to give it another spin. It pays no attention to what the opponent is doing, so it will try silly things like stealing gas while under zergling attack from a 4 pool. The silly decisions hurt.

Steamhammer 3.0 will have a completely recoded gas steal skill using the skill kit, and it will be much fancier. In fact it got too complicated; today I finished rewriting it to simplify the rules. I’ll upload 3.0 as soon as it passes tests.

The skill records three values for each game: The frame a gas steal was decided on (0 if never), the frame when the refinery building was started, and the lifetime of the refinery (when did the opponent clear the gas steal?). Also newly recorded in the game record is the frame when the enemy was first observed to have spent gas on a unit or building.

All this information, plus a few other items like the recognized enemy strategy, goes into the gas steal decision. The outline is that various checks are made first to see whether stealing gas makes sense (“no, this enemy doesn’t take gas for a long time anyway”). If so, attempt a gas steal randomly with a certain probability until we’ve accumulated 5 games of experience with it. Once the data is in hand, adjust the probability up or down depending on the amount of evidence, with fudge factors to try to take certain strategic points into account (“versus 2 barracks? are you sure about this?”).

It’s still crude compared to the analysis I’d like to do. The ideal would be to figure out the effect of stealing gas on the enemy’s strategy and play, infer the best time to attempt it, and send a worker then to threaten it. But it should avoid many of the blunders that the current method makes.

Next: The Cadenzie-Locutus match.

new openings in Steamhammer 3.0

Part of my regular change list for each new version is a list of openings I’ve added, so here’s another preview. The list is long this time, but easy to write up. Only a few of these openings are configured for regular play, but all will show up now and again.

Steamhammer’s new proxy skills enable a huge range of cheese builds. I wrote 2 or 3 for each race, sort of as samples.

terran

• In base proxy openings ProxyBBS and ProxyFactory. Ecgberht occasionally pulls out a similar proxy factory, which has scored wins over Steamhammer. These builds annihilate unready opponents but show execution weaknesses if the enemy is able to defend at all. BunkerNatural makes barracks in the center and bunker at the enemy natural, and scouts at a timing so that it just barely works reliably on a 4-player map.

10-10-10Vultures gets vultures earlier than the standard factory timing. I wrote this to test zerg reactions to fast vultures. Might as well keep it.

protoss

Proxy2Gate in a corner of the enemy base, which I haven’t seen another bot try, and CannonRushNatural with dragoon followup, also new to bot play.

zerg

Burrow versions of existing openings, zergling openings with different timings. It is part of my followup on the burrow skill. As burrow gains more uses in the future, these openings should show up more often. 6PoolBurrow 6PoolSpeedBurrow 8Hatch7PoolBurrow 8Hatch7PoolBurrowB 9PoolBurrowB 9PoolSunkBurrow OverpoolBurrow Overpool_3HatchBurrow 9Hatch8PoolBurrow 10HatchBurrow Over10HatchBurrow 3HatchLingBurrow 5HatchPoolLingBurrow.

Proxy openings: Proxy8HatchNatural makes a quick hatchery in the enemy natural and sunkens it up. AntiTyr and AntiTyrLurker are the same idea, but timed much later to counter the Tyr protoss build where it makes cannons in its base and builds up for a timing attack. AntiTyr serenely swallows the attack and wins. Steamhammer still needs a couple more skills before it can do Fried Liverpool.

AntiFactory2 is a slightly faster version of Steamhammer’s longstanding anti-factory opening, with hydralisks first. The original opening was timed to stop a 3-vulture runby, but lately a couple of terrans have been winning with a 2-vulture runby which is earlier and sneaks in before the defenses are ready. AntiFactory2 closes the gap. I configured it as a top answer to factory openings, so it should be fairly frequent.

11Pool is slightly faster than 12 pool for ZvZ, filling a small gap.

10HatchLing and 10HatchLing2 are specialized versions of 10 hatchery 9 pool which go all-in on zerglings.

• Experimental openings: Phlegethon I timed and showed to be inferior. The alternative 2x10Hatch (10 hatchery, 10 hatchery, 9 spawning pool with repeated use of the extractor trick) I have not timed, so in my ignorance I allowed myself to write variants 2x10HatchSlow 2x10HatchAllIn and 2x10HatchBurrow. The less I know, the more fun stuff I get, there’s a lesson!

Over10Hatch11Pool starts with the same extractor trick-overlord-hatchery sequence as a number of common Steamhammer builds, but inserts a couple extra drones before the spawning pool to build up the economy.

• Going the opposite direction, 3 hatcheries before pool but cutting drones to get the hatcheries faster than standard, are 12-11Hatch, 12-12Hatch, and 12-13Hatch. I was pleased with these and added 12-11HatchLing as a zergling all-in version.

2HatchLurkerPure is a variant 2 hatch lurker build which includes minimal zerglings, making drones instead, so that there’s a little more economy. I figure that if opponents lose because they are unprepared with detection, then the zerglings may not help much.

QueenRush and GuardianRush are not really useful except for testing (the only reason I wrote the queen rush in the first place). But then, I used to think the same about the hive rush build, until it scored wins over BananaBrain. At least they’ll be entertaining if they ever show up. The queen rush makes a half dozen queens with broodling nice and early in the game.

Steamhammer 3.0 game record format

Steamhammer 3.0 is nearly ready, but I’m immoderately busy and don’t know how long it will take for the last adjustments. I can at least slip in short posts to show off some of what’s coming.

Steamhammer 3.0 changes the format of game records in the learning files of the opponent model. The original version 1.4 game record format has been in use since early 2018. The learning file for an opponent is simply a list of game records. Here is the new 3.0 game record format.

meaningitem
game record version3.0
matchupZvP
map(3)Longinus_200.scx
base ID of Steamhammer's start5
base ID of enemy start, 0 if unknown at end of game12
openingOver10Hatch2SunkHard
predicted enemy planHeavy rush
recognized enemy planUnknown
0 for loss, 1 for win0
frame of our first combat unit4382
frame we first gathered gas6814
frame the enemy scouted our base3134
frame the enemy got a combat unit3838
frame the enemy first used gas5162
frame the enemy got an air unit5182
frame the enemy got static anti-air (0 means never)0
frame the enemy got mobile anti-air5182
frame the enemy got a cloaked unit5182
frame the enemy got static detection0
frame the enemy got mobile detection18686
frame the game ended28553
skill kit data (2 skills)gas steal: 0 0 0
unit timings: 60 6161 61 9565 64 2435 65 3815 66 13383 84 18696 154 3240 156 3240 157 3217 160 3263 163 5172 164 3194 165 6575 167 5195
end of the recordEND GAME

As before, the frame number of an event is the frame when Steamhammer first noticed it, not when it happened. They are sometimes very different.

The game record version number can be “1.4” for old records or “3.0” for new records. Steamhammer can read them both and use the data; changing the format doesn’t mean I need to clear out existing learning files. Of course fresh records are written in 3.0 format.

Including the base IDs of the starting positions of the 2 sides means that Steamhammer can pay attention to starting positions. You have to know the map to interpret what the ID numbers mean. The information about enemy gas usage is new and helps with gas steal decisions. The gas steal items from version 1.4 records are moved into the gas steal skill.

There was no gas steal in the example game, so the gas steal recorded 0 0 0 for its data. The skill kit can record data for any number of skills; it is extensible. Each skill’s data is [name of skill]: [data for skill] on one line (the line can be arbitrarily long). The skill needs to know how to write one line of its own data and how to read it back, and that’s all; the central skill kit code takes care of everything else, including rewriting old records without change.

preview of Steamhammer’s proxy skills

Here is a first look at Steamhammer’s upcoming basic proxy skills. These are features that you can use to write a wide variety of proxy openings. I still have work to do before I can release Steamhammer 3.0, and I’m working slowly so it will be a while. I’m making infrastructure changes that tend to introduce bugs. But I’m looking forward.

New macro locations @ enemy main, @ enemy natural, and @ proxy. Buildings for the enemy main or natural are placed in plain sight—MadMix has played that style of proxy with success against bots, and bunkering the enemy natural is standard in some situations. Buildings placed @ proxy go into a distant corner where they have a chance of remaining unseen. I also fixed a bug so that the existing macro location @ center works reliably.

To build in enemy territory, you need to know where your enemy is. Proxy locations interact with early game scouting. On a 2 player map you can always build at a proxy location. On a larger map, you’ll need to scout early enough to find the enemy first. I recommend go scout location with an early worker; on a 2 player map, the location is known so the scout is not sent. If the enemy is not found by the time building construction is to start, Steamhammer will fall back to building in the center of the map instead.

Post workers to a macro location. You can command a worker to take up a post at a given macro location with, for example, go post worker @ proxy. The posted worker can build at that location (barracks @ proxy) and will remain there for further orders (bunker @ proxy). Release posted workers from a given location with go unpost workers @ proxy or from all locations with go unpost workers. A posted worker is different from a worker that was pulled and assigned to a combat squad; a posted worker expects to build stuff and will not try to fight.

The feature bypasses weaknesses in Steamhammer’s assignment of construction workers. A worker sent a long distance tends to arrive late; by posting the worker in advance you can avoid the loss of time. Also, Steamhammer likes to send one worker per building, so if you ask for 3 forward cannons next to your forward pylon, it will send 3 probes (after all, you need 1 worker per building for Steamhammer’s main race zerg). If you post a probe there instead, special case code makes sure that the one posted probe makes the 3 cannons one after another.

Macro locations work for all actions that they make sense for. It’s essential so that you can control where production occurs: If you have a proxy gate and a gateway in your main, you can get your next zealot from the one you choose with zealot @ main or zealot @ proxy. Or similarly, if you have a forge in an exposed blocking position (which you’ll have to write code to place; Steamhammer doesn’t support that out of the box) and a forge in your main, you can specify ground weapons @ main to get your most important upgrade in a safer place. If you don’t specify, either building might be chosen.

The feature is a little fragile. The priority is to start the requested action as soon as possible, not to start it in the location requested. If you ask for a zealot at your proxy gate and that gate is already busy, the zealot will start in your main instead if that gate is free. That can be inconvenient in a hand-written build order, though it should be little trouble for a build order generated programmatically on the fly.

Proxy locations can block bases. A minor tweak to building placement: Normally Steamhammer places its buildings so that they don’t block any future base you may want to take. If you’re building in enemy territory, you don’t care about that. bunker @ enemy natural will commonly be placed to block the base location.

No maps are special cases in the code; all placement decisions are made by analyzing the map on the fly. I think the decisions are good for a first cut, but there is plenty of room to improve them. I did find one map where a mystery bug causes a worker posted in the center to fail to build there (so that Steamhammer sends a fresh worker from its base), but that’s the only bug I know of. It’s complicated, though, and there are probably a lot of misbehaviors I have yet to see.

The features are enough to support a good range of proxy openings. I wrote two or three for each race, for testing and for the fun of having them. In Steamhammer 3.0 none of them are configured to be played frequently, but they should pop up now and again.

The skill kit will be the other major feature in this release. It may sound independent of proxy skills, but in my mind there is a close connection: I want to write skills to make dynamic decisions about whether and how to proxy. It’s possible, and it doesn’t seem too difficult, to do things like cannon the enemy base differently each game based on analysis of the map and the base layout. Many bots place buildings the same way every game, and that can be exploited too.

Stand by for Steamhammer’s next step up in versatility.

how to defile

We have the next round of SSCAIT results. I was hoping for Killerbot by Marian Devecka over ZNZZBot, because Steamhammer is a favorite over Killerbot. But ZNZZBot squeaked a win by crash. Steamhammer will face ZNZZ in loser’s round 3 and almost certainly be eliminated. Oh well.

one little plague

A highlight from Steamhammer-Icebot on Fighting Spirit. In old days, Steamhammer would have finished a winning game like this by brute force, with mass ultralisks or mass guardians. The actual ending did feature brute force, but more elegantly applied.

a plague on all your tanks!

Dark swarm ensured that zerglings would break the front. Rubble of bunkers and turrets lies everywhere. Tanks rain splash damage from above, but as zerg reduced the natural, the defiler (selected) threw a plague over every tank. When the mutalisks visited them, the tanks popped like so many bubbles.

Very satisfying. All that work on defilers was worth it.

Steamhammer 3.0 status

Steamhammer 3.0 will be coming out “real soon now,” as we used to say, meaning “later than I ever thought,” thanks to my ambition to throw too many features into it. I originally wanted Steamhammer to participate in AIST S3, but I think I will probably skip it. I don’t expect Steamhammer to be upgraded to BWAPI 4.4.0 and working reliably by then. The last day to register is 15 February, so I have time to change my mind. But I want to concentrate on new features rather than on tightening the bolts for tournament play.

Here’s the main new stuff. I chose to delay work on pathfinding, overlord control, and scouting for now, though they are high priority features for good play, and are on my must-complete list for AIIDE 2020. (No plan survives contact with the next minute.) I suppose they’ll go into versions 3.1 and following. I was more interested in the skill kit and other infrastructure additions; they hardly help Steamhammer in the short run, but lay a foundation for faster improvement in the future. That’s what seems important now, foundation laying.

The skill kit to make the opponent model extensible.
• Basic proxy skills, including new macro locations like @ enemy natural.
Resource tracking to remember minerals and gas on the map.
• Followup on burrow, with many new burrow openings and tweaks to the Watch squad skill.
• Followup on queens, with slightly improved behavior and support for larger queen numbers.

The skill kit feels like my best new idea in a long time, so I was excited to do it right away. The initial skills will be gas steal (replacing the current opponent model code with something a little smarter) and a unit timing skill which doesn’t control anything in itself but only records information for the rest of the program to refer to. They both fit into the framework. I expect the skill kit to speed up strategy work and to help make Steamhammer more and more adaptive over time.

Proxy openings are amazingly complex to execute well. A bot needs building placement skills, the right worker control, and special unit production and tactical skills. Steamhammer 3.0 will have only some of the skills it needs, but it should at least be able to pull off a simple plan like building a barracks in the center and then bunkering the enemy natural. Even that takes infrastructure work that I haven’t finished yet (partly because I changed plans in the middle). The work will bring extra flexibility that will be useful in other situations too. For complex proxies that can’t be written in data as opening build orders but require code—write a skill for the skill kit, that is one of its purposes.

There are also, of course, the usual new openings and small fixes and tweaks.

the story of a trapped drone

In a game Steamhammer - McRaveZ on La Mancha, McRave pulled drones to try to survive.

unsupported drone

But what happened to that one drone that seems to be leaning over the chasm? It collided with other units and was pushed across unwalkable terrain to a new position where it was trapped.

zerglings can’t reach the drone

Steamhammer’s zerglings desperately want to get at that drone, but they can’t... quite... reach it. The zerglings were nearly useless for the rest of the game, distracted by the stuck drone every time they reached the enemy base. Steamhammer floundered until it finally remembered that mutalisks are also a unit it can make.

Here is the walkability map. Steamhammer actually checks that it can reach the drone target, but the check is incorrect in this case: There is a narrow corridor, one walk tile or 8 pixels across, leading to the little platform where the drone waits. No unit is narrow enough to walk there (even a ghost is 15 pixels wide), but Steamhammer doesn’t know that.

8x8 walk tiles

The imprisoned drone illustrates a flaw in the map design: Accidents should not push units into places where they will be permanently trapped. Freakling would never allow such a blunder! Of course it also illustrates a bug in Steamhammer. The bug makes a regular appearance on a few maps, like Fortress, but this is the first time I’ve seen it affect play on a regular SSCAIT map.

Next: Steamhammer status. Soon: Some of Steamhammer’s best recent games.

the strange question of reaching a refinery

You’ve located an enemy refinery building and you want to know whether your ground units can walk there to attack it. Is it on ground that they can reach, or on an island? For other buildings, Steamhammer solves the reachability problem with a partition map: Areas reachable by ground from each other are in the same partition, and 2 simple lookups tell it whether one point is reachable from another.

Refineries are trickier. First of all, a geyser is not walkable ground, so properly speaking it doesn’t belong to any partition. The same for a refinery built on it; every other building is built on ground that can be walked over after the building is destroyed. This actually causes a rare bug in Steamhammer, where the ground squad understands that it cannot attack an island—except for any refinery that may be on the island, it may attempt to attack that! It knows that a refinery building is a special case, but it doesn’t understand the special case correctly.

Of course, the problem can be solved by filling in the partition map for the refinery with the partition that the geyser is in. “Of course”? No, actually it can’t: The geyser itself might be part of the unwalkable terrain between partitions. Imagine a wall on the left and a wall on the right, and a geyser plugging the gap between them. North of the geyser is one partition, south might be a different partition, and there is no way to walk from one to the other. The geyser, and any refinery you build on it, is adjacent to 2 partitions but doesn’t belong to either.

This actually happens in an even more complicated way on maps like Gold Rush and a number of others, where two assimilators form a gate. An assimilator is smaller than a geyser (protoss space warp tech, no doubt), so if you destroy the eggs between the assimilators, units can pass through. But if you destroy the assimilators the gap disappears and the bare geysers block passage. A bot needs sophisticated knowledge of the game to understand the effects.

assimilator gate

I haven’t chosen a way to fix it yet. But it’s clear that geysers and refineries have to be treated with special care.

resource tracking progress and thoughts

Today I put in the workaround for yesterday’s visible vespene BWAPI bug. Steamhammer now considers the gas reserves of an enemy refinery to be inaccessible. At the same time I fixed a rare bug that could briefly give a gas supply of 0, handled mineral and gas amounts of 0 in a more informative way, added features to improve the debug display, and made unnecessary efficiency improvements (“the cost is negligible—but—but—look how much I can reduce it!”). It added up to refactoring most of the code, but there’s not much of it so it wasn’t long.

Some later day I’ll add tracking of the bot’s own mining. Any minerals or gas missing from the map that Steamhammer did not mine were mined by the enemy, putting one lower limit on the enemy’s total resource gathering. Another lower limit comes from counting enemy units. The first use of enemy mining information will be for scouting: Overlord thinks, “these minerals have been mined, I don’t need to fly any farther to know that the base has been taken.” Look at the map Python. An overlord moving from the base at 3 to the base at 12 will encounter the mineral patches first, and can see that they have been mined before it comes into the sight range of any worker doing the mining. Identifying the enemy base even seconds earlier is an advantage worth taking.

The enemy’s resources will be valuable for strategy calculations. The same overlord on Python can judge whether the enemy is playing a low-econ strategy even before it gets close enough to count the enemy workers. The total resources mined by the enemy, as long as we have it, tells us about the enemy plan. It’s possible to find a hard upper limit too, but it seems complicated to get an upper limit that’s tight enough to be useful. Workers can be made this fast, bases can be taken this fast, a mineral patch can be mined this fast, it’s not as simple as counting stuff on the map.

In the long run, I envision an enemy resource usage estimator that takes visible resource amounts as only one source of information. Saved game records in the opponent model would be another, and a library of known strategies might be another. It feeds to an opponent plan recognizer, which feeds to a strategy planner. In my mind, resource tracking is a step along the path to smart strategy adaptation.

Stepping back to take a wider view, there are two ways to be smart: You can learn stuff like CherryPi with its neural networks, or you can calculate stuff like FAP—you can use knowledge or you can use search. I think you should ideally use both, like AlphaZero, because they support each other. Calculated limits on the unknown value of the game state are good inputs to help a machine learning algorithm.

the joy of inferring tech buildings

The picture is from a test game against the built-in AI. The columns on the right are a new debug display. The game was played to test an unrelated new debug display, which is not showing. Because of a newly-introduced bug (success! I’m introducing new bugs as planned!) Steamhammer had trouble against the built-in AI and did not win until late.

test game screencap

The green unit types on the right are Steamhammer’s units. White is the count of completed units, yellow is the count of uncompleted units. Hmm, 19 uncompleted zerglings, an odd number? That is because 2 zerglings in an egg may not hatch at exactly the same time.

The orange unit types are the enemy units. The white numbers count enemies that have been seen, and the red numbers are inferred enemy buildings. For example, Steamhammer has seen observers, so it knows that there must be a robo fac and an observatory. But wait, why are there a hatchery, a hydra den, and a spawning pool among the inferred enemy buildings?

Ha ha, protoss mind controlled a lurker! It’s there on the list of enemy units. Bug 1: The building inference code doesn’t know about mind control. Bug 2: The code also does not know that lurker research implies a lair.

Bug 1 takes effort to fix in full generality, because you have to remember what units the enemy has mind controlled, and Steamhammer doesn’t track that (or need to for now, it’s rarely important). If enemy protoss mind controlled your carrier, you can’t infer from that carrier that the enemy has a stargate and fleet beacon. If enemy protoss mind controlled an SCV and never mind controlled a marine, then you would like to infer a barracks from seeing a marine. For now I put in a simple workaround: Require an inferred building to belong to the same race as the enemy. That will reduce the errors, at least.

Mind control is a very sharp corner case, it can cut.

Bug 2 I decided also to leave unfixed for now, because there is another bug hiding behind it, related to zerg. Inferring buildings from tech adds complexity. If you have seen 1 enemy hatchery and later see a lurker, implying a lair, does that imply that the enemy now has 1 hatchery and 1 lair? No, the hatchery might have morphed into a lair. In effect, a lair is a hatchery and a hive is a lair, but not the reverse. Similarly if you see a guardian, implying a greater spire. Most tricky.