archive by month
Skip to content

Steamhammer sucks with devourers

Devourers are not an everyday unit. They are specialist anti-air support units for when the enemy goes mass air. Devourers shoot slowly and do little damage for their cost, but their acid spores splash on enemy air units and make mutalisk or hydralisk fire much more effective.

Only today did Steamhammer play its first devourer game, the first game in which it both made devourers and had opportunity to put them to good use. XIMP by Tomas Vajda certainly goes mass air, and with devourers Steamhammer could have made short work of the carriers and corsairs.

devourers fly past like idiots

But it didn’t. Steamhammer’s devourer play turned out to be terribly weak. They sometimes hung back ignoring the enemy and sometimes pushed forward on their own and took fire without reacting. In the picture, the 4 devourers are flying at an angle past the corsairs, ignoring them instead of loading them up with purple goop. Shortly after, they flew around and past the carriers, taking fire and still not engaging.

Devourers are not easy to use well, but I was surprised at how poorly they turned out. I didn’t put any special effort into guardian play, and Steamhammer uses guardians effectively as support units, with fewer micro and coordination issues than I expected. Mixing guardians into the late game army poses problems for the enemy, and the devourers did not.

At some point (if nobody beats me to it) I will teach FAP about the effects of acid spores, and then the real anti-air units in the army will know when to pour on the fire. But that’s not the underlying problem in this game. Devourers moved around foolishly and did not shoot as often as they should have.

turtle strategies

One of the themes of today’s SSCAIT broadcast by Nepeta is that too much static defense is bad for you. He repeatedly showed in ZvZ that the side which made too many sunkens tended to fall behind. Static defense can’t go attack; it costs resources and it offers initiative to the opponent. In a well-played game, static defense has to pay for itself with a countervailing advantage: You have to use the temporary safety it brings to get ahead in economy, as in a protoss forge-expand opening or as Killerbot by Marian Devecka tries to do, or to get ahead in tech, as when in ZvZ you make a sunken to tide yourself over until your spire finishes.

But there is a reason that so many bots play turtle strategies. Turtling is strong against bots which do not adapt, which is most of them. For Steamhammer, I added 1 base and 2 base turtle openings which crush Wuli, an opponent that Steamhammer otherwise struggles against. Wuli does not adapt.

Steamhammer does adapt to static defense and pulls ahead of opponents that turtle too much. When the opponent makes static defense, you have 3 broad strategic choices. They are the same 3 choices you always have, but the opponent has offered you initiative so any of them might give you an advantage. 1. You can pull ahead in army and bust the defenses. Example: Hydralisk bust versus protoss forge expand. It can win outright, but it is risky. 2. Use the opponent’s passivity to pull ahead in tech. If you made a sunken, other things being equal I can safely skip a few lings and get a faster spire. 3. Or similarly, pull ahead in economy. If you made sunkens, I can make drones.

Steamhammer primarily adapts by making drones. A protoss or terran bot might expand sooner instead, so it can build workers faster. But whatever the choice, you want to adapt so that you don’t end up crushed like Wuli.

The game Steamhammer vs KillAll (correcting the unfortunate typo in the bot’s name) is an example. KillAll opened 9 pool with extractor trick to get 10 drones, and Steamhammer unluckily chose 5 pool. It is a build order win for KillAll—if both sides play well, the 9 pool wins with little risk.

But instead of making a second hatchery to win with mass lings, or getting quick gas to win with mutalisks, KillAll turtled. It threw away its advantage.

5 sunkens

You may want 1 sunken, because the 5 pooler starts making lings sooner and can be a little ahead. 5 sunkens are 4 too many and put KillAll behind despite its stronger opening. They are not well placed; they don’t protect either the approaches or the mineral line.

If I had been playing, I would have made a moderate number of drones, teched fast, expanded once for a second gas to guarantee that I would stay ahead, and aimed to win with mutalisks. Steamhammer made many drones and teched slowly (fast enough not to fall behind), spending the extra income on zerglings. It went up to 5 hatcheries to produce a biblical flood of zerglings. The picture shows 3 of the 5 hatcheries; the other 2 are in the natural. Steamhammer is slightly ahead in economy and tech and way ahead in army and production capacity. Steamhammer can only lose if it blunders.

5 hatcheries

The zerglings were so many that they cracked the turtle shell and overran KillAll. GG. KillAll lost drones right off because the sunkens were misplaced, but it took only a fraction of the zerglings to finish off the sunkens. Steamhammer had a completed spire but did not need any mutalisks (see how many purple zerglings are already en route).

the end of the game

Steamhammer’s reaction to static defense is effective. You can beat it with a turtle strategy, but only by exploiting weaknesses. The reaction to static defense is not a weakness.

Steamhammer can’t rebuild its last hatchery

While reviewing WorkerManager to find a different bug, I happened to notice a subtle mistake in WorkerManager::getBuilder(), the routine that chooses a worker to construct a building. If there is a worker whose job is to move into position, it prefers that worker. But if there is not, it picks a mineral worker:

		if (unit->isCompleted() && (workerData.getWorkerJob(unit) == WorkerData::Minerals))

It looks correct. If you have workers then should always have mineral workers, unless they are all pulled for other jobs, and then you probably prefer to wait to start the building. But it’s not correct. There is an important case where there are no mineral workers: You may have no bases mining minerals because they were destroyed or mined out, so all the former mineral workers are marked Idle.

		if (unit->isCompleted() &&
			(workerData.getWorkerJob(unit) == WorkerData::Minerals || workerData.getWorkerJob(unit) == WorkerData::Idle))

Without this fix, when Steamhammer loses its only hatchery, it is unable to rebuild. I ran into that bug in January and always wondered about the cause. Theoretically the bug could also strike in the late game, after all surviving hatcheries have mined out their minerals. I’ve never seen it happen, but then there would be no mineral workers and Steamhammer would be unable to construct a building.

It’s not a critical bug. Losing your last hatchery usually means you lose the game. But if the opponent is also in dire straits, you still have a chance. It happens most often in zerg versus zerg.

Now I need to go find any other places where code looks for a mineral worker and make sure it can find an idle worker too. WorkerManager::isFree() was already correct, but there might be more....

Update: The other routines which get a mineral worker and skip over idle workers are WorkerManager::getClosestMineralWorker(), WorkerManager::getGasWorker(), and WorkerManager::getMoveWorker(). Routines outside WorkerManager which do similar jobs all call isFree() as they should. I rewrote these three to call isFree() too.

fix for the drone dance bug

Here’s how I rewrote WorkerManager::handleGasWorkers() to solve the drone dance bug whose cause Arrak located. It’s a deadly bug and not fixed in any released Steamhammer version, so if you’re running a fork you probably want this.

First, a pseudocode version to show the structure. The “resource depot” is the command center, nexus, or hatchery. If the resource depot is lost, we need to stop mining from the refinery because the enemy army is likely still around and will kill all our workers 3 at a time as we send them over. (Code elsewhere handles the case where the refinery is destroyed.)

if collecting gas
  for each refinery
    if its resource depot still exists
      add workers to the refinery
    else
      remove workers from the refinery
else
  remove workers from all refineries

Then the actual code. The pseudocode is good, but bugs may lurk in the details. It is new code and poorly tested, especially removing workers from a refinery whose depot is lost. Let me know if you find any remaining bugs.

// Move gas workers on or off gas as necessary.
// NOTE A worker inside a refinery does not accept orders.
void WorkerManager::handleGasWorkers() 
{
	if (_collectGas)
	{
		// Gather gas where possible. Check each refinery.
		for (const auto refinery : BWAPI::Broodwar->self()->getUnits())
		{
			if (refinery->getType().isRefinery() && refinery->isCompleted())
			{
				if (refineryHasDepot(refinery))
				{
					// This is a good refinery. Gather from it.
					// If too few workers are assigned, add more.
					int numAssigned = workerData.getNumAssignedWorkers(refinery);
					for (int i = 0; i < (Config::Macro::WorkersPerRefinery - numAssigned); ++i)
					{
						BWAPI::Unit gasWorker = getGasWorker(refinery);
						if (gasWorker)
						{
							workerData.setWorkerJob(gasWorker, WorkerData::Gas, refinery);
						}
						else
						{
							return;    // won't find any more, either for this refinery or others
						}
					}
				}
				else
				{
					// The refinery has no depot to return gas to. Remove any gas workers.
					std::set gasWorkers;
					workerData.getGasWorkers(gasWorkers);
					for (const auto gasWorker : gasWorkers)
					{
						if (refinery == workerData.getWorkerResource(gasWorker) &&
							gasWorker->getOrder() != BWAPI::Orders::HarvestGas)  // not inside the refinery
						{
							workerData.setWorkerJob(gasWorker, WorkerData::Idle, nullptr);
						}
					}
				}
			}
		}
	}
	else
	{
		// Don't gather gas: If workers are assigned to gas anywhere, take them off.
		std::set gasWorkers;
		workerData.getGasWorkers(gasWorkers);
		for (const auto gasWorker : gasWorkers)
		{
			if (gasWorker->getOrder() != BWAPI::Orders::HarvestGas)    // not inside the refinery
			{
				workerData.setWorkerJob(gasWorker, WorkerData::Idle, nullptr);
				// An idle worker carrying gas will become a ReturnCargo worker,
				// so gas will not be lost needlessly.
			}
		}
	}
}

the importance of bugs

Here’s a little story for anyone who doubts the importance of fixing bugs: Randomhammer’s last 4 games were all decided by bugs.

4. Versus IceBot, Randomhammer rolled terran and went vultures. The vulture attack almost broke through IceBot’s wall, but IceBot got its bunker up and managed to keep 1 marine alive long enough to get in. Randomhammer’s hard-coded switch to tanks was late and its tactics were weak, and IceBot was soon winning. The hostile tank push started, then—IceBot crashed, game to Randomhammer.

3. Oleg Ostroumov crashed at 5 SCVs, before the game was properly underway.

2. Hardcoded crashed on start.

1. Versus zerg ZurZurZur there was at least a game. Randomhammer again rolled terran and this time went for a vulture drop. ZurZurZur sent 4 hydralisks across for a poke, where they met Randomhammer’s small force of marines and vultures, whose purpose is to keep the enemy occupied out front while the drop happens in back. It worked; ZurZurZur’s forces were far out of position, and the vultures killed all but 1 drone before being cleaned up. Then Randomhammer fell into a production freeze and did not produce another unit for the rest of the game, allowing ZurZurZur to slowly recover with its 1 drone and win.

There is a sub-theme here: Crash bugs are the worst. You crash, you lose. Randomhammer could have defeated ZurZurZur on points if it had better vulture micro, even with the production freeze. (It couldn’t have won outright, though, because there were sunkens that existing forces could not have brought down.)

Steamhammer has no known crashing bugs. I went on campaign and exterminated them. Its last crashes due to fixable bugs were in April, and its last recorded crashes on SSCAIT were in May and appear to have been due to bugs in the infrastructure, not in Steamhammer. Some of the bugs I fixed are obscure and their triggers have never occurred in real games. For example, Steamhammer has never had a unit mind controlled, as far as I have seen. The normal unit validity check done on every frame should catch mind controlled squad units and workers before Steamhammer tries to send them orders—though it hasn’t been tested, so I don’t promise it’s correct. But I noticed a loophole: The scouting worker is not in a squad and is not treated like a regular worker. It is controlled directly by ScoutManager, which does not run the validity check. I left a comment in the code where I fixed it. How many years would it have been, do you suppose, before somebody mind controlled the scouting worker and brought about a crash?

opponent modeling, scouting, and software development

Opponent modeling is coming along, though never as fast as I would like. Steamhammer now records a pretty informative model. Making best use of the model is not as easy—it has a ton of uses. If it works as well as I hope, Steamhammer will gain scary predictive abilities, even against opponents with multiple strategies.

Opponent modeling depends on good scouting. The more Steamhammer finds out about what the opponent does, the better the model. So today I added a new scouting command, "go scout once around" which sends the worker scout on a single circuit of the enemy base and then returns it home. (Usually. There are some funny cases because the waypoint numbering is not quite clean.) In a lot of openings, I used it to replace "go scout location" which only finds the enemy base and doesn’t look to see what’s there. I’m thinking of also adding "go scout while safe".

The command is a minor addition, but while hooking up the wiring I saw awkwardness in the communication among ProductionManager which executes the commands, GameCommander which initiates scouting, and ScoutManager which does the work. I ended up spending the whole afternoon refactoring it for simplicity and testing to make sure I hadn’t broken anything.

Is that what I should be spending my time on? And yet it makes Steamhammer better.

production freezes

Production freezes are one of the most serious classes of bugs in UAlbertaBot. Its descendants like Steamhammer and Arrakhammer have mitigated the problem by solving various subclasses of production freeze item by item, but have never solved all of them.

There are two main kinds of production freeze, permanent production freezes caused by deadlocks and temporary production freezes caused by waiting for a slow prerequisite to finish.

There are many ways for production to deadlock. You want hydra speed, so you order it up. Then the hydra den is destroyed and the queue hangs. Steamhammer solves that for zerg by canceling items whose prerequisites are missing, which is itself complicated and bug-prone. I think most remaining permanent deadlocks are caused by bugs in the strategy boss, the information manager, the production manager, or the building manager, or in their interactions with each other. Steamhammer tries to mitigate these by timing out and clearing the queue if nothing has been produced for too long, but that is not enough to save the game against a strong opponent.

A temporary production freeze is caused by waiting unnecessarily for a prerequisite to finish. For example, an old version of Steamhammer once froze frequently when it wanted a hive next, because it didn’t realize that it was still researching overlord speed. It had to wait until research finished before it could morph the hive, and in the meantime it was making no units and probably losing the game. The live version solves most issues like that, but it does have an unsolved production freeze that occurs while waiting for the spire (it sounds easy to solve, but I’m not finding it). Another example is: Suppose you want vulture speed and spider mines, and you made 2 machine shops to do the work, but 1 shop has been destroyed. No prerequisites are missing, so there is no deadlock, but you’ll end up researching the upgrades one after another instead of simultaneously, in the meantime making no units. Or even: You want something that requires gas next, so you wait for the gas to accumulate and produce nothing else even though you could make mineral units while waiting. I may add queue reordering to mitigate this, but the underlying issue remains.

Production freezes happen in other bots too. Watch the production tab in OpenBW. I’ve seen tscmoo suffer badly from temporary production freezes.

Software engineering is the solution. So far I’ve been fixing issues one by one. The underlying problem is that the software architecture is fragile. The right kind of fix is to redesign the production system in a way that is not prone to freezes. I don’t know what the redesign will look like, but some of its features are already visible from a distance. For example, I expect it will take into account low-level details like “which building will do this research?” before ordering the research; currently, the details are left to ProductionManager after the order is made, leaving room for slippage.

Anyway, my plans are always changing. This month I am on opponent modeling. After that, I plan to work on the mutalisk control that I’ve always promised. A new macro manager and re-architected production would be a logical task after that, especially since it would improve play for all races. At the rate I’ve been going, I may or may not get to it this year.

Steamhammer and Randomhammer swap ranks

Since uploading version 1.3, I’ve been bemused to watch Steamhammer’s elo fall to near 2100, while Randomhammer’s rose to over 2150. I’m sure that they haven’t really switched places, since Randomhammer has been winning as zerg. The rating swap is some combination of luck and the effects of the voting system. The reversal has already partly reversed itself.

I have gotten a clearer view of new weaknesses, though. One weakness is caused by making emergencies too short, so that after a difficult defense Steamhammer makes drones and tech instead of replenishing its combat squads, and may lose to the next attack. (Someday I’ll solve that in a more principled way.)

I have to put the big effort into opponent modeling, though. I boasted big goals and I have to meet at least some of them.

Steamhammer opponent modeling goals

Next up for Steamhammer is opponent modeling. Some version of it will be ready for AIIDE, deadline 1 September. Opening learning methods that we have seen so far implicitly assume that the bot knows a small number of strategies and that one of them is the best counter for the opponent’s play. I want Steamhammer to be able to cope with opponents that are reactive (Iron), multi-strategy (Zia), or both (Krasi0). My goals for opponent modeling are something like this:

  • Play a wide range of strategies. It has been part of my plan from the first.
  • Learn from the events of the game, not only from the outcome. That way the bot can learn more and faster.
  • Learn from one trial: See an opponent’s strategy in the first game and counter it in the second, or at least make a good try. Fixed-strategy bots that Steamhammer knows a counter for should stand at a disadvantage from the second game on.
  • React by both choosing a counter opening and later choosing a counter unit mix in the middle game.
  • As more games are completed, recognize the range of the opponent’s play.
  • If no one opening strategy counters the full range of the opponent’s play, use game theory to estimate the best mix of openings.

It’s fancier than the strategy learning we’ve seen before, but it doesn’t seem hard to me. It’s straightforward, at least in principle. The key element is a model of game strategy. Already last night I wrote a GameRecord class that keeps a simplified description of what happens. That will be the basis for reading the opponent’s strategy over the game. As soon as we have one game record for an opponent, we can check our openings against it to predict which openings will succeed, and we can also use the record to make middle game decisions about what to produce.

Against opponents with a fixed play style, like XIMP, I expect this to be fast-acting poison. Steamhammer won’t react “Oh, carriers, I’d better make some scourge,” it will prepare ahead of time, “4 carriers will be coming in a minute or so, let me make the right amount of scourge to explode them all.” Against opponents that vary their play, it will take more games to formulate effective venom.

If I have time, I’ll do more. There is no chance that I can get all of these ideas implemented in time for AIIDE, but I’ll make what progress I can.

  • Generalize across opponents, so that an unknown opponent faces play that has proved strong before. If you play a lot of openings, then some of them are weak in most circumstances; so far I have accepted that.
  • Take more information into account, including map and starting positions.
  • Integrate scouting information with the opponent model to get the best possible prediction of what the opponent is aiming for this game.
  • Arrange the known opening lines into a tree, and use the integrated prediction to make decisions at every branch. Opening play will become reactive moment by moment, more like pro play.
  • Use the same mechanism to decide when to break out of the opening book.
  • Record the decisions made just after leaving the opening book as a new opening line to be added to the book and possibly played against other opponents. With breaking out plus adding opening lines, Steamhammer gains the ability to invent its own openings.

Steamhammer 1.3 release version

Steamhammer 1.3 is uploaded. This is the release version. I’ll try to put up the source code and documentation today, so that I can hurry on to opponent modeling.

I’m convinced that Steamhammer 1.3 is stronger overall than the last release, 1.2.3. Some new bugs and weaknesses were added, as always, but more than enough old ones were taken away. Most of the new weaknesses fall into two groups: One, new macro problems revealed by fixing the last round of macro problems. Two, mistuning and general klutziness in the strategy boss because it has more tech choices. Adding lurkers, guardians, and devourers meant that I had to replace the subsystem that chooses the unit mix and tech target, and there are rough edges.

The change list since the last test version:

• Drop SparCraft and use FAP for combat simulation. SparCraft was occasionally breaking the time limit per frame in long games, so it had to go. I can’t find any practical disadvantage to the change. FAP is faster, smaller, simpler, more comprehensive, and less buggy. The CombatSimulation class responsible for calling it became tiny. Its results seem a little more accurate even in simple cases like unupgraded zerglings versus unupgraded zealots, and of course they are much more accurate for units that SparCraft does not support, like bunkers. SparCraft has the advantage of a basic understanding of terrain, so theoretically it might do a better job in assaulting ramps. But both combat simulators ignore vision issues and allow simulated units to pass through each other, so terrain effects are not well simulated anyway—the biggest difficulties in assaulting up a ramp are that you can’t see the top, and that not many units fit on the ramp.

• Fix some potential production freezes related to subtle interactions between the strategy boss and the building manager.

• Fix a potential production freeze related to ordering an impossible extractor.

• A worker sent early to construct a building is no longer prematurely swept up as idle. In the final test version, this was sometimes causing buildings to start a little later than they should have. It’s a recurring bug, and luckily this iteration was not as severe as the last.

• Turrets are a higher targeting priority for melee units.

• In ZvZ, don’t ever make hydralisks, and only make lurkers after hive. Steamhammer was always intended to play this way, and now the rule is strictly enforced.

• In ZvZ, deliberately undercompensate for enemy static defenses and expansions.

• If we’re making hydras now and planning lurkers later, maybe get hydra upgrades if there’s time. Steamhammer prioritizes researching lurker aspect, and the priority was too strict.

• If all lair tech looks useless, go straight to hive. Earlier test versions brought up a lair tech, either mutas or lurkers, even if they judged that all lair tech was unhelpful. Sometimes it’s better to stay on hydra-ling until you can get hive tech.

• More adjustments to what-counters-what. In general, more ultralisks and fewer lurkers.

• Several new zerg openings added with low probability. There are now 3 different 1 hatch lurker builds, even though there is still no 2 hatch or 3 hatch lurker build (all things in due time).

Other changes since the last release, by test version number:

some bugs are very strange

Steamhammer has a particularly weird bug on the map Jade. Jade is a 4-player map with bases in the corners. Each base is on low ground, surrounded by a ring of high ground. A ramp leads up to the natural at one end of the ring of high ground, and at the other end of the ring is a third base.

the map Jade

If Steamhammer starts in the lower left base, then it is unable to take its third on the high ground. A drone on its way to start the third will travel most of the way there, then turn around and go home. BuildingManager then sends another drone, which behaves the same, and so on forever. Starting at a different location is OK. Taking the third of another start location is OK. Only that specific start location has trouble with taking that specific base.

The bug has affected Steamhammer since early days. I’ve never looked into the cause because it only comes up 1/4 of the time on 1/14 of the maps. It’s a game-losing bug, but low on the list. Presumably some detail of the map, or maybe some error in BWTA, is triggering a mistaken decision.

It’s such a surprising bug that I thought it deserved its own post. Maybe somebody has an idea about the cause? I could be mistaken, but I vaguely recall that I’ve seen other bots with the same error.

In the meantime, Steamhammer lost against Roman Danielis today by starting off strongly. Roman Danielis repeatedly tried to take its natural, and Steamhammer repeatedly stopped the nexus from warping in. The strategy boss mistakenly went into a panic, “Oh no, the enemy just took a ton of bases, I’d better make a ton of drones to catch up!” Steamhammer made all drones and no combat units and lost. Now that’s a bug I’ll dig into.

the trend to switching races

There’s a trend for established bots to come out with a version playing a different race, or playing random. Why is that?

racebotauthornew racenew name
terranNavinadSungguk ChazergZia
terranUPStartCraftAI(team)zergUPStarCraftAI 2016
zergSteamhammerJay ScottrandomRandomhammer
protossMcRaveChristian McCraveterranSparks
zergbftjoeJoseph Huangterranbftjoet
terranTyrSimon PrinsprotossTyrProtoss
WOPRterranSoeren KlettzergWOPR Z
protossPurpleWaveDan GantrandomPurpleCheese
protossPurpleWaveDan GantterranPurpleSpirit

Tscmoo was the first established bot to come out with a new race as a regular thing, as far as I can tell from records. Am I missing one? The next was Zia by Sungguk Cha. Both of these were before any visible trend started. I can imagine that Randomhammer may have started the trend; it was close enough in time.

The work I spend to make sure that Steamhammer can play every race—to make Randomhammer—definitely slows down the progress of Steamhammer’s zerg. Without the side work, Steamhammer by now would have fewer bugs and at least one major feature more from my to-do list, such as opening learning or decent mutalisk usage (possibly both). I wrote about the cost of playing random in going random. If you’re aiming for the strongest play, don’t switch races unless you think you can make the new race stronger. And even then, don’t underestimate the time and difficulty of bringing a new race up to speed. Few of the off-race bots have caught up with their parents.

So why the trend? Of course different authors may have different motivations, but there’s a coherent trend so likely there is one main underlying reason. I thought of a few, but I don’t know the answer. 1. People (suddenly) want more variety and less slogging down the same old path? (Probably not.) 2. Other bots are switching races, and it seems cool? (Call it “popularity inspiration.”) 3. The stronger community discussion this year means that more ideas circulate, and people want to try them? (“Idea inspiration.”) 4. Or the stronger community inspires people to contribute more to the community. ("Contribution inspiration.") 5. Authors believe they can do better by switching. (Maybe in some cases.) 6. There is more stuff going on in total this year, so more race switch bots come up too as part of that.

For TyrProtoss, Simon Prins can tell us his thoughts if he likes, but I have a guess: I suspect that the old codebase was getting clunky, and he wanted a fresh start. That explanation doesn’t fit most of the switchers, though. For Randomhammer, my goal as I see it now is more to lift community standards and reach the highest ultimate level of play than to reach strong play in the shortest time. I often leave important weaknesses unaddressed for a long time, because I want to fix them later as part of a major new feature; fixing them right away I see as a slowdown. A full-featured starter bot that can play all races reasonably well helps lift the community. A bot that is designed for customizability and releases its source will have a hard time staying on top for long!

Other ideas? What do you think? Maybe some of the authors will tell us.

PurpleCheese has become cheesier

The cheese news is not letting up. Today the protoss worker rush bot PurpleTickles was disabled. In its place, the former protoss 8-8 proxy gate rushbot PurpleCheese now plays random, and its strategies include the worker rush.

The change was just made and so far the new version of PurpleCheese has played 4 games. It ended up zerg 3 times and protoss 1 time, so we haven't seen its terran yet. As protoss it played the worker rush (versus LetaBot under the Martin Rooijackers name, which of course defended excellently). As zerg it played the worker rush once (versus Randomhammer) and 5 pool twice (both versus Oyvind Johannessen). So it knows at least 2 strategies.

Maybe for each race it can play the worker rush and one other rush strategy for that race? That is my guess. We'll see as more games come in—or if the author tells us!

Update: Now terran PurpleSpirit has joined the Purple family. Against McRave and PurpleWave, PurpleSpirit won with center BBS, so it also has cheese powers. Against Iron, PurpleSpirit played a fast expand strategy with tank-wraith-vulture followup, which put serious pressure on Iron before collapsing due to inadequate air defense.

Stone now attacks buildings

Igor Dimitrijevic has uploaded a new version of Stone, a version which attacks buildings instead of workers. I guess it’s because worker defense has been steadily improving, but many bots still don’t react when a building comes under attack.

Steamhammer doesn’t react to attacks on buildings. Even so, its usual anti-rush opening defended successfully in this game. Buildings have a lot of hit points, so the spawning pool finished before it was destroyed. In the picture, the spawning pool is about to die before any zerglings are spawned, but the sunken colony is already morphing.

Steamhammer loses the pool

The sunken protected the hatchery completely, so there was little risk. Steamhammer replaced the spawning pool in the same position, which was not safe because the sunken protection extended to only one side of the pool. Stone did not seem to understand the range of the sunken, and half the SCVs sent to attack the pool were killed while standing just inside the danger zone. Steamhammer actually won the game more easily than against the older Stone version, because Stone threw away so many SCVs. Stone did point out weaknesses. Steamhammer should defend buildings which are in danger of being lost, and it needs better building placement.

This game versus Skynet by Andrew Smith was fun. Skynet, ahead of its time as usual, does react when buildings are attacked, and pulled many probes to defend. Skynet was unworried by the skirmishes and calmly continued with its build: Late gateway, gas, cyber core... all before the first combat unit.

Skynet doesn’t care

My impression is that the change to Stone has left it weaker overall. Buildings are too hard to kill. Still, it does easily wipe out some opponents, and every change is a new challenge.

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.