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.

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.

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.

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.

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.

Steamhammer wants opening learning 3: lurkers

I rewrote Steamhammer’s lurker micro. Now lurkers fight well enough rely on. They don’t burrow and unburrow too often, unlike most bots’ lurkers. They do tend to be clumsy getting into position in a narrow space, and a side effect of not unburrowing too often is that they may cooperate poorly with other units, but one step at a time. I’m adding lurker support to the strategy boss, because it was past time.

So far I’ve written only 1 lurker opening. I’ll start slow. But as soon as there is a choice of what lair tech to aim for, Steamhammer is faced with the decision. Choosing randomly will lead to mistakes.

Against a terran that goes straight infantry, as many do, lurkers are a strong choice. Against factory units, lurkers are a poor choice (though they can be good for drops and surprise attacks). The majority of terran bots go one way or the other, though some can do either or both. If the opponent’s unit choice can be predicted, then Steamhammer can choose an optimized counter-build from the start. It won’t have to lose time scouting and reacting.

Against protoss, both lurkers and mutalisks counter zealots; any lair tech works. And dragoons are useful against both lurkers and mutalisks; zerg wants zerglings and hydralisks to combat dragoons. So the opponent model tells whether to hurry up and get a lair and how soon to take the second gas. It’s less valuable than against terran, but useful.

Against an opponent that doesn’t bring detection, lurkers are strong against any ground unit mix. The opponent model can remember that too.

Steamhammer wants opening learning 2: zealot rushes

Wuli’s zealot rush beats Steamhammer about 4 games out of 5. UAlbertaBot’s usually wins too. Carsten Nielsen’s wins fairly often, and Lukas Moravec sometimes plays a winning zealot rush. Steamhammer’s weakness is not the initial defense, which holds the zealots for quite a long time. It’s similar to games versus McRave; the weakness is in the transition to lair tech. Steamhammer ends up without enough drones.

Someday the strategy boss will be smart enough to understand the situation and make a safe transition. It will be easier if I improve Steamhammer’s defensive skills, which are simpleminded. But those things take time. In the short run, it’s easier to come up with an opening that beats zealot rushes. Then all Steamhammer needs is to know when to play that opening.

Bots should benefit hugely from opponent modeling, because other bots mostly play in stereotyped ways. Wuli and Carsten Nielsen never deviate from their rush builds. But Lukas Moravec, among others, plays more than 1 build. So to counter zealot rushes, a bot also wants plan recognition. If the scout sees 2 or more gates and a lack of other stuff (no gas, forge, or expansion), then the bot had better stay safe against a hard rush. If it sees a forge and cannons, it had better emphasize drones and hatcheries instead. Opponent modeling and plan recognition can be combined: Here are the plans the enemy has been seen to follow (described in some abstract way, such as the timings at which units appear). Based on scouting information, this past enemy behavior is the closest match, so let’s counter it. Since bots are predictable, simple opponent modeling is likely to give big leverage.

More about opponent modeling: If you know the opponent’s range of openings, then you can figure out how best to open yourself—what to do until you get scouting information and can adapt. Lukas Moravec never tries a fast rush, so you don’t need to stay safe against rushes. If the opponent never plays proxies (like most), then you don’t have to scout for proxies. If the opponent plays a mix of fast and slow openings, then you can try to estimate the best counter-mix with game theory. There are a ton of ways to gain advantage by knowing the opponent’s habits.

tscmoop-Steamhammer hell-for-leather game

This game Tscmoo protoss vs. Steamhammer went back and forth, with both sides repeatedly decimating the other’s workers. On the one hand it’s kind of entertaining, but on the other it shows how weak both bots still are. Steamhammer was much too hesitant with its mutalisks, and Tscmoo did not make the right units to keep control of the situation. They both made plenty of mistakes.

Tscmoo went for a forge expand build, much safer than the bare expansions it has been opening with recently. Steamhammer opened 12 hatchery and got away with it because tscmoo didn’t scout early (if protoss scouts it in time the scouting probe can delay the hatchery, and even if that fails protoss can pull ahead economically by starting the nexus before any cannons, since zerglings will be delayed). Steamhammer has a partial understanding of how to counter forge expand, and it made extra drones and went up to 4 bases. But zerg was also clumsy around the cannons and lost zerglings unnecessarily.

Tscmoo built up zealot numbers while teching. It got a templar archives and high templar, plus a stargate that it never used (but which zerg had to prepare against). Steamhammer started with hydraling on the ground since hydralisks are good against cannons, but seeing the zealots it switched to mutalisks. Zerg started its carapace upgrade shortly after protoss started attack +1, which was correct timing, and later in the game drew ahead in upgrades.

The mutalisks cleaned up probes in the protoss main, apparently putting zerg well ahead. Notice the red zealots in the middle on the minimap.

mutalisks clean up

But the zealots were too strong for the ground army and returned the favor. The mutalisks indecisively moved back and forth, taking occasional swipes at protoss stuff but reacting late to the zealots. Here zerg seems to be fighting back, but at the 3 o’clock expansion zealots are ravaging drones with little opposition.

zealots clean up

Zerg ingeniously transferred drones between bases during the fight and lost more than it should have. When the smoke cleared, zerg had 9 workers and protoss had 12. By the numbers, zerg was narrowly ahead in army, but protoss was merging archons and if the archons maneuvered well then Steamhammer would have to back off while both sides rebuilt. The game was still on.

archon fails to clean up

Well, the archons did not maneuver well. The first one tried to engage the mutalisks by itself, instead of retreating to the cannons to wait for the second archon. That would have been a difficult move for a bot to find. Protoss lost more probes and the templar archives came under fire.

At the same time, zealots returned and killed more drones. This time Steamhammer had the sense to defend its natural with a sunken, and the zealots could not land a killing blow. Steamhammer was able to restore a modest economy while Tscmoo kept losing probes, and archons, and high templar before they could merge, and finally buildings.

Tomorrow: Steamhammer wants opening learning 2.

Steamhammer wants opening learning 1: McRave

I still have some essential bugs to fix. Also I keep literally forgetting that I promised a public repository next, and having to remind myself; it’s not appealing work. But beyond all that, I’m thinking about the next step.

The next major feature will be a start on opponent modeling and opening learning. As I think about it more, I’m seeing how important a feature it is to add soon, so I don’t regret setting out down the path. I’m going to write a series of posts giving examples to show how key a feature opponent modeling is.

McRave

The current version of protoss McRave doesn’t play that strongly. Its new forge-expand strategy is not polished yet, and I think new weaknesses have been introduced. But even so, it beats Steamhammer. The live Steamhammer always plays low-econ pressure builds versus protoss, and (unlike most protoss bots, even Bereaver) McRave is a sturdy enough defender to hold off the pressure. While trying to pile on pressure, Steamhammer doesn’t make enough drones, and as the game wears on it can’t keep up.

It’s easy enough to change Steamhammer’s behavior. There is a standard opening which is slower than 12 hatch 11 pool and faster than 3 hatch before pool: It is 12 hatch 13 pool, squeezing in 2 extra drones before the spawning pool. Those 2 drones make a substantial difference in the economy, because the earlier you spawn a drone, the more it pays off. The trade is that zerglings come later and the opponent gets a window for early aggression. Anyway, this McRave version doesn’t go for early aggression, so I coded up a quick 12 hatch 13 pool into 3 hatch hydra build. Sure enough, my first draft won most test games against McRave.

I don’t want to make 12 hatch 13 pool a standard build versus protoss, because too many bots go for early attacks. Steamhammer’s low-econ openings are effective against most opponents. But I need economic openings to win against defensive opponents like McRave.

I could specify an enemy specific opening mix versus McRave and immediately turn a bunch of losses into wins, at least for a time. Steamhammer does that versus rushbots and a few others. Arrakhammer does it too; it has hand-made builds to beat Wuli and McRave, and one to give it a chance versus Iron. But it’s not satisfying. It’s not sustainable, because I have to keep updating the hand-made builds by hand as opponents appear and change. And it’s likely to fail in tournaments, because many opponents show up with surprise updates that are specifically intended to throw off opponents which tune against them.

The answer is so learn each opponent’s habits from experience.

more findings on the new SparCraft version

Most of my attention is going to bugs, but I’m still poking at the new SparCraft version too (I also ran a few tests). My latest conclusions:

1. I’m still worried whether it will be fast enough. It feels slow. I’ll have to try a test on the SSCAIT server to find out.

2. It’s lying when it claims to support scourge. The provided UnitTypeSupported() call returns true, but with scourge in the sim it throws and you don’t get a result. I modified UnitTypeSupported() to exclude scourge, so that at least it’s honest about what it can do.

3. It also doesn’t support spore colonies correctly. I’ve seen it be startlingly accurate in predicting a small-scale fight of marines versus a sunken and a few zerglings (attacking with barely enough marines and scraping a win with 2 bleeding survivors), but in a fight of mutalisks versus spores it says “sure, 1 mutalisk can win, no problem.” This is the map to Suicide City; enter here and do not exit.

I decided to compensate with a crude adjustment. Don’t add enemy spore colonies to the combat sim. And for every enemy spore not added, drop 6 of our mutalisks (pro rated to the hitpoints of the spore colony). That’s about the number you need to beat a spore safely. In initial tests the adjustment seems not too silly. In reality 6 is too large a number, especially if there are separated spores, but I’m tired of the one-way trips to Suicide City.

Out of the huge range of unit combinations in the combat sim, I have hardly tested any. I expect to find more that SparCraft gets wrong.

Arrakhammer’s infested terrans

Arrakhammer’s description changed recently to say that it supports infested terrans. As far as I know, it is the first bot to make them. Now it has played a game with infested terrans versus Randomhammer.

The game is on Destination, a 2-player map. Arrakhammer opened with hatchery on 9, and instead of playing the opening the natural way with mass zerglings, only made a handful, aiming to tech up fast. Randomhammer opened with 2 barracks and before long had enough forces to push to the zerg natural. Zerg was forced to make sunkens, but terran did not dare to break in, and lost medics due to a bug in retreating them.

Zerg went for lurkers against the infantry, but the expensive sunkens set Arrakhammer’s tech plans far back and the lurkers were slow. Terran accumulated marines to hold a strong contain while expanding. Randomhammer had an objectively winning game; with good play, zerg should never catch up (see the worker and army counts in the picture). But Randomhammer is not a good player.

terran contains zerg

Straight infantry with only scanners for detection is not a winning combination against lurkers, especially not if you try to attack across a narrow bridge and repeatedly lose medics to the retreat bug. As long as scanner energy held out, Randomhammer held its own. But the scanners ran down and Arrakhammer hesitantly pushed out into the open map.

In this picture the lurkers have defeated most of the infantry after scanner energy ran out during a big fight. The queen has just now infested a command center, and from the flashing ramp and the production tab you can see that an infested terran has already started. Before the base was taken, terran had 5 bases to 4. Zerg had more or less caught up, and both sides had chances.

infesting the command center

The first infested terran was shot down barely before it reached its intended victim. Steamhammer knows that an infested terran is a high-priority target, even though this is the first time it has seen one. In the overall situation, marines continued to fight lurkers without enough scan energy, and zerg was pulling ahead.

zerg loses an infested terran

In the next picture, terran has lost another base, but the marines gave a good account of themselves, clearing the attack and killing the infested command center before it could produce. Losing the base was down to poor tactical skill. The marine army was larger and had 1-1 upgrades versus 0-0 for zerg, and repeatedly fought well until collapsing when scanner energy ran out. The queen, by the way, broodlinged an SCV before the zerg attack.

infesting another command center

Infested terrans are difficult units to use well. They’re similar to scourge: Suicide units that do a ton of damage, but are fragile and costly in gas. If you walk them into an enemy army, the army should normally kill them without much risk, as above—it only took 4 marines. If they walk in the open, they should attack SCVs or defenseless buildings. A few infesteds can clear out a dense mineral line, or demolish a substantial block of supply depots; they’re efficient for that. You can drop them on tanks, or on dense concentrations of units that can’t shoot up. Otherwise you need dark swarm to attack an army with infested terrans. You go to a lot of trouble to get them, and they’re a specialty unit which is complex to use.

Of course bots don’t know how to react, so walking into an army may work in practice. Steamhammer, for example, doesn’t react at all when retreating, so if you attack while the army is running away, you can do massive damage. 2 infested terrans did this, with excellent cost-efficiency, by catching the army in retreat:

massacre by infested terrans

Notice that even after the carnage, terran is ahead in army, though it has fallen behind in economy. Zerg is winning but has some fighting ahead.

The upcoming version of Randomhammer, by the way, has TvZ improvements so that Steamhammer can be a tough test opponent for itself. The upcoming version would have put up a fiercer fight, without the medic retreat bug and with a vessel and tanks against the lurkers.