archive by month
Skip to content

Steamhammer 1.3.3 is uploaded

Steamhammer 1.3.3 is uploaded. Fixing the disastrous “I seem to be making a command center, I’d better cancel it” bug was trickier than I expected. After I did fix it, I saw the game Steamhammer vs AyyyLmao, which was just as disastrous. I had to watch closely to see what happened: At about 1:15 into the game, Steamhammer moved a drone to start its spawning pool, and simultaneously sent out its scouting drone. The scouting drone momentarily blocked the spawning pool from starting, which happens from time to time and causes a slight delay. Not this time, though. The spawning pool was canceled on the spot due to another bug, and Steamhammer’s build order was disrupted. Steamhammer recovered poorly and lost the game against an opponent it should have beaten.

Anyway, I made several tweaks to the rules for giving up on buildings, and I tested more thoroughly with games against a variety of opponents. I think it’s mostly OK now. But the change is more fragile than I realized, and I won’t be surprised if more bugs are lying in wait.

Next: The full CIG 2017 results are posted, but they don’t come with the colorful crosstable (at least not yet). I’ll supply my usual red-and-blue crosstable.

Steamhammer 1.3.2 added a severe terran bug

Ack! I fixed one bug that happens when terran gives up on constructing a building, but I missed an even more serious terran bug in the same code. In Steamhammer 1.3.2, terran is unable to build a command center! The bot gives up on the building partway through and cancels it.

See Randomhammer vs ICEbot for an example. Randomhammer expanded late, and ICE had already placed a spider mine at its expansion spot, so Randomhammer gave up on its first attempt as intended. After its vessel came out, Randomhammer eventually cleared the mine and started the command center again—and again—and again, canceling it over and over. Mega ouch! I coded up a quick 14CC opening and verified that the bot can’t finish a command center at all.

The bug is so severe that it deserves a quick 1.3.3 release with a fix. Stand by, I’ll try to get it in today.

Steamhammer 1.3.2 is uploaded

Steamhammer 1.3.2 change list. It amounts to the donated openings, 3 fixes for terran and protoss because I only tested zerg in the AIIDE version, and 2 minuscule tweaks to zerg—and of course configuration to play on SSCAIT instead of in the AIIDE tournament. Otherwise it is the same as the AIIDE version.

  • New protoss openings from Antiga, donated by Iruian. Protoss play will be more varied and hopefully stronger.
  • Version 1.3 had a configuration mistake, when Randomhammer rolled protoss or terran, affecting opponents Dave Churchill (UAlbertaBot) and Andrey Kurdiumov (a UAlbertaBot fork with software engineering changes rather than play changes). It was configured to always play a zerg opening, so when the bot was not zerg, the opening group was not set. Randomhammer played normally... except that it never built a combat unit. Combat units are made depending on the opening group. I corrected the configuration. Also see the next item.
  • Added a workaround in case the opening group is not set to a correct value and it needs to be: Set a default opening group when the error is noticed. As it always has, it puts a message on the screen when the error is noticed, so you’ll know what’s wrong.
  • The new “cancel a building if it takes too long or if too many workers are lost” feature included a bug for terran. Partly constructed buildings could be left around instead of being canceled. Fixed.
  • I changed the formula for making lurkers as aux units, so that Steamhammer makes more aux lurkers. Aux units are extra units added to the regular unit mix. This should improve play when Steamhammer has lurker tech but isn’t using lurkers as a primary unit.
  • If there are mutalisks, then devourers go into the flying squad with the mutalisks. They were mistakenly always put in the ground squad. It should improve devourer play, at least sometimes and a little.

Tomorrow I’ll update Steamhammer’s web page with the source. Then I will return to the opponent model.

Steamhammer 1.3.2 and Antiga’s openings

The biggest new feature in Steamhammer 1.3.2 will be the new protoss openings from Antiga (thanks to Iruian). I sorted the openings into a different order and renamed a few to keep to a more consistent scheme. I’m leaving out the 9-10 gate opening for now; it is only slightly different from 9-9 gate and plays worse because of BOSS, and Antiga leaves it out too.

I’m not straying too far from Antiga’s weights, either. I question some of them, but they are tested and known good and provide variety. I’m making only relatively small adjustments. And that’s the story. It’s taking time to configure and test everything, but I’ll push out the new version before long.

If anybody else would like to donate openings, I’ll include them in the Steamhammer distribution as extras if they are remotely useful. If they’re good, I’ll configure them to play in the live Steamhammer. Since protoss has just been fed, the terran openings are now begging for their handouts.

Someday, when Steamhammer is smarter than now, I’ll build the opening tree and have Steamhammer choose opening lines on the fly. Possibly I’ll have both a concrete tree of macro actions and an abstract tree of strategic plans. At that point, the bot will be able to decide for itself under what circumstances an opening is good, and it will make sense to feed it as many variant openings as possible regardless of quality. I don’t mind accumulating data now for that future day.

the donated openings from Antiga

Here’s what I found out about Antiga’s donated openings. (Thanks again to Iruian, by the way.) This post is only about the openings themselves. Also donated are weights, how often to play each opening in each matchup, which I’ll consider separately. My plan is to distribute the donated file along with Steamhammer’s source, so that whoever wants to can easily borrow the openings and weights. The openings are good, so I’ll also put most of them directly into Steamhammer’s regular configuration; Randomhammer will play them when it rolls protoss.

Going by names, Antiga’s openings are a superset of Steamhammer’s. But 3 of the openings with the same names are different, so it’s a little confusing.

identical openings

  • 1ZealotCore
  • DTRush
  • DTDrop
  • CorsairDT (weak because Steamhammer sucks with corsairs)
  • 12Nexus
  • 13Nexus

openings new in Antiga

These are good openings, so at the moment I’m thinking I’ll throw them into Steamhammer’s config for active use. The weights are a separate question.

  • 9-10Gate
  • NoZealotCore
  • 10-15GateGoon
  • 2ZealotCore
  • 2GatewayGoonExpo
  • Nexusfirst5zealotExpo

openings that are shared but different

I tested the shared openings by playing them against each other head-to-head. I’ll call it Steamhammer versus Antiga, though both sides were running identical Steamhammer code. I didn’t pay attention to the results of the games, which varied depending on how battles happened to come out. I paid attention to macro: Who had more income, who produced units more efficiently, who was able to expand sooner.

9-9 gate The 2 openings proceeded in lockstep until Antiga went out of book. Then Steamhammer’s beautifully optimized UAlbertaBot zealot rush quickly pulled ahead. It evened out somewhat after Steamhammer also went out of book, but not entirely.

10-12 gate Steamhammer’s 10-12 gate opening is not as highly optimized. Again the openings were identical until Antiga went out of book. Steamhammer pulled ahead, but not dangerously. I don’t see any big difference in strength between the openings, only a small advantage to Steamhammer’s existing opening.

ForgeExpand The openings are the same, except that Antiga adds a third photon cannon at the end of the opening. It barely delays the early zealots and dragoons, so I judge it an improvement: Safer and practically as aggressive. I will switch Steamhammer’s opening to this version.

optimizing Steamhammer’s openings

Iruian donated some protoss openings with weights as used in the bot Antiga. I will distribute them with Steamhammer, but I’m still pondering exactly how. The openings are supposed to be straight from Liquipedia, and the ensemble is claimed 50 to 100 elo stronger than Steamhammer’s default protoss openings. I don’t have any reason to doubt it, but I’m still in the process of checking the openings myself.

Unfortunately, there are reasons not to take openings straight out of Liquipedia without testing. Most of Steamhammer’s provided openings are modified from Liquipedia versions, and sometimes the changes are major. (Some were taken from other sources, and a few were developed from scratch, starting with no more than the opening stem and a plan.)

Sometimes Liquipedia is unhelpful, if not outright wrong. I think the 12 pool lurker build on this page is a prime example. It says you should adhere to the build strictly. But if you build everything that the build order calls for, then lurkers are severely delayed, and the build order makes no sense (at least to me); use a 12 hatch build instead. If you minimize the build to get lurkers as fast as possible, then you end up with 4 or more larvas for a long stretch after the second hatchery finishes, meaning that there was no reason to get the second hatchery so soon; you should have stuck with a single hatchery build. Presumably a pro can weigh the situation and decide what extra stuff is good to make, but Steamhammer doesn’t have that skill. So I found the Liquipedia build order unhelpful.

Often Steamhammer plays poorly in the middle game, and the weak play can be worked around or delayed by extending the opening. This is the main reason to deviate from standard builds: Alter the opening so that Steamhammer plays it better.

BOSS is weak, which causes terran and protoss to play poorly after the opening. BOSS tends to build too many production buildings—I often see 6 or 7 gateways on a one-base income that can support 4 gateways, which is wasteful. BOSS also likes to bunch the production of similar things, not keeping the nexus and gateways busy at the same time, but rather “probe probe probe probe zealot zealot zealot zealot”, where first the nexus is busy, then the nexus goes idle and the gateways become busy. It’s crazy inefficient.

That is why Steamhammer’s 9-9Gate opening is so long and detailed. If it ended early like the Liquipedia build, then BOSS would take over sooner and build inefficiently, and the bot would fall behind in probe count and zealot count for the rest of the game. I know this for sure, because I’ve run the different variants head-to-head. Dave Churchill optimized the 9-9 gate opening already for UAlbertaBot, and he did an excellent job. I optimized the 10-12 gate opening myself in a similar way and did not do it as thoroughly; it has room for improvement.

Someday I’ll write a new macro system and drop BOSS, but not yet. I might be able to get to it this year....

Sometimes the middle game strategy decisions are silly. Terran and protoss are especially short on strategy smarts, but the zerg strategy boss also has many weaknesses. In one frustrating example, if the opening build makes a spire but doesn’t make the mutalisks, Steamhammer may decide that lurkers were a better idea after all, get no lair units for a long time, and lose. There are many ways for the strategy boss to misunderstand the strategy behind an opening, so that you have to write a long explicit build order. Some openings I have shortened after improving the strategy boss. Some openings have legacy endings that it might be good to remove.

Anyway, the bottom line is that Steamhammer is not strong enough to play Liquipedia opening builds uncritically. Some are fine, some will confuse the poor bot.

On the other hand, Steamhammer’s existing protoss openings leave a lot to be desired. They’re more a demonstration of what’s possible than a sound selection. It’s no surprise if Antiga’s openings are stronger.

Next: Looking at the donated openings.

NLPRbot

NLPRbot is cpac by Qiyue Yin. I don’t know, but I have to suspect that it is the same version of cpac that is playing in AIIDE 2017.

It is a fork of Steamhammer. The configuration file has been incorporated into the .dll, but it still tells what is going on. Versus terran, it plays Steamhammer’s 11Gas10PoolLurker opening 90% of the time, and a couple other openings the rest (a sensible choice). I couldn’t see any difference between its lurker micro and Steamhammer’s. Versus zerg it plays a half dozen openings, the openings that Steamhammer plays most often. Versus protoss and random it plays even more similarly to Steamhammer.

It has fixed opponent-specific openings named like this, in the order listed. The opponent names are the same as in AIIDE, and some are different than names on SSCAIT.

opponentopening
UAlbertaBotOverpoolSpeedDave
Steamhammer5PoolHard
Aiur5PoolHard
Ximp2HatchMutaXimp
Xelnaga5PoolHard
Skynet5PoolHardSkynet
MegaBot5PoolHard
MicrowaveZvZ_Overpool9Gas
ZZZKBot9PoolSpeedExpo
McRave2HatchMutaMcRave

I’m not sure why Aiur and Xelnaga rated special counters. The ordinary opening mix should beat them reliably.

I didn’t dig into the dll in detail, but I do see additions that look like tracking unit types and keeping feature vectors. It looks like there are extensive changes to the zerg strategy boss; possibly a learning algorithm has been plugged in. In one game I noticed different scouting behavior. Most of the time it plays like Steamhammer.

As far as the configuration itself goes, though, NLPRbot strikes me as a mildly obfuscated fork of Steamhammer 1.3, configured for maximum wins with minimum effort from the author. I don’t know any reason other than obfuscation to rename it from cpac to NLPRbot. Maybe the author wants it to look like an unrelated bot? Maybe somebody other than the author posted it? On the AIIDE roster, Qiyue Yin is listed as “Independent”, so it’s apparently not an institutional thing.

In any case, NLPRbot aka cpac seems successful so far, even scoring a win over Krasi0. With Steamhammer skills plus hand configuration plus strategy improvements, it should be a dangerous opponent.

Steamhammer’s opponent model

At its most general, a learning system consists of a data structure, a learning algorithm to update the data structure with new data, and a retrieval algorithm to answer questions from the learned data structure. You could say it is a specialized kind of memory, with a data store and ways to get information in and out. The information you get out is not the same as what you put in, and that is part of what makes it useful. Or you could say that ordinary computer memory is a learning system with no loss and no generalization.

One of my goals for Steamhammer’s opponent model is to learn from a single game. There is a well-known class of learning systems which makes it easy, because their data store is nothing more than a record of the original input data, called instance-based learning or memory-based learning. This simplest example is the k-nearest neighbors algorithm family: Your data is a set of points (x, y) , input x gives output y (where x and y might be, say, vectors). To learn from a new data point, simply store it along with the others. To answer questions of the form “what’s the output for input x?” you find a given number, k, of x‘s nearest neighbors according to some distance measure, and average their outputs (using whatever kind of average may be appropriate for your problem). A fancier class of systems that can draw complex conclusions from a single example goes under the name case-based reasoning, where the data store is a database of structured “cases”, or examples.

Anyway, I thought I should use a method in the nearest neighbor family. It’s the simplest way to meet my goals.

What should my data points look like? Well, what information does Steamhammer use to make strategy decisions? It looks at the enemy’s current unit mix. I want to be able to predict the enemy’s unit mix at a given time: “Oh no, those zerglings are early, it’s a rush!” or “this enemy switches to goliaths and hardly any tanks, I should build up hydralisks next.” Both are nothing more than unit mix @ time.

My data points are games, boiled down to sequences of unit mixes. In the first implementation, Steamhammer takes a snapshot of the unit mixes of both sides every 30 seconds, “this many drones, that many zerglings, ....” I also threw in some supplementary information: The map, the opening chosen, and as shortcuts for opening selection the times at which the enemy got various things, such as the first combat units, the first flyers, the first detection, and so on. And it simply appends all the data to a file named after that opponent.

To answer the question “what will the enemy’s unit mix be at time t?” the first implementation finds the nearest neighbor. It looks through the game records to find the best match game, the past game against the same opponent which is most like the current game, according to a similarity measure which adds up differences in unit mixes over time, up to the current time in the current game. (So the best match will change at most once every 30 seconds.) Having found the best match, it looks up the recorded enemy unit mix in the best match game record which is closest to time t and calls that the prediction. It’s dead simple.

That was my motivation. In fact, the game records have endless uses beyond predicting the enemy unit mix. For example, to figure out whether an opening is safe to play against this opponent, run the timings of the opening against the timings of the game records. If the opening always gets defenders in time, then the enemy will not smash you with a rush (or at least it will only be a surprise once). Or if you notice that the enemy never gets detection, then go lurkers and get an easy win. And so on.

Einstein, hand me the simplicity!

You can see why I thought the method was obvious. With clear goals and the right background knowledge, it is obvious. And you can see why I thought I could get it working within a few weeks; there is nothing complicated here. If I were a better coder, I would have succeeded.

Of course, it may turn out that the simplest option is not good enough. For the first cut I wanted to take the easiest way. If some part turns out to work poorly, I have improvements up my sleeve. The possible improvements are as endless as the possible uses.

  • The recorded unit mixes include buildings. Buildings are especially important for predicting what the opponent is up to, but my first cut similarity measure does not understand that. It treats the difference between 1 barracks or 2 the same as it treats the difference between 1 marine or 2, and that is obviously not ideal.
  • For some purposes, it may be better to record the total units ever made (or ever seen, if the enemy’s) instead of the current unit mix, because the current mix depends on the outcome of battles as well as the strategy followed.
  • If the best match is not close at all, maybe it should be ignored.
  • If there are a number of good matches, maybe they should be averaged together.
  • Surely the current unit mix should have a role in predicting the next unit mix. In the first cut, it is ignored.

The bottom line is that my first implementation may or may not work adequately. But I’m confident it can be improved until it does work.

Steamhammer AIIDE 2017 version

You can download the archive I submitted to AIIDE 2017, which is Steamhammer 1.3.1. It follows the AIIDE rules: It includes a compiled binary, the configuration file, and source. Unlike an SSCAIT submission, it does not include the BWAPI 4.1.2 library.

The configuration file is specialized for the tournament. The terran and protoss opening lines are removed, and it is intended to play zerg only. I did all my testing with zerg, and mostly on the AIIDE maps. Everything is optimized for the best AIIDE performance, at the expense of anything else.

Next is Steamhammer 1.3.2 for SSCAIT. It will restore the terran and protoss configuration. I also made a minor change that should improve devourer play (at least a little), and may make a few other small fixes. I need to test that protoss and terran are working well. It shouldn’t take more than a day or two, and then I’ll be right back on opponent modeling.

AIIDE 2017 outlook

AIIDE submission closes after today. Some bots may yet withdraw at the last moment or otherwise disappear, but we pretty much know the roster. I want to look ahead with the information we have.

race distribution

This year we have a zerg plurality. That happens to be good for Steamhammer, because ZvZ is Steamhammer’s best matchup.

race#%
terran721%
protoss1031%
zerg1443%
random13%

The percentages add up to 98% instead of 100% due to rounding.

BWAPI versions

I was surprised how many bots were already on BWAPI 4.2.0.

BWAPI#%
3.7.4928%
4.1.21753%
4.2.0618%

The 2 bots listed as withdrawn were also on BWAPI 4.2.0. Does anybody know if or when SSCAIT will support the newer version? I know resources are limited, so I won’t be surprised if it takes time.

6 of the 9 bots still on BWAPI 3.7.4 are the legacy bots carried over from last year. Only 3 are active entrants. Surprisingly, one of the 3 is ForceBot, which seems to be a recent bot since it only recently appeared on SSCAIT and suffered some teething troubles there.

the newcomers

There are unusually many absolute newcomers, bots whose names or authors I don’t recognize. History says that most newcomers will do poorly; it takes a long time to turn an empty repository into a contender. But there are exceptions. This year PurpleWave reached #3 in CIG 2017. Last year Bereaver was a sensation. It will be a surprise if an unknown wins—but surprises happen.

  • bonjwAI
  • CherryPi
  • cpac
  • DeepTerran
  • HOLD
  • Inspir
  • Myscbot
  • Sling

I think many are especially looking forward to the Facebook entry CherryPi by old hand Gabriel Synnaeve. I’ve read the papers, and my hopes are not high. My impression is that the project is not far along. I expect CherryPi to finish in the lower half, and I mainly hope that it will show some interesting behaviors along the way.

the unpredictable

A few bots are both potential top finishers and potential also-rans. Arrakhammer and McRave have shown inconsistent results, strong play when in their best form but many losses when problems creep into the codebase. AILien was often impressive on SSCAIT, but stopped playing there after updating to BWAPI 4.2.0. I don’t know what updates it may have seen since.

the known contenders

Iron is of course the favorite. In CIG, Iron suffered because it was unready for the new and troublesome maps. In AIIDE, the maps are standard and are the same as last year. I see a strong chance that Iron will pull in well ahead.

Bots that are likely to finish high are LetaBot, Microwave, PurpleWave, Steamhammer, UAlbertaBot, and ZZZKBot. ZZZKBot won CIG 2017 and is a perpetual contender. This tournament has more new bots than CIG, which favors ZZZKBot’s exceptionally well-implemented 4 pool—it smashes opponents which are not perfectly prepared. ZZZKBot is my pick as the most likely #2 finisher. Beyond that, it gets harder for me to forecast.

Steamhammer I think is likely to finish fairly high, but outside the top 3. It will lose almost all games versus Iron and PurpleWave, and some versus UAlbertaBot (which I expect to be stronger with the new SparCraft). Without opponent modeling and unable to adjust its strategy mixes, Steamhammer is also at risk of losing many games to newcomer bots. I see the opponent model as a necessary feature for a tournament, because unknown opponents might do anything, and known opponents might have surprises in hand.

But really, we don’t know. The tournament exists to find out.

Update: The roster page now says that 4 of the newcomer bots, plus AILien, either withdrew or did not submit. 27 contenders remain.

Update 2: Now AILien is listed as submitted after all. Whew.