archive by month
Skip to content

Steamhammer next test version 1.2.6

Another test version is uploaded. Almost done. At most one more test version, maybe none, and then the proper release. My attempt to get lurkers to stand off from cannons failed, but it’s not critical. The change list:

• BOSS has a hard-coded limit (in DFBB_BuildOrderSmartSearch::calculateSearchSettings()) on the number of workers. It was restricting terran and protoss to 45 workers. I changed the limit to 75, to match Steamhammer’s intended maximum. I can’t wait to get rid of BOSS.

• Protoss and terran configured limit of workers per mineral patch tuned downward slightly, to spread workers better among bases.

• I broke out InformationManager’s BaseStatus struct into a separate file, renaming it Base (always a good name for a class). I arranged for Base to keep track of its own geysers so it can work around the BWAPI geyser bug. This bypasses BWTA, whose geyser tracking is subject to the bug, and it is another step toward dropping BWTA entirely. It took more refactoring than I expected.

• Using the new Base geyser tracking, I wrote a method InformationManager::getMyGasCounts() which counts taken and free geysers accurately. The old way could be wrong after either a base or an extractor had been destroyed, including after the extractor trick. This should fix a variety of mistakes in starting and stopping gas, building extractors, and so on. It was the most serious of the remaining basic infrastructure bugs.

• I implemented Arrak’s idea of individual attack or retreat for dark templar. It has its own problems, but it seems better overall.

• Zerg collects 300 spare gas before turning off gas collection, down from 400. There are other minor tweaks to turning gas on and off.

• Zerg reacts more strongly to early terran attacks. It’s still not good, but it’s a little improved.

• Aux guardians and aux devourers were badly wrong. It would do things like make 6 devourers to face down a shuttle. Fixed.

• Unused code, different code for doing the same vector and angle calculations, removed from one place and commented out in another.

WOPR Z

I am... amazed by the weird play of WOPR Z, whose name says that it is a zerg version of WOPR by Soeren Klett. Except for the name and the fact that they’re both in Java, I don’t notice anything in common between the jars. WOPR Z is based on Atlantis. I have the impression that Atlantis is not a well-known framework, so maybe more people should check it out.

WOPR Z seems to play the same versus all opponents. It opens pool first, gas, expansion and some zerglings, then builds 5 sunken colonies for defense and goes into mass mutalisks. That’s the entire strategy.

WOPR Z never makes another hatchery, so it is larva limited for most of the game, and it makes far more drones than needed for 2 hatcheries. It also doesn’t know how to recover from losing a hatchery. It’s not a strong player.

The mutalisks stay in a tight ball, which is typically good play (though not always). The mutalisk ball drifts slowly around the map, as if it somehow had trouble holding position. When the flyers accidentally sight an enemy, they pounce. By then the mutalisks are often many, and the target may be demolished in no time. It’s strange to watch.

I imagine that WOPR Z is a first draft that will get more work. Macro hatcheries and expansions, recovering from losses, and scouting for the enemy seem like skills that might be left out of a first draft. On the other hand, Atlantis claims to support most of those skills out of the box. I’ll be watching for updates.

Steamhammer 1.2.5, second test version

Since I got in trouble by not uploading often enough, until the release I decided to move closer to a “give us this day our daily fixes” model. Arbitrary version number 1.2.5 is now up.

The last Steamhammer upload fell in rating to about the same as Randomhammer, a little above 2100. I think the worst new bug is a new production freeze that didn’t happen before. It didn’t show up in my testing, but it seems sort of common in real games. Chasing the enemy scout too much doesn’t help either.

Anyway, for this test version I fixed a bunch of easy weaknesses.

• Fixed 2 possible causes of production freezes.

• If no buildings are in the building queue, recover any idle workers. It’s a quick fix so drones don’t stay idle forever.

• Since early days, Steamhammer has canceled uncompleted buildings that are about to be destroyed. I extended it a little to include lurker eggs and zerg cocoons. Recovering most of the gas from a lurker egg that’s about to die should make a difference.

• Photon cannons count as evidence that lurkers may be a bad idea. I made a few other tweaks to what-counters-what.

• Irradiated air units advance, hopefully leaving their non-irradiated colleagues behind. It’s a quick hack, and I’m not sure how well it will work. Also irradiated burrowed units try not to unburrow, to avoid exposing their friends to the radiation. An irradiated lurker will wait underground until it dies—not ideal, but maybe an improvement.

• Lurkers in small numbers try to burrow out of photon cannon range. It’s crude and definitely doesn’t always work, but I hope the effect will be to set up a containment until more units are available.

• Fixed a bug affecting the terran BBS opening: Units collected at home sometimes stayed there after "go aggressive". It was an interaction with unsticking units, which ironically caused marines to stick.

InformationManager knows that lurker eggs mean the enemy has cloak tech. It didn’t realize until now.

• If we’re planning to make gas units, hurry up and collect gas. If gas was turned off, the bot used to wait until the first gas unit came to the front of the queue.

Steamhammer test version results so far

The new test version of Steamhammer is scoring poorly, dropping in elo, while the new Randomhammer is holding up well. My observations so far:

• Terran marine play is clearly better overall, mostly because medics stay close to marines.

• The terran BBS opening is not as strong as intended, because a new bug tends to cause some or all marines to stay home when they should move out. The bug must have been a late change, because I tested the opening thoroughly. Even so, the BBS smashed Killerbot by Marian Devecka.

• Terran tanks behave differently, but still poorly. Instead of staying put when they should run away, they siege and unsiege even more energetically. Tanks are hard.

• The old drone dance bug, where drones move about erratically instead of mining, is critical. I’m closing in, but I haven’t nailed it yet. There is a new drone dance bug affecting drones sent away to build. Sigh.

• Fixing the bug that sometimes caused mutalisks to separate into widely-spread clumps is an improvement... right? The mutas hang together as they should. So when they’re doing nothing because they’re afraid of bunkers in their path, they do nothing harder than ever and ignore tanks that roll past to besiege the natural. It happened in a loss versus LetaBot. Some problems are bottlenecks that must be cleared, and disorganized mutalisks were apparently not.

• The new lurker play does cause serious trouble for some opponents. In one game, tscmoo protoss never got detection in a long difficult fight and lost, a surprising flaw in a smart opponent. The lurkers also show some easy-to-see weaknesses. Hannes Bredberg’s pure marine play won 2 games versus 1-base lurker builds by exploiting weak lurker coordination and poor decisions from the strategy boss (“we’re out of lurkers? eh, hatcheries are more important”).

• This version deliberately goes lurkers more often than it should in the middle game, so I can see how well it works. I’ve already put in one change for the next version: Lurkers are contraindicated in the presence of photon cannons. Researching lurker aspect versus Tomas Vajda was... not ideal.

• Speaking of Tomas Vajda, that game was a disaster. Researching lurker aspect delayed hydra range and speed for a long time, handing the carriers an advantage. Later Steamhammer decided to make devourers, which was good. But it turned out to be unable to morph mutas into devourers—totally broken, though the code looks right to me. Finally, in a desperate situation but still fighting, Steamhammer lost by busting the per-frame time limit. It is likely due to the slower new SparCraft.

• With the macro improvements, Steamhammer has seen the old bug return of sending 2 drones to start 1 hatchery. The second drone stays idle permanently. I thought of a quick fix.

There are more problems than I expected. That’s what I get for not uploading for so long. I’ll need at least one more test version before the release version.

viewing OpenBW SSCAIT replays after the https change

sscaitournament.com has switched to https, which is an improvement. Unfortunately, the change broke a couple features. For one, elo ratings are not available. For another, the OpenBW SSCAIT listings point to the old http URLs, so the replay viewer does not work. I’m sure things will be fixed up before long, but until then there is a workaround to view replays on OpenBW.

To view replays at OpenBW SSCAIT listings, simply edit the replay URL to https. Choose a replay as usual from the menu. If the URL is wrong, starting the replay will hang, and you have all the time in the world to edit the URL in the URL bar. Find ...?rep=http%3A... in the middle and change http to https.

All fixed now. Ratings and OpenBW are both updated and work again.

Steamhammer test version uploaded, the long change list

I’ve uploaded a test version, which I call 1.2.4 just to keep my folders nicely sorted, of both Steamhammer and Randomhammer. It’s a big version with a ton of bug fixes and several new features. I hope I can get by with only a few more tweaks and minor fixes and put out release version 1.3 shortly. It will depend on how the test version does.

This version configures more enemy-specific openings than ever before. It’s a last hurrah. Most of my time from now until the AIIDE submission date on 1 September will go into opening learning. That version should have no enemy specific openings.

configuration

• Always use race (e.g. "Zerg") not "StrategyMix" in strategy mixes. This fixes a bug in nested strategy mixes.

• A bug caused SurrenderWhenHopeIsLost to be set to true and ScoutHarassEnemy to be set to the value of SurrenderWhenHopeIsLost. It caused Steamhammer to harass with its scout even though ScoutHarassEnemy was configured to false.

• The extractor trick works. BWAPI bug workaround found by Arrak, thanks! I removed the command "go extractor trick", splitting it into "go extractor trick drone" and "go extractor trick zergling". And I updated some zerg openings to use the extractor trick; fast rushes and some 9 pool openings should be a touch stronger.

• On command, pull workers for combat, and release them when done. Workers pulled from mining go into the MainAttack squad (the ground squad, needless to say). The commands are "go pull workers n" (pull a given number), "go pull workers leaving n" (pull all except a given number), "go release workers" (send the workers back home to mine). I added a terran BBS opening which pulls workers for added punch. Also the zerg strategy boss has code to pull workers to hold early terran marine attacks, though the code is poorly tested and likely buggy.

map analysis

• The distance map data structure drops unused data and uses shorts to save memory. It should use less than half as much memory and be faster to calculate. I also dropped dead code, like MapTools::parseMap() and MapTools::reset().

• Since distance maps take less memory, I increased the distance map cache size constant allMapsSize in MapTools.h to 40 (from 20). Distance maps should need recalculating less often.

• I fixed a bug in MapTools in analyzing blocked tiles. Steamhammer now consistently considers a build tile (32 x 32 pixels) unwalkable if any of its constituent walk tiles (8 x 8 pixels) is unwalkable. This should correct a few... edge cases.

• Ground distances take map blocks into account. Both mineral patches and buildings that block map paths at the start of the game are considered to block the paths permanently. This only affects distance calculations, not the paths that units follow, but it is the first step.

MapGrid remembers our units only if they are completed. The change is to MapGrid::update(). This reduces wasted memory and computation and implements MicroDK’s suggestion to ignore uncompleted units in the combat simulation.

production

WorkerManager::willHaveResources() sends the worker to construct a building 24 frames early, not 50 frames. When constructing a nearby building, workers now get into position at close to the correct time, so less mining time is lost. They are still late when running off to construct a distant building.

• Better reactions to workers lost in the opening, for terran and protoss. Instead of resetting the build entirely, Steamhammer now replaces the lost worker and tries to get back into the flow of the opening. In some situations where it’s urgent it may make a combat unit. I tried the same change for zerg, but it turned out to interact badly with the extractor trick and I haven’t had time to debug the interaction yet, so the reaction is disabled for zerg.

• Fixed a major bug that caused drones to go permanently idle in the base. That bug cost a lot of games. It primarily affected zerg, but theoretically could affect the other races on occasion.

• From time to time, randomly change the choice of “main base” where all buildings are constructed. Actually it changes pretty often. The main goal is to fix the protoss “my main is full, I can’t build anywhere” issue, the root of many protoss losses. The change affects all races, although it sometimes has bad effects, prompting terran and zerg to build unsoundly toward the center of the map. See InformationManager::maybeChooseNewMainBase().

SparCraft

• The new SparCraft version. A goal of this test release is to find out whether the new version is fast enough to be usable. The question may be moot—even if it turns out plenty fast in practice, there’s a strong chance that I’ll switch to FAP.

• I modified SparCraft to reject suicide units (scourge, infested terrans) which it claims to support but doesn’t.

• Exclude unpowered photon cannons from the combat simulation. Steamhammer used to fear cannons that had no pylon.

• Spore colonies are simulated poorly, so drop enemy spore colonies and drop 6 of our mutalisks for each spore dropped. It’s a rude hack.

other tactical changes

All the tactical changes should be real improvements, and some of them are big. Steamhammer should make fewer gross tactical blunders for all races.

• Combat workers are placed in a combat squad, and are no longer controlled by WorkerManager. They’re treated the same as other melee units. They should fight a little smarter when pulled.

• Some units that get stuck are immediately unstuck. Random stray zerglings are no longer left behind like a trail of breadcrumbs. Unfortunately dragoons still get stuck sometimes, and I have seen a hydralisk get stuck too. I cured one sticking disease, but there is at least one more.

• Units hurrying to defend a base no longer ignore enemies that are in their path, but stop and fight them if they are too close. This should reduce cases of tactical disintegration where Steamhammer sends would-be defenders crashing blindly into enemy armies, losing without a fight.

• I changed the retreat timer. When UAlbertaBot decides to retreat, it starts a timer and does not attack again until the timer runs out, to reduce indecisive play. Even though it can’t attack, it repeats the combat sim while the timer is running, and if the sim still says to retreat then it resets the timer to zero. Steamhammer now 1. has a shorter timer, and 2. doesn’t repeat the combat sim until the timer runs out. The effect is that fewer combat sims are run, and the bot reacts faster when the situation changes (and the code is simpler, an improvement from every angle). For example, suppose the bot is holding back in front of a strong protoss army. If a probe pops out, UAlbertaBot and past Steamhammer versions will retreat from the probe and look like an idiot until the timer runs out—and the timer was just reset, so it will run its full duration before the bot reacts. Current Steamhammer will still retreat until the timer runs out, but that will take only part of the full timer duration, and the chance of killing the probe is higher.

• The unit closest to the enemy is found by air distance for air squads, rather than by ground distance. Squad::unitClosestToEnemy() is updated. For air squads, this affects detectors, the combat simulation, and regrouping. It also fixes a severe mutalisk retreat bug: Mutalisks retreated by ground distance, so as soon as they went over a wall or reached impassible terrain, they believed they were safe. That bug brought a lot of losses. Using ground distance causes problems even for ground units, but I’m leaving it for now to see how it does.

• Regrouping is slightly simplified, and no longer has a case which checks the base location. MicroManager::regroup() is updated. This fixes a common mutalisk positioning issue where mutalisks string out over a long distance instead of grouping up, and should help ground squads too. I couldn’t find any disadvantage in my testing, though theoretically it could be harmful for slow units fighting against faster enemies.

• Don’t try to retreat ground units to a spot they can’t reach. Ouch. Squad::calcRegroupPosition().

• Smarter targeting for proxy buildings. On some maps (like Python), bases are close by air and some enemy buildings in the enemy main could be close enough to count as “proxy” buildings. Mutalisks would target the “proxy”, attack the buildings and ignore units, and die. Even in a true proxy, attacking the buildings and ignoring enemy units caused awful blunders. I think all the disasters are now avoided.

• Reavers are higher priority for targeting; they weren’t being sniped when they should be. Steamhammer is skilled at sniping high templar with its mutalisks, but tended to overlook reavers. Plus a few other targeting tweaks.

other code changes

• A bug fixed in ScoutManager::enemyWorkerToHarass(), which chooses which enemy worker our scout should poke at. It was intended to choose the enemy worker closest to the enemy geyser, and now it does. I made other minor tweaks to ScoutManager along the way.

• Minor cleanup of worker defense code. This should have no visible effect on play.

• I renamed WorkerManager::getClosestEnemyUnit() to findEnemyTargetForWorker(), since that’s what it does.

• Arranged for a bit more constness in BuildOrderItem references.

• Simplified some base defense code.

• Fewer beeps from BOSS. Someday I’ll get rid of BOSS, and until then I don’t want to see so many exceptions on the screen.

• Added a trivial Random class to centralize random number generation, which is now used in a few places.

getAir2GroundSupply() now includes carriers. The bug was caught by bftjoe.

UnitUtil::CanAttack() understands floating buildings. It used to treat them as if they were on the ground.

UnitUtil::GetWeapon() understands carriers and reavers. It used to say they had no weapon.

• I renamed MapTools::getGroundDistance() to getGroundTileDistance(), the ground distance between two positions in units of build tiles. To get the approximate ground distance in pixels, I added getGroundDistance(), though it is only 32 * getGroundTileDistance(). That way ground distances are on the same scale as air distances from unit->getDistance(), which is also in pixels. But the 32 pixel granularity leaves them a little tricky to compare.

• I removed UAlbertaBot’s opening learning code, since I won’t be using it.

• I fixed a parenthesis mistake in GameCommander::setCombatUnits() that could cause a worker to simultaneously be a scout unit and a combat unit. I couldn’t find any bad effects from the mistake, but it was definitely a bug.

protoss

Protoss only has a couple changes, and they are minor.

• I made the PvZ forge expand opening more likely. It’s working better than I expected, given the poor building placement.

• UAlbertaBot has a “dark templar never retreat” rule so that undetected dark templar aren’t unnecessarily frightened off by large armies. In UAlbertaBot a squad with dark templar usually consists entirely of dark templar, so the rule was simple: If we are following a dark templar opening, and no dark templar has died yet, then the squad does not retreat but keeps attacking.

In Steamhammer the squad often contains visible units as well. The visible units do not retreat either and die pointlessly—even if no dark templar has come out of the gateway yet. The correct fix is to understand dark templar better, but as a quick improvement I put in a different rule: If the squad contains a dark templar, and no dark templar has died yet, the squad does not retreat. It depends on the contents of the squad rather than on the opening, so it behaves a little less foolishly.

terran

Terran has a bunch of changes, and they should substantially improve terran play.

• New BBS opening pulls 4 workers to buffer the marines. The in-base BBS with pulled workers crushes Steamhammer’s mutalisk openings as flat as Tyr’s (by Simon Prins) center BBS does.

• Medics retreat properly.

• Tanks don’t siege if they know they will immediately unsiege again. In the previous version, if a zealot ran up to a tank, then the tank got into a siege-unsiege loop: It unsieged to fight the zealot, then sieged again because it had a target, and would have repeated the process if it lived.

• Tanks are able to unsiege to retreat.

• Make a science vessel if the enemy has cloaking tech.

• Science vessels join their squad as intended. They weren’t counted as combat units, so they used to sit idle by the starport.

• Bio openings add tanks when tanks counter the enemy unit composition. The combination of a vessel and tanks gives Steamhammer terran the ability to fight lurkers with a bio opening.

zerg

Zerg has the most changes of all, but the zerg changes are complex and not as well tested as the others. Probably some will make play worse, and some may not function at all. There are substantial additions and changes to the zerg strategy boss, and it has been hard to get it tuned. Also, since lurkers are new and I want to see how they do, Steamhammer deliberately prefers lurkers in many situations.

• Support for lurkers, guardians, and devourers. The guardians and devourers are particularly likely to be mistuned and/or broken.

• Lurker micro is completely rewritten and much improved. It needs more improvement, but it should be in the same ballpark as other zerg bots’ lurkers. Good enough for now.

• There’s a concept of “auxiliary units” which are made in a fixed quantity. If Steamhammer has lurker tech and its current unit mix does not include lurkers, it may throw in a small number of lurkers anyway depending on the situation. Similarly for guardians and devourers. The variety puts pressure on the opponent to respond. Aux units are also used to produce hydras before lurker tech is done, so some are available to morph right away, and the same for mutalisks and guardians/devourers. I think of aux units as a hack to get by until I write a proper system with flexible production goals.

• Steamhammer tries harder to make enough macro hatcheries. It is improved, at least.

• Ground emergencies are less authoritarian about taking over production. It was causing losses.

• Ground emergencies last 5 seconds (down from 20).

• Don’t compensate for enemy static defense buildings which are proxied. That’s not defense, it’s an attack! So far I’ve seen only 1 game where this would have made a difference, and Steamhammer won anyway, but it is still a bug fix.

• Count a shield battery as enemy static defense. And other changes in strategic reactions to the enemy’s defenses.

• React better to early marine attacks. My attempts down this line so far are too complicated and not very successful. This is another point that is likely to show bugs.

• I added 2 aggressive ZvT openings with low probability, and downgraded other aggressive openings.

• I also added 2 different 1-hatch lurker builds versus terran. One is a 9 pool build optimized for fast lurkers above all, and the other is an overpool build with slightly slower lurkers but a stronger attack. I predict that these fast lurker builds will crush many terrans, though some terrans will survive. Overall, play versus terran should be more varied, more aggressive on average, and less vulnerable to early terran attacks, a weakness of the past Steamhammer version.

• Work around an incorrect calculation in InformationManager of the number of free geysers. The underlying bug was too sneaky for me to solve quickly. This bug caused overhatch openings to sometimes skip getting gas; that part is solved. The underlying bug still causes other problems.

• In ZvZ, make mutas before scourge. This should give better survival chances, on average, when the enemy gets a faster spire.

• I made adjustments to speed up tech switches. They are still far from as smooth and efficient as I would like, and because there are more tech choices they happen more often.

a first look at the FastAPproximation combat simulator

Comments pointed out the new C++ combat simulator FastAPproximation (FAP) by N00byEdge. It’s included in the source of the bot Neohuman, but it has virtually no dependencies and can be easily ported to use in another bot. It is under an MIT license, like UAlbertaBot and Steamhammer, so it also has light legal constraints.

I haven’t tried it yet. No time! Here are my impressions after reading the code.

• I think it’s not quite finished. For one thing, the parent bot that it is part of doesn’t use it yet. For another, it’s still under rapid development. In the last 2 days it has gotten support for stim and medics, and has had at least 2 bug fixes and other changes.

• Even so, bftjoe uses it, so it is in a usable state.

• It’s simple and short and easy to understand. You can read through and easily see its abilities, and its bugs and limitations. SparCraft is large and complex and difficult to understand and modify. I think understandability is a major advantage. If it has problems that affect your bot’s play, you can fix it yourself.

• It supports more stuff than SparCraft. This is a big deal. Unlike SparCraft, FAP explicitly supports bunkers, reavers, and carriers. Overall, SparCraft has major omissions and makes a lot of mistakes with units it does support—for example, the new version claims to handle mutalisks versus spore colonies, but in practice doesn’t do an acceptable job. A combat simulator which handles those things even halfway correctly could have big advantages.

• Its combat simulation is extremely simple. Each unit finds the closest enemy and attacks it as possible, moving toward it until it can. SparCraft has “scripts” that allow much more flexible specification of behavior.

• No support for terrain. SparCraft constrains ground units to walkable terrain. FAP doesn’t read the map at all. Both pretend that units are allowed to freely overlap each other when they move (which in Brood War is only true for air units). Neither understands high ground, which affects visibility and hit probability and makes a giant difference. So SparCraft has a theoretical advantage in simulating ground battles that are in chokes or otherwise affected by terrain obstacles, while both are weak in coping with high versus low ground.

• It ought to be reasonably fast due to its simplicity. With the addition of a location-indexed data structure to find nearest targets quickly, it could be made very fast.

• Other limitations: I didn’t notice any support for suicide units (scourge, infested terrans, spider mines). No splash damage. No support for most spells, not even repair (only stim and medic healing). Details for bunkers, carriers, and reavers are simplified.

• Bugs: The range bonus for a bunker is added on only 1 of 2 #ifdef paths. When a bunker is destroyed, it seems that the 4 fictional marines which are assumed to be in the bunker also disappear, so bunkers will be underestimated.

the usual infinite Steamhammer delays

I thought I would have a test version of Steamhammer up by now, but I am too ambitious. I keep finding problems in recently-written code and feeling that I have to fix them. Or realizing that there’s an “easy” fix for a difficult bug and spending over a day getting the fix correct. Yesterday Arrak found a bug in an error case of the extractor trick code, and I fixed that too although it should be somewhat rare. I am resisting the temptation to immediately try out the extra-simplified combat simulator FAP. The test version will be ready soon... or soon-ish. I hope.

the many uses of the extractor trick

In a comment to next up for Steamhammer, MicroDK speculated (correctly) about the purpose of getting an extra pair of zerglings using the extractor trick. Liquipedia has an entry on the extractor trick but does not mention all of its uses. Steamhammer’s upcoming “go extractor trick drone” and “go extractor trick zergling” only scratch the surface.

An extra drone. The most common use of the extractor trick is to get an extra drone early, going to 10 drones while your overlord and hatchery provide only 9 supply. When you are at 9 supply, as your minerals approach 100, start an extractor. Using up the drone takes your supply down to 8, so you can start another drone and return to 9 supply. Then cancel the extractor to get the drone back and you have 10 supply in units. You can do it any time you are supply blocked, but it usually only pays off at 9 supply when your build order is such that otherwise the extra drone would wait a long time.

Extra zerglings. The second most common use of the extractor trick is to get an extra pair of zerglings when rushing with a 4 pool or 5 pool. When you reach 9 supply, instead of starting an overlord right away, do the extractor trick and spawn zerglings. They’ll be earlier than if you waited until after the overlord, which puts more pressure on the opponent. 4 pool rushbot ZZZKBot never builds a second overlord, but keeps its supply down by constantly attacking and uses the extractor trick whenever it can to get more zerglings.

Exceed max supply. Protoss mind control famously allows protoss to exceed the 200 supply limit. Zerg can also exceed the 200 supply limit with the extractor trick. It’s not practical and I’ve never seen it happen, but I can imagine the situation: You’re at 197 and you want just one more ultralisk (4 supply) before your attack....

The double extractor trick. If you have 2 drones and 2 geysers, you can do a double extractor trick: Make 2 extractors and go over your supply limit by 2. It’s rare, but I have seen it in a pro game. Or if you have 3 geysers, etc., though I’ve never seen that and doubt it would be useful.

Field repairs. Another side effect of starting and canceling a zerg building is that an injured drone is restored to full health. It’s still called an extractor trick even though the purpose is different. If your scout drone is harassing the enemy base and gets hurt, it can use the geyser in the enemy main or natural to bring its hit points back and harass some more. It’s common in pro games, and I intend to eventually implement it in Steamhammer. Or if you’re being rushed, you may be able to rescue a drone that is in danger of dying.

Other buildings. Nothing says that you have to use an extractor for the trick. Any zerg building will do. An extractor is the cheapest, 50 minerals, and can be built away from the zerg base wherever there is a geyser. If you have creep available but no geyser (maybe you’ve already taken your gas), you could build a creep colony instead, 75 minerals. If all you have is open ground, you could build and cancel a hatchery at 300 minerals—though it’s hard to imagine a situation where that would pay off.

It’s kind of depressing how limited and stereotyped bots are in using flexible tricks like this. Someday we’ll do better!

the economics of bot development

In yesterday’s post, LetaBot commented “Pretty easy to hold as long as you pull back [hurt workers].... After all, you can outproduce the opponent.” Of course the details are more complicated than that; you have to get your workers to coordinate to some degree, at least pulling the right number to fight. But in substance, it’s true. The worker rush is not a sound strategy and can be defeated every time. Worker rush bots so far (Stone, then a LetaBot version, now PurpleTickles and Yuanheng Zhu) have found new wrinkles and scored wins against top veterans, but actively developed veterans quickly patch their defense skills and recover.

Even so, it can make sense to play a worker rush, as an option against some opponents. As PurpleWaveJadien also commented, in a round robin tournament “getting an additional win versus weaker opponents is as good as getting an additional win versus stronger opponents (and easier).” The worker rush makes sense because of the economics of bot development.

Think of it from the point of view of a new bot author. Your creation is freshly uploaded to SSCAIT and it doesn’t have many skills yet, but it does win sometimes. What should you work on next? It depends, but probably basic macro and micro skills will lift your elo rating the most. It’s a cost-benefit analysis; for a given development investment, seek the bigger benefits first. You can put effort into worker defense later, when it becomes a bottleneck skill.

Worker defense in Steamhammer (such as it is) had a bigger benefit than I expected, which means I likely put it in later than I should have. But Steamhammer was already an above-average bot by then, in the top third or quarter of the rankings. For a below-average bot, the benefit is probably small; you will lose most games to stronger opponents by being overrun with too many units because you didn’t keep up in macro, or by mismicro or misreaction due to missing skills. The basics are a better investment.

But as long as many bots are missing defense skills, other bots will exploit the missing skills. They’ll play worker rushes or whatever else is easy for them to code and more difficult, or not yet worth it, for their opponents to respond to.

As long as we have a steady stream of new bots, rushbots and other cheap exploits will make economic sense.

PurpleTickles

PurpleTickles is a new bot in the Purple family. It plays a 4 probe rush, mining only with the 1 probe it makes with its initial 50 minerals. It never sets more probes mining, either, so the 4 probe rush hits hard but builds slowly.

On a 2 player map it’s a dangerous rush that gives trouble to strong defenders like Krasi0. The 4 probes arrive in a group and stick together to fight in coordination, so the defender needs skill to hold. The style is quite different from Stone’s SCVs, which act independently most of the time and gang up only when they spot an opportunity.

I haven’t seen a game on a 3 player map. On a 4 player map, the rush is naturally much weaker. PurpleTickles scouts with 2 probes and leaves 2 in the center to join in faster when the enemy base is located. Consider the 4 player scouting options for a 4 probe rush; there are 3 bases to scout:

  1. Scout with 2 probes and leave 2 at home mining until the enemy is located. The worst case is when the enemy is at the unscouted base. That happens 1/3 of the time and has 4 probes arriving more or less simultaneously at the enemy. The extra minerals make the followup stronger.
  2. Scout with 3 probes and leave 1 at home mining. This always gets 1 probe to the enemy base as soon as possible, and the others arrive more or less simultaneously. Compared to option 1 it hits a little harder 1/3 of the time in exchange for a slightly weaker followup.
  3. Scout with 4 probes, sending 2 to one base. Compared to option 2, it hits harder 1/3 of the time when the double probes reach the enemy first, and the followup is a little weaker again.
  4. Scout with 2 probes and leave 2 in the center, the PurpleTickles option. The center probes can join the fight sooner than a probe at a base, whether it is the home base or an empty base. So there’s a 2/3 chance that the enemy is hit by 1 probe, then 2 more after, then another; and a 1/3 chance that the enemy is hit a little later by 2 probes, then 2 more after.
  5. Scout with 3 probes and leave 1 in the center. The enemy is hit by 1 probe, then 1 after, then the final 2 probes.

Intermediate plans are possible, with probes mining part of the time and staged in different locations depending on the map distances, but these 5 seem to be the main options. I don’t see much difference between them, but the PurpleTickles option seems plausible if you believe that hitting as hard and early as you can is best, and that the followup is less important.

I noticed that the rushing probes choose their attack goals along a straight line from the base entrance. They are more successful when they arrive at one end of the mineral line and attack from one end to the other, when they face few enemy workers at a time. They are less successful when the minerals lie at right angles to the line from the base entrance, so that the probes aim for the center of the mineral line and meet many enemy workers at once. An injection of smarts might improve that.

PurpleTickles is moderately successful overall, but it does have wins versus Iron (Iron apparently suffered a bug and never built a barracks) and versus Krasi0. Notice Krasi0’s trick of building its depot and barracks in an out-of-the-way location so that the attacking probes never bother them. It seems like a clever idea versus a probe rush.

Yuanheng Zhu coincidentally uploaded shortly after with nearly the same strategy, though the code is unrelated. On a 4 player map, it scouts with option 3 above. It also crashes when its probes arrive at their scout locations, so we haven’t seen how well it plays yet.

Update: Yuanheng Zhu succeeded in playing one game versus Sungguk Cha. Maybe it works on 2 player maps? The strategy turns out to be quite different from other worker rushes: 1. The 4 rush probes initially attack mostly buildings, not workers, presumably to stay safe for the followup. 2. The bot does not send more probes to attack, but sets new probes mining. 3. It builds a pylon and forge in its main, then adds a pylon and cannons in the enemy base, switching into a cannon rush. Most cool.

Other good stuff to build in or near the enemy base are a shield battery and gateways. I’m sure bots will do that too one of these days.

next up for Steamhammer

I’ve been working behind the scenes and haven’t made a release in a long time. It’s partly because I haven’t finished my original plan, and partly because I keep putting off the item that I promised next, the public repository. I should update everybody on Steamhammer plans.

My original plan was to mainly fix bugs for the next release, and call it version 1.2.4. Debugging gets dull. I have almost but not quite finished with the most critical bugs I planned to squash. I keep tempting myself into adding features instead.

My new plan is to put out a test version sometime soon. When everything is shipshape, I’ll call the release version 1.3, since there are major new features. They are:

  • New SparCraft version.
  • Calculate ground distances taking map blocks into account.
  • The extractor trick works (bug fix found by Arrak). I extended the commands to “go extractor trick drone” and “go extractor trick zergling” so you can choose the unit you want.
  • Added a “go pull workers n“ command to pull n workers for combat. They join the ground attack squad. Useful for all-in rushes (and in principle for reacting to emergencies, though then you might want them to join a defense squad).
  • Zerg strategy boss supports lurkers, guardians, and devourers.

Plus there are many bug fixes and minor improvements, and openings that use the new features—including all 3 of the new “go” commands.

Steamhammer will not participate in CIG 2017, as LetaBot noticed in a comment. But it should be in AIIDE 2017. After version 1.3, the next version will be 1.4 for AIIDE, with opening learning as the major new feature. I’ll keep that as my secret weapon for AIIDE and release it after submission closes.

a few fun games

I wrote up a few fun games between Steamhammer and its rivals. The first of the two games against McRave is especially exciting.

versus Arrakhammer

Arrakhammer is successful, but its ZvZ matchup is not as strong as the others. It has been losing a lot of games to Steamhammer and winning rarely. In Arrakhammer vs Steamhammer, Arrakhammer went with a fast mutalisk opening and Steamhammer chose a zergling opening. Arrakhammer made 3 sunkens to hold the zerglings... and they weren’t enough.

Steamhammer hit a bug this game (fixed in the next version). It intended to take its gas early, but incorrectly thought it couldn’t. If it had played as intended, it would have had fewer zerglings but they would have had speed, and I don’t know how the game would have gone.

versus McRave

McRave has been playing a lot of games against Steamhammer, with increasing success. McRave has been opening with forge-expand—it may sound simple but it is a sophisticated build that is difficult for a bot to master. Steamhammer plays its usual random selection. Many of the games are stomps for one side or the other. Here are the 2 I found the most entertaining.

In a game on Moon Glaive, Steamhammer went 12 hatch into 3 hatch ling, which sometimes breaks the cannons and wins outright. Not this time, though. Both sides struggled with weaknesses. Steamhammer went hydras and then switched to mutas, then switched back to hydras, repeatedly suiciding units all the while. McRave blocked its dragoons in its base with buildings and only got zealots out on the map.

McRave maxed its supply earlier, capping its workers at 60 probes and saving the rest for army. Since only zealots and probes got out of the base, Steamhammer was able to take the map and grow a larger economy, going to 75 drones. Finally Steamhammer got ultralisks and, nearly maxed itself, busted the cannons, letting McRave’s army free. What would win, the bigger army or the bigger economy?

Protoss held the ramp. The ultras could not break in. The battle went on and on and on as both sides burned resources, and the blue ramp on Moon Glaive will probably be red forever. Both bots controlled their units poorly in the usual bot way—more moving than shooting, all butting heads and no finesse. Eventually reavers and storm forced the zerg back and protoss gained map control for the first time.

With its ample economy, Steamhammer was soon maxed again, while protoss had lost many probes in the fight. Protoss had held its ramp, but could not maintain map control for long. A detachment with ultralisks defeated the reavers in the center while most of the zerg army reduced the protoss main, and only mop-up was left.

A game on Andromeda went differently. Steamhammer chose a less economic opening and reacted sluggishly to the cannons. It ended up going mass lings with mutalisks. This time McRave was ahead in both army and economy.

Protoss moved the army to protect a center expansion. Mutalisks had been picking off probes from the undefended mineral only base, and eventually they moved forward far enough to notice that the defending units had departed. Muta-ling broke the cannons and rampaged through the 3 protoss bases around the main. Probes died, and suddenly zerg had a chance. Would the protoss army get back in time to defend?

McRave reacted not by defending, but by countering Steamhammer’s distant corner expansions. Zerg ought to have finished off the protoss tech and production before anything else, but that is not how Steamhammer is coded. Zerg ran to defend, creating a complex situation—and Steamhammer is vulnerable to tactical collapse in complex situations. The zerg units in the picture are not attacking the mined-out center expansion, they are moving past the enemy while taking fire. On the minimap, notice the diagonal line in two colors. It was a debacle.

reacting to build order disruptions

The live version of Steamhammer, when playing terran or protoss, tries to recover from a disrupted build order using a method inherited from UAlbertaBot: When it loses a building or a worker, it throws away the now-broken production plan and calculates a new one from scratch, using BOSS.

It’s not a very effective method. Games against Stone show why. When Stone kills a worker in the opening with its SCV rush, BOSS usually calculates a plan that says “OK, let’s build some gateways/barracks and workers, and later we’ll get combat units.” Then Stone kills another worker, the build is interrupted again, and BOSS says “OK, let’s build some gateways/barracks....” Steamhammer protoss beats Stone reliably because its probes fight well, but it often ends up with several extra gateways before it can get a zealot out and turn the tide. Steamhammer terran rarely gets a marine out before Stone beats it.

Today I improved the reaction. I didn’t change things when a building is destroyed, because that might genuinely break the build. I thought: If a few workers are lost in the middle game, it’s no big deal, so we can ignore it. If many workers are lost in the middle game, the game is probably over, so we can ignore that too. But if a worker is lost in the opening, we can replace it, and try to stay as close as possible to the original opening.

The code is in ProductionManager::onUnitDestroy().

	// If it's a worker or a building, it affects the production plan.
	if (unit->getType().isWorker() && !_outOfBook)
	{
		// We lost a worker in the opening. Replace it.
		// It helps if a small number of workers are killed. If many are killed, you're toast anyway.
		// Still, it's better than breaking out of the opening altogether.
		_queue.queueAsHighestPriority(unit->getType());

		// If we have a gateway and no zealots, or a barracks and no marines,
		// consider making a military unit first. To, you know, stay alive and stuff.
		if (BWAPI::Broodwar->self()->getRace() == BWAPI::Races::Protoss)
		{
			if (UnitUtil::GetCompletedUnitCount(BWAPI::UnitTypes::Protoss_Gateway) > 0 &&
			    UnitUtil::GetCompletedUnitCount(BWAPI::UnitTypes::Protoss_Zealot) == 0 &&
			    (BWAPI::Broodwar->self()->minerals() >= 150 || UnitUtil::GetCompletedUnitCount(BWAPI::UnitTypes::Protoss_Probe) > 0))
			{
				_queue.queueAsHighestPriority(BWAPI::UnitTypes::Protoss_Zealot);
			}
		}
		else if (BWAPI::Broodwar->self()->getRace() == BWAPI::Races::Terran)
		{
			if (UnitUtil::GetCompletedUnitCount(BWAPI::UnitTypes::Terran_Barracks) > 0 &&
				UnitUtil::GetCompletedUnitCount(BWAPI::UnitTypes::Terran_Marine) == 0 &&
				(BWAPI::Broodwar->self()->minerals() >= 100 || UnitUtil::GetCompletedUnitCount(BWAPI::UnitTypes::Terran_SCV) > 0))
			{
				_queue.queueAsHighestPriority(BWAPI::UnitTypes::Terran_Marine);
			}
		}
	}
	else if (unit->getType().isBuilding())
	{
		// We lost a building. It may be serious. Replan from scratch.
		goOutOfBook();
	}

The main complication is that if several workers are lost, we don’t want to delay the production of combat units while replacing the workers. So if there are no zealots and we can safely make a zealot, we do; and the same for a marine. A more aggressive reaction might be better, but this is what I went with.

Steamhammer protoss now defeats Stone smoothly. You have to watch closely to see when it deviates from its opening book. I expected that Steamhammer terran would still lose, because it doesn’t know what to do when an SCV that is constructing a building comes under attack. In fact, terran puts up a much stronger fight than before and sometimes wins. The marines don’t fight efficiently, but if they accidentally build up a critical mass then they sweep the enemy SCVs away.

It’s hilarious to see Steamhammer tech up to academy while still struggling to clear its base of the SCV rush. In the picture, Steamhammer’s academy is almost finished but it can barely keep marines alive. Shortly after this, more marines came out, the marines happened to group together well, and the SCV rush was suddenly broken. I didn’t see it coming at all.

Steamhammer getting academy, Stone with SCVs

doing away with the BOSS

I think the biggest weakness in Steamhammer protoss and terran is macro (not that they have any shortage of other weaknesses). They rely on BOSS by Dave Churchill for production decisions, and BOSS does not live up to its promise. BOSS often orders more production buildings than it can use, and then does not use them efficiently. It will do things like order up a big batch of workers, or of production buildings, and allow resources to accumulate that could be spent immediately in the existing production buildings. Randomhammer loses game after game as protoss and terran because it does not have as many units as it should. “Never mind that we’re under attack. The factories we have are not enough. Make more factories and leave the existing ones idle!” Steamhammer forks like terran bftjoet also suffer.

BOSS also works more effectively with long build orders, which means that bots tend to react slowly when the situation changes. When the bot makes a discovery (“uh oh, we need detection” or “that’s too many tanks, I should make zealots instead of dragoons”), it has four choices. 1. It can insert an emergency reaction directly into the build order. It does that when it sees dark templar: Protoss makes a forge and cannons, terran makes an ebay and turrets. It’s inefficient and delays regular production, because the inserted reaction and regular production cannot overlap. 2. It can wait for the current build order to finish and call for a reaction in the next build order. If the current build order is long, it may be a long wait before the reaction occurs. 3. It can cancel the build order and call for a new one that includes the reaction along with regular production. The reaction is likely to be slow because BOSS does not offer any way to prioritize. If you say you want an observer, BOSS promises that by the end of the build order you will have an observer; that’s the only promise. 4. It can cancel the current build order and call for a new one with only the reaction. The reaction will be quick but other production will suffer—again, no overlap. You'll get your observer as soon as possible, but in the meantime your gateways will be idle.

BOSS’s strength is that it provides an API that is easy to use. You tell it what units and upgrades you want, and it figures out prerequisites, decides what production and research buildings you’ll need, and gives you back an exact build order that accomplishes what you want (modulo a few bugs, which are minor for protoss and terran). If its build orders were good, BOSS would be great. As it stands, BOSS is convenient but problematic.

I want to drop BOSS to avoid its problems. Who wants to work under a boss when you could be independent? But I would like my replacement to maintain its strength. Here’s what I’m thinking.

The current zerg strategy boss combines “what do we want to make?” and “how do we make it?” into a monolithic module. I want to refactor the two questions into separate modules. BOSS solves “how do we make it?” I’ll replace BOSS with a new production planner that accepts abstract production goals and incrementally plans how to achieve them.

“Abstract production goals” means you don’t ask for exactly what you want, as with BOSS. If you want tanks and vultures, then your production is constrained by the situation. Tanks are gas-heavy and how fast you can make them depends on your gas income. Vultures are limited more by the number of factories. You might emphasize tanks or emphasize vultures, but the production planner should take the income and production constraints into account when deciding how many factories to build and what the ratio between units should be. That should both make the API easier to use and improve the bot’s play.

I’m thinking the input should be a set of goals with priorities. Something like: Tanks with this priority; vultures with that priority; 2 dropships and 2 science vessels as soon as possible without wasting resources; upgrades with some priority, etc.

“Incremental planning” means that the plan is worked out in small chunks so that reactions can be quick. You should be able to change goals and priorities at any time and see results quickly. If you want an observer with high priority, each step along the tech path should take minimum time, and remaining resources should continue to go into your regular production.

That is my idea, as far as I have worked it out. It’s not an immediate plan. I have more plans than time. But I want to get around to it at some point. When I do, I expect Randomhammer’s protoss and terran play to become much stronger. Zerg should be a little stronger too.

lurkers, decisiveness, and partial overlapping solutions

I claim that, unlike other zerg bots, Steamhammer’s lurkers (in the upcoming version) do not burrow and unburrow too often. They are decisive. Not that Steamhammer’s lurker play is exemplary or anything, but at least the bot doesn’t change its mind on alternate frames.

I did it by combining 3 different techniques to increase decisiveness. None solves the problem by itself, but each reduces part of it, and the techniques overlap so that together they create decisiveness.

I want to advertise the meta-idea of partial overlapping solutions. An engineer seeing one problem may think it calls for one solution. In a complex situation, partial overlapping simple solutions are more likely to be robust than one fancy solution. Biological evolution often solves problems with partial overlapping solutions. Take a minute to think about how many different partial solutions evolution overlapped to convince humans to reproduce!

  • Each trick is easy to implement, no more than a few lines of code.
  • The tricks are independent. They don’t step on each other’s toes.
  • The effects combine, each reducing some aspects of the indeciveness problem so that the problem as a whole is much reduced.

1. Never unburrow while a target is in range—any target. Take Killerbot by Marian Devecka as an example; many bots are similar. Marines are more important targets than supply depots, so when a lurker has a supply depot in range but no marines, it may unburrow and move toward the marines. The marines may back up and force it to unburrow again, or may catch it above ground and kill it.

Steamhammer simply stays in the ground and batters down the supply depot. When nothing of the enemy remains in range, then it will unburrow and approach the marines. Lurkers are stronger if the enemy has to come to you, because if you maneuver the lurkers then you have to spend extra time burrowing and unburrowing.

2. Only unburrow at the top of each second. Many bots (I think most) unburrow a lurker the moment that it has no target in range. If you do that when a line of marines is feeding itself into the sausage machine, then the lurkers may spend half their time above ground and lose the fight instead of winning effortlessly.

I simply changed each call

    lurker->unburrow();

into this, unburrowing by the clock.

    if (BWAPI::Broodwar->getFrameCount() % 24 == 0)
    {
        lurker->unburrow();
    }

The slight delay is hardly noticeable when you watch Steamhammer play, but the effect is that a lurker is much less likely to unburrow and then immediately burrow in the same place when another enemy moves into range.

3. Don’t always burrow at maximum range. If you can approach closer without taking too many hits, you’ll do more damage and constrain the enemy’s movement more. For now, Steamhammer implements this idea with an approximation. Each lurker is given an enemy target. If any enemies in the area threaten the lurker, then the target is probably one of the threats. Steamhammer simply checks: Is the single target enemy a threat? It is a threat if it can hit ground and is not a worker. If it’s a threat, the lurker burrows at maximum range for safety. If not, the lurker approaches to within 64 pixels before burrowing (compared to the lurker’s maximum range of 192 pixels).

The implementation is easy. There is not much more to it than changing

    if (lurker->getDistance(target) <= lurkerRange)

to

    int dist = lurker->getDistance(target);
    bool isThreat = !target->getType().isWorker() && UnitUtil::CanAttackGround(target);
    if (isThreat && dist <= lurkerRange || dist <= 64)

The effect is that, when attacking workers or defenseless buildings, the lurkers approach much closer, come in range of more targets, do more damage, stay underground for longer before having to move, and push the enemy farther away. If marines retreat behind buildings, the lurkers do not try to follow, but stop and tear down the buildings first.