archive by month
Skip to content

Steamhammer 1.4a3 with last-minute bug fixes

New tournament version with last-minute fixes! I set to work on version 1.4 for release around the end of the tournament, and thought, “Well, what could be a better start than a bug fix?” I ended up fixing 2 bugs that could help in the tournament and have low risk of causing other problems. I changed gears, and now 1.4a3 is uploaded.

• Why does Steamhammer sometimes make a hydralisk den versus zerg, when it is explicitly coded to never make hydralisks in ZvZ? Once I realized that it only happens when the opponent went random and rolled zerg, I was able to trace the bug. It turned out that the actions are out of order: Steamhammer first makes its strategy decisions, then checks to see if the enemy race is still Unknown. So in the strategy boss’s first production round after it finds out the enemy’s race (which is usually the first round out of book), it thinks it still doesn’t know. “Hmm, better be ready for anything.” Facepalm!

• In a test game after fixing the above bug, Steamhammer skipped lair tech (in ZvZ!) and rushed to hive for ultralisks. I’ve seen that misbehavior before. It hurts badly when it happens, and the fix turned out to be trivial. A condition was miswritten with && instead of ||.

There must be dozens of play bugs that are hard to trace or even to notice because their effects are rare or subtle....

Steamhammer 1.4a2, tournament version

I’ve uploaded the SSCAIT 2017 tournament version of Steamhammer, which is version 1.4a2. The reason for the strange version number: I promised that release version 1.4 would have a full-up opponent model, and even if I break every other promise, I can keep that one!

Randomhammer is disabled for the tournament (it took me a minute to figure out how to create an empty zip file, since zip refuses to do it directly...). For Steamhammer, I found a number of low-cost low-risk improvements that are enough to make a difference. The new version already has a win against McRave, for the first time in a long time, so I can’t have messed up too much.

• Fixed a crashing bug in assigning units to the Recon squad after losses in the main army require the Recon squad to be downsized. The bug only affected terran, and was related to medics.

• Ranged units target arbiters with a higher priority. By the way, in the strange world according to Steamhammer, scourge are ranged units.

• Fixed a bug in recognizing worker rushes. On one map, enemy workers busy mining could be recognized as “rushing”. Still a strange world.

• A few changes to zerg to be more careful in collecting gas. Turning gas off because there’s a gas excess compared to minerals now happens using the current minerals, not current minerals minus minerals reserved for buildings, so it is more conservative. If there are idle drones, always turn gas on (might as well put them to work). If short of gas, Steamhammer adds extractors faster—it always has, but now it is a little more eager.

• Account for gas usage in planned spending. Together with the gas changes above, this improves the midgame unit mix and army size. Watchers may not notice, but to me the difference is visible.

• Be more thorough in using all larvas. Steamhammer has long had a fallback rule to make zerglings with any spare larvas. I loosened the conditions, and had it also make drones if the army is “big enough” according to an arbitrary criterion. The rule usually fires later in the game, when there are plenty of hatcheries and Steamhammer wants to make more gas units than it has gas for. The result is a bigger army, and again, I can see the difference.

• Tweaks to make guardians less often. I think Steamhammer still makes guardians too often, but it should be closer to right.

Randomhammer crash!

Randomhammer crashed in a game! It’s the first crash since May, except for the untraceable crash. Now I know exactly what to do next.

The crash was in an interesting TvP game against cannon-bot Jakub Trancik. It’s a shame not to see how it continued. Randomhammer went with marines and Jakub Trancik decided to build its proxy cannons below the ramp, so Randomhammer (seeing the pylon with its scout) didn’t pull SCVs but waited for combat units. The first marines were not quite able to stop the cannons, and retreated out of sight up the ramp. Terran and protoss have very few strategic reactions (unlike zerg), but there is one when the bot is making infantry and meets dragoons, tanks, lurkers, or static defense: It adds tanks. It was the correct move; the unit control is clumsy and loses stuff unnecessarily, but the tanks were sieging down cannons and I was starting to think that the play was good enough.

Then CRASH! The crash is in CombatCommander::updateReconSquad() which decides what units are in the Recon squad. It is complicated for terran because there may be medics in the squad, depending on size and composition, so it’s no big surprise that there’s a bug.

To work!

Steamhammer tournament plans

Today I went for a walk in the snowy woods, setting the first footprints on some of the paths. It’s kind of how I feel about working on Steamhammer: At some points I may leave the first prints, but the path was already there. And I feel as though I still have a lot of paths to walk before I can reach wilderness.

For the tournament, I have changed my plans. Trying to hit a deadline makes my code worse and messes with my motivation. Some people thrive on deadlines; I go wrong. So instead of turning on the next opponent model feature as I had been thinking, I’ll do whatever smaller fixes and features seem likely to help. I’ll have to comment out some stuff I’ve just done, but whatever. The tournament version will be 1.4a2 (anyone who’s not confused by the version numbers needs to get back to their real work), and hopefully not long after I’ll put out release version 1.4 with opening selection controlled by the opponent model. I expect that later 1.4.x releases will add more opponent model features, because the opponent model can do many things.

The switch is partly inspired by watching Steamhammer’s 2 recent losses to XIMP by Tomas Vajda. The loss on Heartbreak Ridge I can swallow, because Steamhammer has always played particularly poorly on that map. The loss on Icarus seems to show that Steamhammer is playing worse against the carriers (though it was a long, hard-fought game and many carriers blew up). Apparently delaying the hive, though often good, in this case left Steamhammer unable to batter down bases with ultralisks, because it used all its gas making scourge. Looking closely, I see that it was short of gas in part because it turned off gas for a full minute before seeing the carriers, seemingly due to a bug. Outside of emergencies, zerg should turn off gas only if gas piles up to at least 3 times the mineral count, and here it turned off gas with 1700 minerals and 300 gas. That should be possible only if the building manager reserved a huge pile of minerals to make buildings, and didn’t reserve any gas... it seems barely possible. This is something that can be fixed by a deadline.

Steamhammer 1.4a1 - the rest of the changes

Yesterday I wrote up Steamhammer’s scouting improvements. Today is the rest of the change list.

stuff affecting squads and combat

• Added a parameter setting to each squad: For combat simulation, include either all known enemy units in the area (including remembered units that are out of sight), or include only visible enemy units plus known static defense. For most squads, it is useful to include all known enemy units, so that you don’t attack a superior force when you momentarily can’t see all of it. It’s especially useful for a squad of zerglings, which have a short sight range. The Recon squad is set to fear visible units only, because its purpose is to see what is there.

• The combat simulation radius is also a parameter setting for each squad. The primary combat squads have a large radius so they can try to understand the ultimate outcome of a battle (though it’s questionable whether this is a good idea). The Recon squad has a small radius, so that it does not fear distant units that it is out of range of. That lets it come closer and see more.

• If we can see the last known location of a remembered unit (its lastPosition) and the unit is not there, we flag it as goneFromLastPosition. We keep the lastPosition and know when it was set, so we can narrow down where the unit is now (which is not done yet, but someday). This is a feature from the when the enemy unit is out of sight post. Units which are goneFromLastPosition are skipped in combat simulation, which makes Steamhammer more aggressive. Of course the unit might still be nearby, so Steamhammer is taking a risk, but it seems better than fearing ghosts.

• Squads no longer single-mindedly attack the enemy main. The combat commander prefers to issue orders to attack the enemy base with the least static defense. It’s still not very smart, but the tactical play is much more interesting and varied. There are other tweaks.

• A bug in tactics calculation prevented the combat commander from issuing orders to a squad to attack enemy units, which it will do if there are no enemy bases the squad can attack. Fixed.

• Valkyries, corsairs, and devourers now play much better. Since they are unable to attack bases, the bug fix above to send them to attack units was critical. A new unit micro controller, MicroAirToAir, helps the flying squad make better use of these units. Steamhammer no longer sucks with devourers and protoss corsair openings are stronger.

• Ranged units like to hit air targets that have acid spores on them. Get full value from those devourers.

• Queens, defilers, and dark archons are recognized as combat units and assigned to squads. Steamhammer can’t use any of these spellcasters (yet), but there’s no reason to ignore them.

• Due to mis-nested conditions, if you asked a squad whether it had any air or ground units, flying detectors were counted as ground units. Fixed.

UnitUtil::GetWeapon() makes the simplifying assumption that a bunker has marines in it. It used to ignore bunkers. Someday Steamhammer will attempt to keep track of whether a bunker is loaded, but not yet.

InformationManager::getNearbyForce() includes enemy medics. They were mistakenly excluded by a weapons range check. It was a serious bug.

InformationManager::getNearbyForce() checks enemy attack ranges more accurately. It makes little difference in practice.

InformationManager::getNearbyForce() no longer returns detectors. It is used to feed the combat simulator, and FAP does not support detectors, so it was no help.

• In FAP, added N00byEdge’s September patches: A scarab is a suicide unit, medics heal less.

other

• Recognize some enemy opening plans. This is part of the opponent model. For now, only zerg takes advantage. The plans Steamhammer tries to recognize are named Proxy, WorkerRush, FastRush, HeavyRush, and SafeExpand (which means natural with cannons or bunker). It doesn’t always recognize them successfully, but when it does I find that it is rarely wrong.

• Added the macro act command "go nonadaptive" for zerg, affecting drone production. Zerg normally adjusts its drone production depending on the situation, even if it is playing a book opening. For example, if the book says “make zerglings” but the opponent has cannons, Steamhammer may decide to make a drone instead (it has even more freedom out of book, of course). The "go nonadaptive" command means to turn off this adjustment process for the entire game and trust that the opening book has the situation covered. The new command is used in openings which counter forge fast expand. This version doesn’t play any of those openings, though!

• Steamhammer’s event-driven base tracking system sometimes gets out of sync with reality. Past versions made corrections in some cases. Now all incorrect stored base information is corrected as soon as possible.

MapInfo::getNextExpansion() skips bases without enough resources to be worth it. It should fix occasional cases where Steamhammer re-expanded to a base that was mined out.

MacroAct::mineralPrice() and gasPrice() are now correct for upgrades beyond level 1. See upgrade prices in Steamhammer.

• The configuration file has new flags Config::IO::ReadOpponentModel and WriteOpponentModel. In this version the flags don’t do anything (the file I/O is turned off in code), but in the release version 1.4 they will work. Separate control of reading and writing the files is handy for debugging.

terran and protoss

• Terran and protoss turn off gas collection when there is too much gas, as zerg has always done. “Too much gas” is defined conservatively as 1. over 400 gas, and 2. over 4 times as much gas as minerals, and 3. more gas than is needed to fill all the orders in the production queue. I think the biggest benefit is that the bot can survive after many workers have been killed, when collecting gas causes mineral mining to slow or stop. Gas production starts again when the bot has a use for the gas.

• Adjusted the terran ratio of marines:medics to 5:1. It used to be 6:1, not enough medics. Some people prefer 4:1.

• Added a terran siege-expand opening. Steamhammer doesn’t adapt well enough to play the opening safely in many cases, but I think it should be adequate for TvT.

zerg

• In case of a recognized Proxy, WorkerRush, or FastRush enemy opening plan, possibly break out of the opening and react appropriately. If the opening is already doing something that looks sensible, let it. I did not follow IMP’s advice to not distinguish between plans with the same reaction, because I expect that the reaction will not always be the same (especially for forks).

• In case of a recognized HeavyRush, maybe build a sunken. It is a wimpy reaction, but may help sometimes. This Steamhammer version does not react to SafeExpand, but I hope that the tournament version will.

• Recognize corsairs, scouts, and carriers as countering guardians. What a blunder! That is why Steamhammer kept making guardians against XIMP.

• Recognize goliaths as countering zerglings. Properly, only enough goliaths counter zerglings; their long range makes them deadly in groups. Steamhammer is too primitive to understand that, so far.

• Also what-counters-what tweaks in ZvZ.

• In ZvT, prefer to get lurkers after mutalisks in the standard way. Steamhammer classically rushed to hive, crazy zerg style. I’m not sure whether this adjustment works as intended.

• Always get overlord speed before hive, except versus zerg. This is a concession to the BWAPI 4.1.2 bug that you can’t get overlord speed after hive.

• Prefer to make unit types that already have their upgrades. It’s not a strong preference, though.

• A new “do I have enough units to get away with this?” check to decide when it is safe to tech. For example, if the enemy has air and we don’t, delay less important spending.

• Added a bunch of openings to counter protoss forge expand. This version doesn’t play them, though. I hope the tournament version will.

• Added an overgas 9 pool opening for ZvZ, mostly because it’s fun but also because it’s a good opening.

• Added an OverpoolHydra opening similar to ZZZKBot’s 1 hatch hydra build that it used to defeat Iron in AIIDE 2017. It is a weak build, and I don’t know if it has any other use than to defeat that version of Iron.

• Lurkers can change targets away from a building. See fixing a lurker micro bug.

• Lurkers are little more eager to target a protoss observatory or robotics facility.

• At some point a bug crept in that made it impossible to research lurker aspect if you had a hive. Fixed.

• In ZvZ, get queen’s nest and hive only once you have at least 12 mutalisks. Steamhammer was losing games by teching at an insane rate.

• Other minor strategy changes to mildly encourage making more combat units.

• Never have more than 9 devourers at a time. See too many devourers.

• A new feature is supposed to prevent zerg from stopping gas collection if that will cause drones to go idle. If you have excess drones, you might as well collect gas whether you need it or not. Unfortunately, the feature doesn’t seem to be working, though I can’t find a bug.

code changes with no effect on play

• Renamed the MainAttack squad to Ground. MainAttack used to be a good name, because all the squad wanted to do was attack the enemy main, but now it has wider ambitions. The 3 combat squads are now named Ground, Flying, and Recon.

• The capitalization of MapGrid::getUnits() was nonstandard. Fixed.

• Removed the unused MapTools::_units instance variable.

• Renamed RegroupRadius in the config file, also known as Config::Micro::CombatRegroupRadius in the code, to CombatSimRadius, since that is what it is. A unit that can fire into this radius around the combat simulation center point is included in the combat simulation. Also it doesn’t hurt for the names to be consistent.

• Rewrote UnitData::updateUnit() to be slightly simpler.

• There was still a redundant mention of SparCraft in the VS settings. As far as I can see it caused no harm, but it’s gone now.

• Map-related data structures use short ints to push less other stuff out of cache. I cleaned up the typing of short ints so that the compiler understands that the type conversions are safe, though they were already.

• In FAP, I initialize the closestDist local variables in 3 routines, solely to avoid compiler warnings when warnings are set to a high level. The code was correct, but the compiler is not smart enough to tell.

• All the debug configuration “Draw...” options can be set manually during the game using /set. It can save time in debugging. I had added some options without adding corresponding commands.

• I renamed all the Micro::SmartX routines to Micro:X to reduce noise in the code text. It doesn’t need to brag. For example, Micro::SmartMove is now Micro::Move.

Steamhammer’s new scouting skills

I decided to write up Steamhammer’s changes in parts. Scouting today, more stuff tomorrow. I wrote briefly about scouting improvements in September; here are the details. The scouting changes affect all races, though of course only zerg has an overlord to help. The overall effect of the changes is that Steamhammer collects more information sooner and makes better decisions, so it was worth the effort.

Steamhammer has suffered its usual ratings crash in the new version. I think the voters have the journalistic instinct to comfort the afflicted and afflict the comfortable, and top bots and new versions of well-known opponents count as comfortable. They say to themselves, “Let’s vote in a good challenge,” and in Steamhammer’s case succeed.

Even so, I’m satisfied with early results. I see plenty of familiar misbehaviors, and no surprise bugs. And play improvements are showing. For example, Microwave has opening learning, and learned that 5 pool usually beats Steamhammer’s default ZvZ opening mix. In Steamhammer-Microwave, Steamhammer played a gas-first opening that formerly would have lost instantly to the rush, but this time saw it coming and built a sunken in time to stay alive. It became a good game instead of a smash.

early game scouting

Classic Steamhammer scouting, from December 2016: Pick a base on the map, and send both the first overlord and the scouting drone to that base. It was a hack. The overlord waits there for the rest of its life whether the enemy is there or not, and the scouting drone keeps looking if necessary.

Good scouting: Send the overlord and drone to different bases. Redirect one or both depending on what is seen. Send later overlords to good locations to collect further information.

Steamhammer’s current scouting is in between. It uses only the first overlord and the scouting drone, and against terran doesn’t send the overlord because it still doesn’t understand how to keep it safe from marines. The overlord and drone go to different bases, so that the enemy is often found sooner. When the enemy base is located, the overlord changes its path if necessary to go there, so there is often a better view of the enemy’s play for a long time. If the overlord finds the base first, the drone either goes home or stops by to visit the base, depending on its orders.

I added only one clever feature, inference of the enemy zerg’s location from seeing its overlord. When Steamhammer sees an enemy overlord early in the game and the enemy base has not been located, it considers “what bases have I not yet scouted?” It calculates which of those bases the overlord might have come from, based on its position and top speed. If that narrows it down to one base, then “Bingo! Found you!” This doesn’t quite extract all the available information; it’s possible that seeing the overlord could eliminate one base and leave two possibilities, and Steamhammer doesn’t realize that. But that’s a rare case, and in practice the overlord sighting speeds up scouting fairly often. The feature was definitely worth adding, and it helps terran and protoss too.

I want a more general scout manager instead of the current one that is able to scout with one worker and one overlord. It should be: Dump whatever units you feel are free into the scout manager, and it will figure out how to employ them. I decided it was too much for now, but I’ll probably do it later.

middle game scouting

Most bots, I have noticed, scout only to see what’s up. Even Zia, which scouts in the middle game with a zergling, only sends the zergling to see stuff and doesn’t attack with it.

Purely out of orneriness, I decided to do middle game scouting differently. Steamhammer’s middle game scouting is reconnaissance in force.

When there are “enough” ground combat units for the main ground squad, Steamhammer redirects a small number of them into a squad named Recon. The choice of units depends on race, of course, but only certain ground unit types are considered suitable for Recon. The terran Recon squad can include medics, and there are actually remaining bugs in that. If the main squad loses too many units, Recon may be disbanded to join it.

Recon is another combat squad, and it gets orders to attack bases where the enemy is not known to be. Usually it discovers that the enemy is still not there, and it gets new attack orders. But if it sees enemy presence, then its orders remain the same; the combat simulator decides whether to attack or hold ground. Stray enemy units and naked expansions are at risk. If Recon holds ground too long, then its orders time out and it is given a new location to attack.

I added a couple parameters to squad behavior so that Recon can do its job better, while the main combat squad does its job as always. I’ll write that up tomorrow.

Recon usually moves around pretty fast and travels over most of the map, though it does get stuck sometimes holding ground. The effect of the Recon squad is that Steamhammer finds enemy expansions quickly and has much more vision of enemy army movement. It occasionally prevents expansions or catches enemy scouts or tears down misplaced buildings in the middle of the map, but my feeling is that that is less important. I’m curious to see how Recon copes with terrans that sow the map with spider mines. Recon does get dedicated detection when it is available, but the detector often lags behind. I may need to make changes if it struggles against spider mines.

other scouting-related stuff

• A new feature controls the damage of scouting misses, when the scout worker is lost before finding the enemy base. In past versions, that caused disastrously bad play when the early combat units came out: They scoured the map indiscriminately looking for enemy presence in unlikely corners, and were often out of position when the enemy came knocking. Now Steamhammer recognizes that is is likely to find the enemy in a starting base location, and looks there first. The enemy is found much sooner and the combat squad is out of position for a short time or not at all. It is more aggressive than Killerbot’s approach of leaving the combat units at home until the enemy is found.

• The gas steal works, though this version doesn’t use it. You can configure "go steal gas" and Steamhammer will find the enemy base and try to steal the geyser. Or "go scout" and "go steal gas", and the scout will steal gas and, if it still exists, continue to circle the enemy base. And some other combinations. Getting the gas steal to work for all races and cases was time consuming; the number of bugs was incredible.

• The previous Steamhammer version has a misbehavior when the scouting worker is on its way home: It stops to attack anything stationary that it runs across. It is the standard worker self-defense behavior popping up at an inappropriate time. Fixed.

• When doing worker harass on a map with other than 1 geyser in each main, there was a potential crash. It never happened, but I fixed it.

Steamhammer test version 1.4a1 uploaded

The annual rush of new bots is well underway. The latest is a batch of terran bots from the Charles III University of Madrid, none of which seems to be 100% working yet. One step at a time!

Meanwhile, Steamhammer has been unchanged on the server since September, a longer stretch than ever before. I have been working more slowly, but it has been a long time and I have done a lot in total. But mainly I delayed in order to release 1.4 with the promised opponent model, and yet I didn’t feel like working hard on the model.... And now the 20 December SSCAIT tournament deadline is threatening to wrap around my neck. I’ve made a ton of improvements, and it would be crazy to go into the tournament without a look to see what new bugs I’ve added too.

I’m still not sure exactly what will be in 1.4, but today I uploaded the test version Steamhammer 1.4a1. Why that version number? Because it’s inconsistent with the version numbering scheme I used before, and nothing could be more important than inconsistency!

This version has noticeably more complex and interesting play than the September Steamhammer. Most of the opponent model features are disabled; I expect to turn on more of them for the tournament version, because the gain can be big. But watch this version and you will see much improved scouting in the opening and middle game (to support the opponent model), somewhat smarter decisions from squads (to support the opponent model), better reactions to some kinds of rushes (as a result of the opponent model), and many tweaks to strategy (because it desperately needed them). On the stream, look in the upper left for the new “Opp Plan” line that tells Steamhammer’s inference of the opponent’s intention in the opening. It starts out as “Unknown” and often stays that way the entire game, but sometimes changes to “Fast rush” or “Heavy rush” or one of several other values. A few of the values can lead to dramatic strategy shifts, "Heavy rush" has only a subtle effect, and others are unimplemented and have no effect.

I’ll go into detail starting tomorrow.

Randomhammer’s marines versus protoss

This game Randomhammer-MegaBot 2017 is an example of why it’s not such a good idea to go marines versus protoss. Randomhammer still does it (15% of the time in the live version) because its other TvP strategies are also ineffective.

Stage 1: MegaBot went 2 gate zealots while Randomhammer answered with marines from 2 barracks. If MegaBot had been aggressive with the zealots it likely would have won early, because Randomhammer doesn’t understand early game marine-zealot micro and it lets the marines get hit far too often. But MegaBot did not press. In the picture, the larger zealot army is overcautiously retreating.

MegaBot retreats for no reason

Stage 2: Randomhammer got academy tech while MegaBot was still on zealots. The terran force had been dangerously small because of poor macro, but it was growing. Then the zealots took a bad engagement moving across a bridge in widely separated formation, and got wiped out. Stim is strong, and slow zealots are not the right unit to face marines and medics.

Randomhammer annihilates zealots

Stage 3: MegaBot got dragoons, which it should have done much earlier. Defending the ramp, a small number of dragoons was just able to hold the infantry force that had destroyed far more zealots. The better tactical situation (defending a choke instead of trying to pass through a choke) and better unit choice of dragoons versus marines made a huge difference.

MegaBot narrowly holds its ramp

Stage 4: MegaBot expanded and formed a mixed army of dragoons and zealots. Randomhammer built factories for tanks and also expanded but lost the command center to dragoons. It was partly due to more weak macro (gotta replace BOSS).

The game went on because MegaBot decided not to win on the spot, but morally Randomhammer was lost. In the end, though, MegaBot crashed. The game is also an example of the importance of reliability.

I chose the game to write up because of the stark contrasts between stages. The zealots seemed strong at first, then went poof after stim finished. A trickle of dragoons in the next stage was enough to turn it around again. The game would have been a better example if MegaBot had gotten reavers or storm and showed the infantry some real protoss devastation.

when the enemy unit is out of sight

If you have watched a game of Steamhammer versus Stone, then you have seen Steamhammer’s zerglings chase SCVs all over the map. The lings don’t seem to have the idea that they should find the enemy base and tackle the problem at its source.

if I don’t see you, you’re not there

If Stone’s base has been found, then the zergling squad actually does have orders to go to the enemy base. Why doesn’t it happen? The weakness is in micro targeting: When the squad chooses targets for each zergling to attack, it only considers visible targets. Against Stone, some SCVs are almost always visible and the base rarely is, so the zerglings become infinitely distractible and run hither and yon, chasing whatever pops into view. Eventually some zergling stumbles into the terran base and makes it visible, and then the squad is able to assign things in the base as targets.

The fix is, of course, to choose targets from a longer list that includes the enemy command center or mineral line, even if it hasn’t been scouted yet. I’ve been planning this fix for months, and it has never risen to the top of the list. Steamhammer beats Stone in the end, even if it looks silly doing it. But I can’t put it off too long, because the weakness does lose games against other opponents.

Another curious behavior you may have seen is that, if the zerglings are chasing an SCV that disappears up a ramp, they instantly lose interest and switch to chasing another target. The reason is the same: As soon as the SCV is out of sight, even for a moment, it is not a target. Steamhammer has object permanence and knows that the SCV is still there; it has a system (inherited from UAlbertaBot) which remembers the last known location of each enemy unit. But it can’t use its memory for micro targeting.

if I once saw you, you’re still there

Steamhammer does use its memory to feed the combat simulator with remembered units. If it runs into sieged tanks, it is important to remember them after we retreat out of sight range, so that we don’t immediately turn around and run back into tank fire. There is a curious flaw, though. Steamhammer uses the remembered location of an enemy unit even if it can see that location and the unit is not there! It only updates the location of a unit if it sees the unit again; seeing an empty spot where the unit used to be tells Steamhammer nothing. This is the cause of some strange retreat behavior, where the bot seems to shy away from invisible dangers.

This is, of course, also on my list to fix. I’m not sure what the fix should be. Sometimes shying away from invisible dangers is good, because the enemy units have not moved far. I may add an “it’s gone!” flag to the record for each remembered unit, if I can figure out how to update the flag efficiently (looping through every remembered unit or every visible tile each frame doesn’t feel like a good use of cycles). Then I’ll experiment. I might end up ignoring units which are gone, or using them if they’ve only been gone a short time. Or something.

For now, I added a flag to each squad “fight visible only”. If the flag is false, the squad behaves as now. If the flag is true, the squad does not include remembered enemies in the combat simulation, except enemy static defense, but only visible enemies. Setting the flag makes the squad bolder and more inquisitive; it will also run back into tank fire as soon as the tanks go out of vision. I think it’s suitable for scouting squads. The change is one of my improvements to scouting for the upcoming version.

early experience with Steamhammer’s new enemy opening plan recognition

I’ve been testing out Steamhammer’s new opening plan recognition to get a feel for it. I can summarize my findings in 2 points:

  1. Recognizing the enemy opening plan works pretty well.
  2. The reaction to the enemy’s plan is not easy to get right.

Right now, Steamhammer (development version) recognizes a half dozen different enemy opening plans. I’m likely to add or remove or switch around the recognized plans before release; it is still in an experimental state. The set of plans is not supposed to be exhaustive, because if Steamhammer’s usual behavior will do fine against some plan, then there is no need to recognize that plan. I may change my mind about that the next time I rewrite the strategy boss.

Plan recognition makes few mistakes of commission. I mean that, once it has decided what the enemy is doing, in my tests so far it seems to rarely change its mind (which it’s allowed to do as much as it wants) and rarely be wrong. On the other hand, it easily makes mistakes of omission, leaving the plan as Unknown because it doesn’t have enough information to draw a firm conclusion. I think it will take experience to learn whether that is a good tradeoff. I may want to relax conditions or add smarts.

Reacting to the enemy’s plan is a different story. So far, Steamhammer has a special reaction to worker rushes only, not to any of the remaining 5 possible enemy plans.

Opening plan recognition has 2 points. One point is that it will (it doesn’t yet, but this step is easy) tie into the opponent model, so that an opponent which usually follows the same plan will face openings intended to counter it. Stone, starting from the second game, will face Steamhammer’s anti-worker-rush opening. The other point is that, if the enemy plays unpredictably, Steamhammer will try to react when it recognizes the plan. PurpleWave and Tscmoo have been sometimes playing worker rushes that Steamhammer loses to, because the live version reacts poorly.

I think I have it working well now, pending more tests, but I found it hard to optimize and debug the worker rush reaction. Only zerg tries to react specially, for now. When Steamhammer recognizes the worker rush, it checks its build order to see whether it is playing an opening that does the right thing. That way, if it is already playing an anti-worker-rush opening or one that behaves similarly for the moment, it will keep calm and carry on. If the build order does something else, like make too many drones, then Steamhammer breaks out of the book opening and falls back on the strategy boss’s idea of what to do. And the strategy boss now has a special idea of what to do about worker rushes, starting from whatever situation Steamhammer finds itself in.

It’s a complicated arrangement, and it was hard to get right. Reactions to other plans will work differently, but even so I doubt I’ll have time to implement more than 1 or 2 more before the SSCAIT deadline on 20 December.

The game info in the upper left corner of the screen includes a line “Opp Plan” with the recognized enemy opening plan, so that stream watchers will be able follow along when the version goes live. It starts out as “Unknown” and changes if and when Steamhammer recognizes the plan. I think “Opp Plan” is a poor description, but I haven’t found a short string that is better (so if you have an idea...).

an implausible game

Today’s game Randomhammer vs Flash is unbelievable. What I mean is, if I didn’t know that the replay was generated automatically by bots playing, I would assume that it was a setup. That should not happen!

Randomhammer rolled protoss and opened with 1 gate and dragoons. Flash put down 2 gates and made zealots, so of course Flash had more units. Randomhammer had an easy defense in principle: Make a fighting withdrawal with the dragoons, to buy time and to put some bruises on the zealots. When and if the zealots reach its base, Randomhammer should have enough dragoons to outmicro the zealots, and it can run probes if necessary.

Randomhammer has no understanding of any of that. The only withdrawal it knows is headlong retreat, and instead of running probes it fought with them. When the surviving zealots were finally driven off, only 2 probes survived. Furthermore, the 2 probes were collecting gas and had no ability to switch to mining minerals, so Randomhammer had zero income for the rest of the game. “Game over,” I thought. It was 6 Randomhammer dragoons, versus an opponent that was briefly behind in units, but now had its own dragoons and 2 running bases.

Randomhammer loses probes

As I expected, Flash soon rivaled Randomhammer’s army size. But I could hardly trust my eyes when I saw the fight. Flash had just started dragoon range, and could not cope without it! The 5 ranged dragoons (1 froze in the middle of the map) outmicroed Flash’s dragoons and remaining zealots by an extreme margin, with Flash rarely getting shots off. Randomhammer smacked down the army and a long stream of reinforcements which came in piecemeal.

a battle of nearly equal armies

Then Flash showed that it is every bit as careless with probes as Randomhammer, and instead of mining safely in the main and building up a ramp defense force while the natural was slowly flattened, kept transferring probes. Randomhammer finished the game with 4 dragoons, having lost only 2 against a much larger number of enemies. Not plausible, only true.

The next Steamhammer version will turn off gas collection for terran and protoss when there is reason to, as it always has for zerg. It’s a simple feature, and I think it will make a difference.

Next: The theoretical right way to analyze the enemy’s build.

recognizing the enemy’s opening plan

I’ve been adding recognition of the enemy’s opening plan to Steamhammer, as part of the opponent model. Besides making the opponent model smarter, the OpponentPlan is directly valuable to the strategy boss. I’ve been concentrating on enemy plans that the strategy boss is clumsy in reacting to.

After writing recognition code for several plans, I already felt dissatisfied with how it works. It looks at buildings and timings, it counts bases, it notices if zerglings are out suspiciously early, all extremely basic stuff. “2 barracks and no gas, I know what’s coming next.” There is no “You should have a second pylon by now, where is it hiding?” and no “I see more zerglings than you can get from 1 hatchery, you must have 2.” Rich and complex inferences can be drawn from the game information, and the primitive code I wrote draws only simple ones.

So I looked at PurpleWave, which does opening recognition under the name of “fingerprinting”. PurpleWave tries to recognize specific openings for zerg and protoss: This is 4 pool, this is 12 pool, this is 10 hatch, etc. And the way it works is, at heart, the same as what I wrote in Steamhammer. It is written in a different style, but it checks almost exactly the same information.

The biggest difference is that Steamhammer does not try to recognize specific opening builds. I think there are too many, and some of the differences don’t matter. The OpponentPlan groups enemy openings into categories, like “this is a fast rush,” without distinguishing between 5 pool and other early pools, or even between 5 pool and 5 barracks and 5 gateway. 2 barracks no gas gets the same plan label as 2 gateways no gas. If you want to react differently to 2 barracks than to 2 gateways, that is for the strategy boss to figure out. I think the plan categories extract more information from the game and compress it into fewer labels for the rest of the code to handle.

Well, if PurpleWave gets away with it then I guess the primitive recognizers are good enough for now. Someday I hope to write a cleverer plan recognizer that draws the deep inferences, that (like a pro) knows when you’re trying to hide a base and triggers a goal to go look for it. Or that says “You’re proxying something and I don’t know what, but I don’t need to see it because the answer is to build turrets.”

when do the first zerglings hatch?

I collected data to calibrate openings so that Steamhammer’s opponent model can make more sense of the opponent’s opening. I thought some of the data might be of interest.

Here are the frame times at which Steamhammer’s first zerglings hatched with different spawning pool timings. These were all measured on Heartbreak Ridge, since the numbers vary depending on the layout of minerals on each map. Also the numbers vary somewhat from game to game, but it’s close enough. Steamhammer has wasted movement, so optimal timing is probably a touch faster.

poolframes
4 pool2630
5 pool2750
6 pool2920
7 pool cutting drones2990
7 pool going to 9 drones3120
8 pool3160
9 pool3230

Making a spawning pool on 7 leaves you with 6 drones. It’s possible to make 3 drones and an overlord before the zerglings, but the lings have to wait for the overlord and are slightly delayed. Instead, you can cut 1, 2, or all 3 drones and get that many pairs of zerglings before the overlord, saving a sliver of time. It’s an interesting tradeoff.

I like that there is a nice spread in the timings. It seems as though each of these builds might have some use, depending on what you think your opponent’s timings are and on how you plan to follow up.

untraceable Steamhammer crash

Steamhammer has had its first crash loss on SSCAIT since May. Or it may have overstepped the time limit. Randomhammer protoss has sometimes broken the time limit, but this is the first for zerg in a long time.

The game is Steamhammer-UPStarcraftAI 2016 (a zerg rushbot), and it looked like a routine Steamhammer win until 5:19 in, when suddenly bam, the 0/0 supply that means crash. Steamhammer has won dozens of these rushbot games without incident.

  • SSCAIT did not record an exception log.
  • If it was a time limit loss, why did it happen in a short game with few units?
  • It didn’t seem like server maintenance either. The games before and after were closely spaced.

It’s a mystery, and there doesn’t seem to be any information to start from.

Steamhammer does still have crashing bugs despite my rigorous eradication campaign. AIIDE 2017 reported 4 crashes out of 2964 games, a rate of about one per 740 games. The current SSCAIT version now has 1 crash in 385 games, which is not statistically different. I found a crash yesterday with a stress test where I forced Steamhammer to play an opening that caused it to lose bases and struggle to recover. After many games, I got one crash. I think I fixed the cause, but the crash is rare and difficult to reproduce, so....

mine-laying framework

What is a good framework for laying spider mines?

Steamhammer’s terran is much better with barracks units than with factory units. To catch up, it needs 2 skills. One is the ability to siege tanks non-ridiculously, and the other is the ability to lay spider mines in reasonable places. Right now it can’t lay mines at all.

It would be easy enough to code up a simple behavior like “lay mines along the path between the friendly and enemy main.” But I’m a little more ambitious. For terran and protoss, Steamhammer is primarily a starting point for authors to build their own bots. I want there to be enough structure that authors feel they can plug in their own mine-laying skills without having to figure out the details from scratch. I don’t think it would take much structure.

A brief reminder of some of the many uses of spider mines:

  • Provide map vision, so you can (for example) see incoming drops.
  • Obstruct paths so the enemy can’t move around as easily.
  • Catch fresh units just coming out of the gateway (say).
  • Deter cloaked units without needing detection.
  • Block expansion locations.
  • Directly attack sieged tanks or dragoons by being laid next to the target.

So what is a good framework for laying mines? I’m imagining something like a list of available behaviors and some way of telling when to use each, but I haven’t come up with a satisfying plan.

What would you do?

Steamhammer-Tyr game

A funny game, a comedy of errors: Steamhammer versus Tyr terran by Simon Prins, on the map Tau Cross. Steamhammer opened with 2 hatch mutalisks, and Tyr bunkered itself in and went with infantry on one base.

Phase 1: Steamhammer fiddled around with its mutalisk force, picking off several building SCVs but mostly wasting time.

Phase 2: Steamhammer happened to notice that the terran mineral line was also a possible target. “Oh, look, terran has SCVs mining. I didn’t know that!” Tyr didn’t defend but moved out to counter instead and lost all SCVs. Steamhammer had 3 mining bases to 0, and only had to survive Tyr’s attack to win. Terran could not reinforce, so that was easy, right?

Steamhammer finds the mineral line

Phase 3: Instead of defending itself, Steamhammer decided to sacrifice every mutalisk against the meaningless bunker. It also wasted units piecemeal against the terran ball. Tyr destroyed the zerg main and natural. Steamhammer lost many drones by sending them to mine gas at bases that were under attack. That makes 3 big mistakes, more than enough to lose.

Phase 4: Tyr spread out to find the zerg 3rd base, found it after a few tries, and then—decided to send its army home to rest. “No zerg anywhere! Not that I’ll admit, anyway.” The marines in the picture saw the base, and that is when Tyr started to send its troops home.

Tyr locates the zerg base

Phase 5: Steamhammer slowly recovered from 7 drones at its third base. It restarted its tech from zero, put down 4 sunkens because it knew there was a scary army out there, and belatedly switched to lurkers. Steamhammer made far too many drones before moving out, but finally sent a lurker and won easily because Tyr had no detection. The mutalisks had also killed the comsat.

In the picture, nothing can stop the lurker, and more lurkers will come. You can see in the minimap that Steamhammer has retaken its main and natural and a mineral only base as well.

one lurker can win

Both sides showed a lack of resilience. This time, Tyr turned out to be lacking a little more. Besides its opportunity to attack and win, Tyr had an unfinished science facility that it could have canceled (it’s in the upper right of the last picture). Then it would have had the resources to make an SCV and get back to mining.