archive by month
Skip to content

the fast success of Steamhammer

SSCAIT 2016 is beyond the halfway point, and Steamhammer’s score ratio has been holding steady near 2:1, good enough to place it in the bottom half of the top 16. It will probably make it into the finals (no guarantee; some tough games are still ahead). Its rate of upsets suggests a 30% chance that it could win in the round of 16 and make it through to the round of 8. It is unlikely to get further than that.

I’ve seen a few people wonder how a brand-new bot could do so well. Steamhammer 0.2 has less than 3 weeks of my development effort in it. I can answer that!

1. Steamhammer builds on a strong foundation in UAlbertaBot. I changed the openings and the strategy followup, and fixed bad play where I had time to, but most of Steamhammer’s play comes straight from UAlbertaBot. Tactics are only slightly changed; micro has modestly improved targeting but is otherwise nearly identical.

2. I know the game and I’ve been following the bot scene for a long time. I was able to make choices that both fit within UAlbertaBot’s limitations and pose challenges to other bots. Knowledge is power. Most new bots play inefficient builds; Steamhammer builds inefficiently only to work around other problems.

3. Strong new bots usually show good results at first and then decline as other bots adapt. I’ve seen it before and I see it now with Steamhammer. The opening learning bots find the right openings to play; I played a test match versus Zia in which Steamhammer scored 1 1 1 1 1 0 0 0 0, switching from wins to losses when Zia hit on the right opening. The actively developed bots get fixes to any weaknesses that the new bot reveals; both Krasi0 and LetaBot have mentioned improvements to mutalisk defense.

Steamhammer plans

My goals and plans for Steamhammer development. What, I told you it was next, didn’t you believe me?

Start with the usual 3 levels of abstraction: Strategy, tactics, unit control. My eventual goal is to conquer the levels one after another with machine learning, starting at the top with strategy—it’s more fun that way. I think I have to tackle each level separately, because any learning method that can learn all levels at once will devour more data than I can feed it—it will be beyond my resources.

My vague plan for each level is to start with a hand-made approximation of good play and learn the differences between the approximation and actual good play. That’s also because it’s more fun that way. First, play will never be too awful, so it won’t be discouraging. Second, learning will be faster because there’s less to learn, which is important because I expect to have to relearn each model repeatedly. For example, every time the tactics change too much, the strategy model should relearn what strategy is good with this set of tactical skills.

One goal is to learn opponent models, at least at the strategy level. I’d love to learn models at each level. We’ll see if I get that far.

Another goal for the strategy level is to be capable of every opening. If an absurd build like 8 gas 14 pool is good against some weird opponent, I want Steamhammer to be able to figure that out, at least in principle. I want to be able to say: If Steamhammer played enough games, it could eventually figure it out, no matter how unusual. Humans can develop new builds, bots should do it too.

For the moment I’m working on infrastructure. I renamed UAlbertaBot’s MetaType data structure which represents “a thing to build/research/etc.” to MacroAct, since I like names I can understand. I added “command” actions to MacroAct, and so far have implemented commands for scouting and taking drones off gas (both of which affect macro—they are macro actions). You can now write these into build orders in the config file, which makes the build orders more powerful; the bot’s behavior is no longer hardcoded. (Dave Churchill was apparently planning something similar, since the original MetaType already had an unused “command” variant.) I’ll use the same system for communication from the strategy boss to the production manager.

After a few more commands, I’ll add positioning information to MacroAct, so that it can distinguish between an expansion hatchery and a macro hatchery, specify which base gets the static defense building, and stuff like that.

That covers the most vital missing skills. Then I’ll start on the strategy boss. Goals are versatility, good macro, fast adaptation, and the ability to recover from upsets, all of which Steamhammer 0.2 is weak at.

A first working version should be ready to release some time in January. Depending on how fast I can make progress, I would like to add one more feature before the release, random choice of openings. Learning bots quickly learn to exploit Steamhammer 0.2’s fixed openings, and that’s no good. I’ll start with fixed probabilities for each opening, specified in the config file. Since the strategy boss can adapt to the game situation, the opening build orders will be shorter than now. A random mix of aggressive openings and macro openings with different tech choices should be difficult for the learners to exploit, as long as Steamhammer can play all the openings well enough. It should also be more fun for humans to play against.

Then it will finally be machine learning time. I’ll decide whether to learn openings or strategic play (after the opening) as the next step. The first target of opening learning will not be “learn the best opening,” it will be “learn the best mix of openings.” The second will be to develop new openings, of course.

Along the way I’ll be fixing bugs, improving micro decisions, and whatever else seems essential. But since I plan to completely replace the tactics and micro code, I’d like to minimize the work I put in and only do the essential.

Steamhammer versus Killerbot and XIMP

I got my SSCAIT wish and saw the first Steamhammer versus Killerbot and Steamhammer versus XIMP games today.

Steamhammer versus Killerbot by Marian Devecka: Would my counter-build work? In my tests Steamhammer wins with it about half the time. Killerbot went with its +1 speed lings and Steamhammer opened 11 pool and held with its own slow lings while teching to lair. Timing is critical—12 pool is too slow on some maps! In this game Steamhammer managed to sneak in a drone kill while Killerbot’s lings were busy chasing the scouting drone (UAlbertaBot doesn’t do that natively, I had to improve the decision making). Steamhammer added 2 sunkens for protection while getting mutalisks—it still had only 1 hatchery, while Killerbot was headed for 3 hatcheries, and it is impossible to hold without static defense. Steamhammer’s first 3 mutalisks hatched and headed for the enemy base, and as soon as the flyers were safely out of range to intervene, Killerbot’s zerglings attacked! Steamhammer pulled drones to defend and lost every single drone, but the sunkens held and the base was left barren but secure for the moment. The 3 mutalisks killed all of Killerbot’s drones in return and then tore down the enemy zerg base with excruciating slowness—Steamhammer won a close game. Steamhammer-Killerbot games often go down to the wire like this in my testing; I’ve seen one side or the other win with only 1 or 2 buildings left bleeding onto the map. But without the special-purpose counter-build, Steamhammer loses every game; Killerbot is far superior in tactics and robustness.

Steamhammer versus XIMP by Tomas Vajda: Steamhammer opened with 3 hatcheries before pool, the only bot I’ve seen play this logical response to forge-expand. (Though I saw auxanic open unsoundly with 5 hatcheries before pool!) XIMP cannoned up for carriers, as always. I hadn’t tested this matchup, so I wasn’t sure what would happen. Steamhammer went hydras with +1 attack, and soon had enough to tear down the cannon wall (slightly before +1 finished, annoyingly), wipe out XIMP’s natural, and start on the main. That’s what I intended, and I’m pleased it worked. XIMP seemed about to fall, but suddenly the first carriers started to make a difference—they finally had enough interceptors. The hydras did not have critical mass to fight carriers and were cleared from the main. At this point, Steamhammer had 6 bases though not enough drones to saturate them, and XIMP was mining minerals with 6 probes and gas with 3. Steamhammer was still winning by a mile.

As the game went on, the carriers moved to the middle of the map and Steamhammer trickled hydras toward them, losing them a few at a time for no apparent gain. There were 2 obvious problems. First, Steamhammer only attacked interceptors; as I watched, I realized “carriers don’t attack, so they’re at the bottom in the target priority list.” The code is easy to rewrite, though I’m not sure what solution is best. And second, trickling the hydras in was suicidal. I concluded while watching that SparCraft must not know about carriers. It ignores units that it does not know about, so when asked to predict the combat outcome, SparCraft always reported “zerg wins,” and Steamhammer moved its hydras confidently to their deaths. That may be harder to fix.

Steamhammer then won when XIMP overstepped a time limit, taking too long on a frame. That was disappointing. :-( I’m not sure how the game would have turned out. Steamhammer was still ahead but was playing like an idiot, and XIMP did finally re-expand to its natural and may have been able to add carriers before Steamhammer could take the rest of the map and start to make progress.

After these two uncertain wins, Steamhammer played against protoss Ian Nicholas DaCosta, a weaker bot which it had beaten in their previous game. Steamhammer got unlucky with base positions and scouting, placed its 3rd hatchery directly on the path that zealots were taking toward its main, and lost. Luck runs both ways!

Iron’s surprise losses

Among SSCAIT tournament watchers, the talk of the moment is of Iron’s two surprise defeats against zergs Steamhammer by me and GarmBot by Aurelien Lermant. Iron got unlucky 2 games in a row.

In the Steamhammer game, Iron became overcautious against the few early zerglings, bunkered its ramp, and was late with its vulture attack. Provoking reactions like that is one of the reasons Steamhammer makes zerglings. When the mutalisks came out, they soon had enough numbers to safely break the bunker and then were free to ravage Iron’s base (they could have gone ravaging from the start, but they were obsessed with the bunker). Iron’s vultures moved in and quickly wiped out every drone, but the mutalisk swarm split up, some cleaning vultures and the rest cleaning the terran base. Steamhammer won with empty bases but unchallenged air supremacy. In my testing, Steamhammer has never won against Iron with this build order—Iron got unlucky, or perhaps a late change weakened its play in this situation.

In the GarmBot game, GarmBot randomly expanded to Iron’s natural and built a sunken that covered the ramp. Iron was again overcautious: It double bunkered its ramp and blocked with vultures and many SCVs, and sent no vultures past the sunken. It seemed in no hurry to get tanks and blow away the sunken. Mutalisks showed up and started picking at a supply depot; nothing stopped them. But the lethal blow did not come until lurkers arrived and burrowed in good position on the ramp. There was no detection. Lurkers defeated the blocking units and cleared the bunkers while mutalisks killed the engineering bay, and then there was no hope. Iron reacted poorly to GarmBot’s bizarre expansion and GarmBot followed up well.

It’s a hard game! Even a bot as well-rounded as Iron is not prepared for everything.

Steamhammer’s surprises

Krasi0 and LetaBot congratulated me in comments on Steamhammer’s strong 4-1 start in the SSCAIT tournament. It’s too early—5 games are not enough to say, of course. For myself, I have mixed feelings because Steamhammer sprung one of its surprises, and it backfired resulting in the 1 loss!

I gave Steamhammer 5 counter-builds for 7 specific opponents.

  • Killerbot by Marian Devecka - 11 pool into spire
  • Iron by Igor Dimitrijevic - 2 hatch hydra
  • ZZZKBot by Chris Coxe - 9 pool into expo and finally spire
  • PeregrineBot - the same anti-rush 9 pool build
  • XIMP by Tomas Vajda - 3 hatch before pool into hydras
  • ZerGreenBot - the same 3 hatch build
  • Jakub Trancik the cannonbot - a 9 pool zergling build

The counter-builds for Killerbot and Iron score about 50% in my local tests. The build vs Iron scored nearly 100% against a November version of Iron, but Iron improves fast! Killerbot and Iron are far more sophisticated than Steamhammer, and only countering their strategies can make up the difference.

I’m eager to see how the 3 hatch before pool build does, especially since Steamhammer still has a terribly weak macro game. The opening is sound against the forge expand of those 2 protoss bots, but I know some of the mistakes Steamhammer will make. And the anti-cannon build for Jakub Trancik is a shot in the dark that I haven’t really tested. Steamhammer ought to tech to guardians once nearby cannons are eliminated, but time was short.

The anti-rush 9 pool build is slow and cautious and it’s effective against the version of ZZZKBot that I tested. (I haven’t tried PeregrineBot; I just hope it’s close enough.) So when I tuned in to Steamhammer vs. Chris Coxe on the stream and saw mutalisks beating up a barren zerg base, at first I thought “Good, it worked.” But no, Steamhammer was losing! ZZZKBot had switched to an entirely different ZvZ build! ZZZKBot built 5 sunkens to hold off lings and then went mutalisks, which counters builds that counter ZZZKBot’s former 4 pool. Steamhammer’s usual ZvZ 12 pool would crush, but instead my evil plot was thwarted. I expect that Killerbot will also find itself countered, and Zia may or may not be able to adapt.

It’s a double-edged lesson in the risk of fixed builds. By the way, Steamhammer’s 12 pool also counters most of Zia’s strategies, but Zia does have 1 strategy that beats it and soon learns. I expect to lose against Zia this tournament.

With enough time, I could find counter-builds for other troublesome opponents. But the best, like Krasi0 and Bereaver, play more strategically soundly and good openings would not make up much of the skill difference. Or at least that’s what I figured. I thought the effort would go to waste.

Next time! Late last night I fixed the double overlord bug, which sometimes caused Steamhammer to spawn 2 overlords when it needed 1. That messed up its opening timings, which led me to write overcautious opening builds in some cases. Expect more accurate openings in January.

Steamhammer 0.2

Steamhammer 0.2 is up on SSCAIT. Unless I discover a last-minute bug, and it’s a simple bug that I can fix without risk, this is the tournament version. It includes improvements at all levels, strategy, tactics, and micro. Most are inconspicuous, but some should be easy to see. The glaring weaknesses that I didn’t have time to fix are also easy to see!

I have built in some surprises. My hope is that after the tournament, a few bot authors will be thinking “Uh oh, I really need to do something about that.”

Steamhammer’s web page with downloads and discussion should be up some time tomorrow.

Still next: Future development will take a sharp left turn. I’ll outline my plans.

Steamhammer 0.1 download

Want to run Steamhammer 0.1 yourself? Here is Steamhammer’s zip file as I uploaded it to SSCAIT. The contents are:

  • Steamhammer.dll
  • Steamhammer_Config.json
  • BWAPI.dll

Steamhammer needs the config file and expects it at the path bwapi-data/AI/Steamhammer_Config.json. The BWAPI version is 4.1.2.

The config file system was inherited from UAlbertaBot (I made minor changes). The config file is easy to read and modify, and fun to play around with. Besides the active build orders and other config settings, it includes a few leftover build orders from UAlbertaBot plus build order experiments that I tried or meant to get around to trying. Items at the top of the “Strategy” section declare which build orders are active. In my view, the current ZvZ and ZvT build orders are adequate, the ZvP build order is poor but an interesting try, and the ZvRandom build order is awful.

Expect Steamhammer 0.2 in time for the SSCAIT tournament. It will have some surprises.

Around this weekend, Steamhammer will get its own web page where I’ll post new versions in source and binary as they come out.

Steamhammer (Z)

ZerGreenBot was re-uploaded today. I hope it’s much improved! And I uploaded my bot for the first time today, not because it plays an interesting game (because it doesn’t) but to start getting my hand in and see what’s up.

My bot is named Steamhammer, a reference to the legend of John Henry. Steamhammer plays zerg.

Steamhammer’s play is crude, at the level of figuring-out-how-this-stuff-works. I hope to squeeze in one more update before the SSCAIT deadline and put the fear of zerg into at least a few opponents. Steamhammer won’t begin to resemble my intentions for it until some time next year. While SSCAIT is running I should be able to get the first fun ideas in place.

UAlbertaBot

I chose UAlbertaBot as my base, because UAlbertaBot seems neatly organized, comes with some documentation though never enough, and is designed to be flexible and extensible. It’s basically designed to be a research platform for trying new ideas, and that’s what I want. It can play any race, though it seems best tested for protoss. I find its code more readable than other bots I’ve looked at; only Skynet comes close, and Skynet is specialized for protoss and has a more rigid design.

UAlbertaBot has more bugs than I expected. Well, it was developed by one person and never widely tested, so maybe I should have expected them! A number have me baffled. The most devastating bugs have to do with build order. UAlbertaBot usually automatically schedules overlords when needed, but sometimes makes 2 instead of 1 (often a serious mistake) or doesn’t realize it has hit a supply block, makes no overlord, and freezes the build in its tracks (rare but usually fatal). The build order search BOSS usually behaves sensibly, but sometimes schedules extra buildings which are not implied by the build order goal, such as an extractor or a lair or a hydralisk den. These bugs can be seen occasionally in SSCAIT games. One you won’t see on SSCAIT is that if UAlbertaBot has a lurker on the field, then BOSS falls into a fit of terror and is unable to solve any goal, no matter how simple [the bug is real, but I misidentified the cause; see comments].

UAlbertaBot also has limitations. It can theoretically make any unit (I haven’t tried them all yet, and I had to fix a bug before I could make sunkens or spores), but it can’t use all of them. When I tried making lurkers I found that UAlbertaBot was unable to micro them; they sat around. Well, it’s designed to be easy to extend, and it only took me 20 minutes to code up a simple lurker controller. Not that it helped, with the lurker bug in BOSS! I also suspect that SparCraft does not know how to burrow lurkers, because a squad with lurkers runs away more often than it should.

UAlbertaBot behaviors high on my to-do list to fix: Improve base defense, improve scouting, add building placement code for static defenses and macro hatcheries.

UAlbertaBot as a test opponent

I find that UAlbertaBot makes an excellent test opponent for trying out opening build orders, because it is easy to configure it to play whatever opening you like. Edit the configuration file, add a build order as a list of units and buildings to build and tech to research, and set UAlbertaBot to follow it. No need to recompile.

UAlbertaBot may play the opening poorly, but it will follow the build order efficiently and you can catch the timings.

status

Steamhammer has different builds versus terran, protoss, zerg, or random. All the matchups are poor. ZvRandom is particularly awful—I couldn’t find a sensible build within the existing limitations. One step at a time!

In the next week or so I’ll make a dedicated web page for Steamhammer and put its code up.

Next: Outline development plan.