archive by month
Skip to content

Steamhammer 2.1.1 status

Posts take time, but I am also making progress on Steamhammer. The next version will have no big features, so I’ll call it version 2.1.1. Big stuff has to wait until next year, after the tournament season. I found a second serious bug in defiler control, and now defilers consistently move to where they are wanted. It helps them swarm and plague more actively, though they still don’t do as much work as I would like. So far, 2.1.1 development version keeps track of burrowed units accurately, recognizes enemy proxies better, wards off the enemy scout worker more reliably, and has some improved macro decisions and emergency reactions, a new opening (of course), and a variety of other fixes.

There are a bunch of debilitating bugs in squad control and micro. For upcoming work, I have my eyes on 2 bugs in particular that I think cause the most frequent setbacks (rather than the most glaring blunders), the suicide pokes and the stuck units. If I get those fixed in time, I have a priority list of more stuff. If I succeed, Steamhammer will play better in nearly every game, which should show in the SSCAIT round robin phase.

AIIDE 2018 - what Steamhammer learned

In CIG, Steamhammer was broken. My findings on what Steamhammer learned in CIG 2018 are not valid, because Steamhammer rarely played the opening it thought it was playing; it played a broken version of the opening that left out drones and buildings. That is likely why the zergling rushes were successful in CIG: There was little in the build to leave out, so the build played more nearly as written. In this tournament, Steamhammer seems to have been working fine (though we’ll see when the replays come out)—well, working fine except for the usual bugs, some of which are fixed in version 2.1. Also, Steamhammer’s learning was revamped to better bamboozle opponents that tried to learn its patterns; the result is that its learning behavior is richer. I think these tables are full of interesting data.

103 rounds were played, of which 100 were official. Steamhammer is set to record at most 100 game records per opponent, so games from the first 3 rounds may have been dropped. That’s why the numbers don’t exactly match the official crosstable, even though the game totals look correct.

Steamhammer’s game records contain much more information than I can summarize in tidy little tables. This time I captured a little more of it, adding a table about the plan recognizer. For each plan that was recognized during a game, the table shows how often the plan was predicted before the game, how often it was recognized during the game, and the win rate in each of those cases. It also tries to measure the accuracy of the prediction. The plan recognizer itself is not very accurate; it often fails to recognize what is in front of it, calling the plan Unknown. The “?” column shows how often the plan was predicted and then no plan was recognized. The plan recognizer can also blow it completely and recognize the wrong plan. When the opponent plays predictably, the plan predictor is generally more accurate than the plan recognizer. When the opponent plays unpredictably, I don’t know which is more accurate! Either way, the plan prediction is more important early in the tournament; once Steamhammer has accumulated enough experience, it pays more attention to its learning data, and it doesn’t matter whether the predicted plan is good.

#1 saida

openinggameswins
11Gas10PoolLurker30%
11Gas10PoolMuta10%
11HatchTurtleHydra10%
2HatchHydraBust10%
3HatchHydraExpo10%
3HatchLurker10%
4HatchBeforeGas20%
4PoolHard30%
5PoolHard10%
5PoolSoft10%
6Pool10%
7PoolSoft20%
9Hatch8Pool20%
9HatchExpo9Pool9Gas10%
9Pool10%
9PoolExpo10%
9PoolLurker812%
9PoolSpeedAllIn10%
9PoolSunkSpeed10%
AntiFact_13Pool80%
AntiFact_2Hatch120%
AntiFactory160%
AntiZeal_12Hatch20%
Over10Hatch2SunkHard10%
OverhatchLateGas10%
Overpool+110%
OverpoolHatch10%
PurpleSwarmBuild10%
Sparkle 2HatchMuta20%
ZvP_3HatchPoolHydra10%
ZvT_12PoolMuta20%
ZvT_2HatchMuta10%
ZvT_3HatchMuta10%
ZvZ_12PoolLing10%
ZvZ_Overgas9Pool10%
ZvZ_Overpool11Gas1315%
ZvZ_Overpool9Gas10%
ZvZ_OverpoolTurtle10%
38 openings1003%
planpredictedrecognizedaccuracy
countgameswinscountgameswinsgood?
Factory100100%3%9191%3%91%2%
Naked expand0%0%77%0%0%0%
Unknown0%0%22%0%0%0%


SAIDA is a good example of how Steamhammer reacts to a predictable opponent. First, it repeatedly tried its counters to the opponent’s Factory plan, the 3 “AntiFact” openings (you may call them fake news openings if you like). In this case the counters did not work; SAIDA is too strong. Then it explored more widely. Steamhammer scored 1 win with a fast lurker opening, and repeated the opening to no avail (maybe Steamhammer got lucky once, or maybe SAIDA learned the timing). It also scored a win with a ZvZ fast mutalisk opening, and repeating that did bring a second win for a total of 3 in 100 rounds. The smaller second table shows that the plan predictor was 100% accurate over the last 100 rounds in predicting SAIDA’s factory-first play, while the plan recognizer was 91% accurate and actually saw a command center first in 7 games.

#2 cherrypi

openinggameswins
2.5HatchMuta10%
3HatchPoolMuta10%
4HatchBeforeGas10%
4PoolSoft10%
6PoolSpeed20%
7PoolHard10%
8Hatch7Pool10%
9Hatch8Pool10%
9PoolSunkSpeed10%
OverhatchLing10%
OverhatchMuta10%
OverpoolSpeed10%
OverpoolSunk10%
ZvP_2HatchMuta10%
ZvP_3BaseSpire+Den10%
ZvT_12PoolMuta10%
ZvT_3HatchMuta10%
ZvT_3HatchMutaExpo10%
ZvZ_12HatchMain2114%
ZvZ_12PoolLing10%
ZvZ_12PoolMain30%
ZvZ_Overgas9Pool10%
ZvZ_Overpool9Gas3030%
ZvZ_OverpoolTurtle2532%
24 openings10020%
planpredictedrecognizedaccuracy
countgameswinscountgameswinsgood?
Fast rush2222%14%11%0%0%100%
Heavy rush7777%22%2828%25%35%61%
Naked expand11%0%22%0%0%0%
Unknown0%0%6969%19%0%0%


Steamhammer sees CherryPi as a strategy switcher. I suspect that CherryPi did not actually play any fast zergling rushes, because they said they avoided risky openings, but I can’t be sure without a closer look. In any case, Steamhammer found answers and scored a respectable 20% against a much higher ranked opponent.

#3 cse

openinggameswins
11Gas10PoolLurker10%
11Gas10PoolMuta1020%
11HatchTurtleHydra20%
11HatchTurtleLurker10%
12HatchTurtle10%
2.5HatchMuta10%
2HatchHydra10%
2HatchHydraBust50%
2HatchLurkerAllIn10%
3HatchHydraBust90%
3HatchHydraExpo10%
3HatchLingBust30%
3HatchLingExpo10%
3HatchLurker20%
3HatchPoolMuta10%
4HatchBeforeGas60%
4PoolHard20%
5PoolHard2Player20%
5PoolSoft10%
7PoolHard20%
7PoolSoft10%
8Pool30%
9HatchExpo9Pool9Gas10%
9PoolExpo10%
9PoolHatch10%
9PoolSpeedAllIn20%
9PoolSpire20%
AntiFact_2Hatch10%
AntiZeal_12Hatch10%
Over10Hatch2SunkHard10%
Over10HatchBust20%
Over10HatchSlowLings20%
OverhatchExpoLing30%
OverhatchExpoMuta10%
OverhatchMuta10%
Overpool+110%
OverpoolHydra10%
OverpoolLurker10%
OverpoolSpeed20%
PurpleSwarmBuild10%
Sparkle 1HatchMuta10%
ZvP_2HatchMuta50%
ZvP_3BaseSpire+Den30%
ZvP_3HatchPoolHydra40%
ZvP_4HatchPoolHydra10%
ZvZ_12Pool20%
ZvZ_Overpool11Gas10%
ZvZ_Overpool9Gas10%
48 openings1002%
planpredictedrecognizedaccuracy
countgameswinscountgameswinsgood?
Heavy rush0%0%44%0%0%0%
Safe expand1919%0%3333%0%32%5%
Turtle8181%2%6060%3%60%2%
Unknown0%0%33%0%0%0%


Steamhammer has trouble telling the difference between Safe Expand (in the protoss case, forge expand with cannons) and Turtle (hide behind cannons), because it does not scout well enough to see the natural nexus reliably. It compensates by reacting similarly in both cases. But the opponent is still seen as an unpredictable strategy switcher, so Steamhammer switches up its openings too. In this case it has more counter openings and tries each fewer times, so they are not as obvious in the table, but they do have higher counts: See 2HatchHydraBust, 3HatchHydraBust, 3HatchLingBust, 4HatchBeforeGas, ZvP_2HatchMuta, and ZvP_3BaseSpire+Den. As against SAIDA, Steamhammer scored 2 wins with a ZvZ fast mutalisk opening. I have an idea to add another exploration phase which experiments with all-in attacks like the fast mutas.

#4 bluebluesky

openinggameswins
11Gas10PoolLurker20%
11Gas10PoolMuta10%
11HatchTurtleHydra20%
2.5HatchMuta10%
2HatchHydraBust50%
2HatchLurker10%
2HatchLurkerAllIn10%
3HatchHydraBust10%
3HatchLingBust10%
3HatchLingExpo10%
4HatchBeforeGas30%
4PoolSoft10%
5PoolHard10%
7PoolHard1010%
8Pool10%
9HatchExpo9Pool9Gas1811%
9HatchMain9Pool9Gas10%
9PoolSpeed30%
9PoolSpeedAllIn30%
AntiFact_2Hatch10%
Over10Hatch20%
Over10Hatch1Sunk10%
Over10Hatch2Sunk20%
Over10Hatch2SunkHard10%
OverhatchExpoLing20%
Overpool+110%
OverpoolHatch10%
OverpoolHydra10%
OverpoolSpeed10%
OverpoolTurtle10%
PurpleSwarmBuild10%
Sparkle 1HatchMuta10%
Sparkle 2HatchMuta10%
Sparkle 3HatchMuta10%
ZvP_2HatchMuta40%
ZvP_3BaseSpire+Den70%
ZvP_3HatchPoolHydra60%
ZvT_13Pool10%
ZvZ_Overgas11Pool10%
ZvZ_Overgas9Pool30%
ZvZ_Overpool11Gas20%
ZvZ_Overpool9Gas10%
42 openings1003%
planpredictedrecognizedaccuracy
countgameswinscountgameswinsgood?
Heavy rush77%0%2020%5%29%0%
Naked expand0%0%11%100%0%0%
Safe expand5353%2%4545%0%58%2%
Turtle4040%5%3333%3%45%0%
Unknown0%0%11%0%0%0%


Different all-ins took a few wins from BlueBlueSky.

#5 locutus

openinggameswins
11Gas10PoolLurker20%
11HatchTurtleLurker10%
12HatchTurtle10%
2HatchHydra10%
2HatchHydraBust50%
2HatchLurker20%
2HatchLurkerAllIn20%
3HatchHydra10%
3HatchHydraBust30%
3HatchHydraExpo10%
3HatchLingBust2512%
3HatchLingExpo20%
4PoolSoft10%
5PoolHard20%
6PoolSpeed10%
8Hatch7Pool10%
8Pool10%
9HatchExpo9Pool9Gas10%
9HatchMain9Pool9Gas10%
9PoolSpeed10%
9PoolSpeedAllIn10%
AntiFact_13Pool10%
AntiFact_2Hatch10%
AntiFactory10%
AntiZeal_12Hatch10%
Over10Hatch10%
Over10Hatch2SunkHard10%
OverhatchExpoMuta20%
OverhatchLateGas10%
OverpoolHydra10%
OverpoolSpeed10%
OverpoolSunk10%
OverpoolTurtle10%
PurpleSwarmBuild20%
Sparkle 2HatchMuta10%
Sparkle 3HatchMuta10%
ZvP_2HatchMuta50%
ZvP_3BaseSpire+Den40%
ZvP_3HatchPoolHydra50%
ZvP_Overpool3Hatch10%
ZvT_12PoolMuta40%
ZvT_13Pool10%
ZvT_2HatchMuta10%
ZvT_3HatchMuta10%
ZvZ_12Pool10%
ZvZ_12PoolLing10%
ZvZ_12PoolMain10%
ZvZ_Overgas9Pool10%
ZvZ_Overpool9Gas10%
49 openings1003%
planpredictedrecognizedaccuracy
countgameswinscountgameswinsgood?
Heavy rush0%0%44%25%0%0%
Safe expand6262%3%5555%0%60%0%
Turtle3838%3%4141%5%50%0%

#6 isamind

openinggameswins
11Gas10PoolLurker10%
11Gas10PoolMuta10%
2.5HatchMuta10%
2HatchHydra10%
2HatchHydraBust60%
2HatchLurker10%
3HatchHydra10%
3HatchHydraBust50%
3HatchLingBust50%
4HatchBeforeGas30%
4PoolHard10%
4PoolSoft20%
5PoolHard2Player10%
5PoolSoft10%
7PoolHard1118%
7PoolMid10%
7PoolSoft10%
8Hatch7Pool10%
8Pool10%
9HatchExpo9Pool9Gas30%
9HatchMain9Pool9Gas10%
9PoolSpeed10%
9PoolSunkHatch10%
AntiFact_13Pool10%
AntiZeal_12Hatch10%
Over10Hatch10%
Over10Hatch1Sunk20%
Over10Hatch2Sunk10%
Over10Hatch2SunkHard10%
Over10HatchSlowLings10%
OverhatchExpoLing30%
OverpoolHatch812%
OverpoolHydra10%
OverpoolLurker20%
OverpoolSpeed20%
PurpleSwarmBuild10%
ZvP_2HatchMuta20%
ZvP_3BaseSpire+Den40%
ZvP_3HatchPoolHydra617%
ZvP_Overpool3Hatch30%
ZvT_2HatchMuta40%
ZvT_3HatchMutaExpo10%
ZvZ_12HatchMain10%
ZvZ_12PoolMain10%
ZvZ_Overpool11Gas10%
ZvZ_OverpoolTurtle10%
46 openings1004%
planpredictedrecognizedaccuracy
countgameswinscountgameswinsgood?
Heavy rush1717%12%1414%14%65%6%
Proxy22%0%22%0%0%0%
Safe expand6262%3%4747%2%47%5%
Turtle1919%0%3333%3%26%0%
Unknown0%0%44%0%0%0%

#7 daqin

openinggameswins
11Gas10PoolMuta812%
2HatchHydra20%
2HatchHydraBust50%
2HatchLurkerAllIn50%
3HatchHydra20%
3HatchHydraBust30%
3HatchHydraExpo20%
3HatchLing10%
3HatchLingBust40%
3HatchLingExpo10%
4HatchBeforeGas40%
4PoolSoft10%
5PoolHard2Player20%
6PoolSpeed30%
8Hatch7Pool10%
9HatchExpo9Pool9Gas10%
9PoolHatch20%
9PoolSpeedAllIn30%
9PoolSpire10%
9PoolSunkHatch30%
9PoolSunkSpeed20%
AntiFact_13Pool10%
AntiFact_2Hatch20%
AntiZeal_12Hatch10%
Over10Hatch1Sunk20%
Over10Hatch2Sunk30%
OverhatchExpoLing10%
OverhatchExpoMuta40%
OverhatchLateGas10%
OverhatchLing10%
OverpoolHatch10%
OverpoolHydra20%
OverpoolLurker10%
OverpoolSpeed40%
OverpoolSunk10%
OverpoolTurtle10%
Sparkle 1HatchMuta20%
ZvP_2HatchMuta20%
ZvP_3BaseSpire+Den30%
ZvP_3HatchPoolHydra20%
ZvP_4HatchPoolHydra10%
ZvT_12PoolMuta10%
ZvT_3HatchMutaExpo10%
ZvZ_12HatchExpo10%
ZvZ_12HatchMain10%
ZvZ_12PoolLing10%
ZvZ_Overgas11Pool10%
ZvZ_OverpoolTurtle20%
48 openings1001%
planpredictedrecognizedaccuracy
countgameswinscountgameswinsgood?
Heavy rush0%0%33%0%0%0%
Proxy1010%0%1616%0%0%0%
Safe expand3535%0%3434%0%29%6%
Turtle5555%2%4141%2%40%7%
Unknown0%0%66%0%0%0%

#8 mcrave

openinggameswins
11HatchTurtleHydra1250%
2HatchHydra1136%
2HatchLurker250%
2HatchLurkerAllIn10%
3HatchHydraBust743%
3HatchLing20%
3HatchLingBust10%
AntiZeal_12Hatch20%
Over10Hatch2Hard10%
Over10HatchBust10%
OverhatchLateGas2330%
ZvP_3HatchPoolHydra1323%
ZvP_Overpool3Hatch10%
ZvT_12PoolMuta10%
ZvZ_OverpoolTurtle2264%
15 openings10038%
planpredictedrecognizedaccuracy
countgameswinscountgameswinsgood?
Heavy rush9191%37%5151%25%54%31%
Safe expand88%38%1111%45%0%62%
Turtle11%100%55%20%0%0%
Unknown0%0%3333%58%0%0%


The plan predictor struggled to predict what McRave was going to do next, but learning worked well anyway—eventually. The ZvZ_OverpoolTurtle choice is a big surprise, an opening that builds 3 sunkens and gets fast mutalisks on one base. The opening is sound only against certain all-in zerg strategies; protoss really ought to smash it. I’m guessing it worked against a zealot rush where McRave was slow to switch tech when the mutas showed up.

#9 iron

openinggameswins
12HatchTurtle10%
2.5HatchMuta10%
3HatchPoolMuta911%
9PoolExpo825%
9PoolSunkHatch10%
AntiFact_13Pool3523%
AntiFact_2Hatch20%
AntiFactory10%
AntiZeal_12Hatch10%
OverpoolLurker10%
OverpoolSpeed10%
OverpoolSunk10%
ZvP_4HatchPoolHydra10%
ZvZ_12PoolMain10%
ZvZ_Overgas11Pool1450%
ZvZ_Overpool9Gas2245%
16 openings10028%
planpredictedrecognizedaccuracy
countgameswinscountgameswinsgood?
Factory100100%28%9191%29%91%7%
Turtle0%0%22%0%0%0%
Unknown0%0%77%29%0%0%


When I run matches locally against Iron, Steamhammer soon settles on AntiFactory as the most reliable answer, and that does seem best. For some reason, Steamhammer behaved differently in both CIG and AIIDE. It is astonishing that ZvZ fast mutalisk openings came out on top again. Exactly as against SAIDA, the plan predictor was 100% accurate while the plan recognizer was 91% accurate.

#10 zzzkbot

openinggameswins
3HatchHydraBust10%
4PoolHard10%
9PoolSpeedAllIn1479%
9PoolSunkHatch2232%
OverhatchExpoLing10%
OverhatchLing10%
OverpoolSunk2138%
ZvP_3HatchPoolHydra10%
ZvP_4HatchPoolHydra10%
ZvZ_Overgas9Pool2544%
ZvZ_Overpool11Gas520%
ZvZ_Overpool9Gas10%
ZvZ_OverpoolTurtle617%
13 openings10039%
planpredictedrecognizedaccuracy
countgameswinscountgameswinsgood?
Fast rush7777%42%2121%57%22%75%
Heavy rush1414%21%22%0%0%86%
Turtle99%44%22%100%22%56%
Unknown0%0%7575%33%0%0%


9PoolSunkHatch and OverpoolSunk are anti-rush openings, and 9PoolSpeedAllIn is general-purpose but good against rushes. In contrast, ZvZ_Overgas9Pool is a fast mutalisk opening and can be overrun by too many zerglings. I don’t know how accurate the plan predictions are, but they agree fairly well with the selected openings.

#12 microwave

openinggameswins
11Gas10PoolMuta2832%
3HatchHydraBust10%
3HatchLing10%
3HatchLingExpo10%
3HatchLurker10%
4PoolSoft1217%
5PoolHard2Player10%
9HatchMain9Pool9Gas20%
9PoolSpeed10%
9PoolSpeedAllIn10%
9PoolSunkSpeed20%
AntiFact_2Hatch10%
OverhatchLing20%
OverpoolSunk425%
ZvZ_12HatchMain20%
ZvZ_12PoolLing10%
ZvZ_12PoolMain20%
ZvZ_Overgas9Pool20%
ZvZ_Overpool11Gas1020%
ZvZ_Overpool9Gas2339%
ZvZ_OverpoolTurtle20%
21 openings10023%
planpredictedrecognizedaccuracy
countgameswinscountgameswinsgood?
Fast rush1515%27%1010%50%13%53%
Heavy rush4242%17%2020%40%14%45%
Naked expand4343%28%2121%5%21%49%
Turtle0%0%11%0%0%0%
Unknown0%0%4848%19%0%0%


Microwave really mixed things up, and it was successful! Steamhammer could not predict the opening switches. It’s interesting that when Steamhammer predicted a fast rush, it won a quarter of the time, and when it actually recognized a fast rush, it won half the time. That doesn’t tell us what actually happened in the games. When Steamhammer recognizes a fast rush, it can react no matter what opening it is playing, and often save itself. When it is rushed and doesn’t recognize it, it will lose unless it is playing a safe opening.

#13 lastorder

openinggameswins
3HatchLingBust1233%
4PoolHard10%
4PoolSoft2129%
6PoolSpeed10%
AntiFactory10%
Over10Hatch10%
Over10Hatch1Sunk425%
OverhatchLing20%
OverhatchMuta729%
PurpleSwarmBuild10%
ZvP_3HatchPoolHydra10%
ZvT_3HatchMutaExpo633%
ZvZ_12HatchMain1331%
ZvZ_12PoolLing520%
ZvZ_12PoolMain50%
ZvZ_Overpool11Gas1735%
ZvZ_OverpoolTurtle20%
17 openings10026%
planpredictedrecognizedaccuracy
countgameswinscountgameswinsgood?
Heavy rush100100%26%7777%25%77%14%
Naked expand0%0%33%0%0%0%
Turtle0%0%66%17%0%0%
Unknown0%0%1414%43%0%0%


LastOrder did not learn during the tournament and played predictably, yet Steamhammer struggled to find an answer. We also know that LastOrder learned extensively offline before the tournament. Knowing that, and looking at these tables (check out the variety of recognized plans and the variety of Steamhammer’s more successful openings), I get the impression that LastOrder is highly adaptive and knows how to react in a wide variety of situations. I guess we’ll see when the replays come out.

#14 tyr

openinggameswins
2HatchHydraBust1338%
2HatchLurkerAllIn1443%
3HatchHydraExpo3876%
4HatchBeforeGas20%
4PoolHard425%
9PoolSunkSpeed10%
Over10Hatch2Hard10%
Over10HatchBust10%
OverpoolLurker729%
OverpoolSpeed5100%
ZvP_3BaseSpire+Den1362%
ZvP_3HatchPoolHydra10%
12 openings10056%
planpredictedrecognizedaccuracy
countgameswinscountgameswinsgood?
Heavy rush3939%56%4545%78%41%3%
Naked expand0%0%11%100%0%0%
Turtle6161%56%5050%32%48%5%
Unknown0%0%44%100%0%0%


These numbers say that anything which helps Steamhammer find the right answers early, without having to do so much random exploration, would be a big win in a long tournament. The plan recognizer is not good enough.

#15 metabot

openinggameswins
11Gas10PoolLurker250%
11HatchTurtleHydra683%
12HatchTurtle367%
2HatchLurkerAllIn367%
3HatchHydraExpo10%
3HatchLing1182%
3HatchLingExpo1060%
4PoolHard10%
6PoolSpeed2100%
9HatchExpo9Pool9Gas850%
9PoolHatch367%
9PoolSpeedAllIn250%
AntiZeal_12Hatch10%
Over10Hatch250%
Over10Hatch2Hard1100%
Over10Hatch2Sunk30%
OverhatchExpoLing862%
OverhatchExpoMuta1443%
OverhatchLateGas425%
OverpoolSpeed475%
ZvP_2HatchMuta250%
21 openings9157%
planpredictedrecognizedaccuracy
countgameswinscountgameswinsgood?
Heavy rush3437%65%1921%68%21%41%
Naked expand33%33%33%100%0%33%
Safe expand3437%56%2022%45%21%38%
Turtle1921%47%1314%46%11%42%
Unknown11%100%3640%58%0%0%


It must have been a crazy learning duel! Later I’ll try to figure out what MetaBot learned, and we can check them against each other.

#16 letabot

openinggameswins
12HatchTurtle20%
3HatchLing10%
6PoolSpeed1164%
9HatchExpo9Pool9Gas633%
9PoolLurker4582%
OverpoolHatch771%
OverpoolLurker2882%
7 openings10074%
planpredictedrecognizedaccuracy
countgameswinscountgameswinsgood?
Heavy rush9999%74%5959%78%59%20%
Safe expand0%0%44%50%0%0%
Turtle11%100%1717%76%0%0%
Unknown0%0%2020%65%0%0%

#17 arrakhammer

openinggameswins
2HatchLurkerAllIn10%
4PoolHard2268%
6PoolSpeed5275%
7Pool12Hatch10%
9HatchMain9Pool9Gas10%
9PoolSpeedAllIn10%
AntiFactory10%
Over10Hatch2SunkHard10%
Over10HatchBust10%
Over10HatchSlowLings10%
OverhatchExpoMuta10%
OverhatchLing10%
OverpoolHydra10%
ZvZ_12HatchMain10%
ZvZ_12PoolLing10%
ZvZ_12PoolMain20%
ZvZ_Overpool11Gas1136%
17 openings10058%
planpredictedrecognizedaccuracy
countgameswinscountgameswinsgood?
Heavy rush9999%58%7878%65%78%1%
Naked expand11%100%2121%29%0%0%
Unknown0%0%11%100%0%0%


This old version of Arrakhammer has a fixed anti-Steamhammer opening configured. It was written before Steamhammer had learning. Modern Steamhammer can exploit the fixed opening. You can’t get away with that any more.

#18 ecgberht

openinggameswins
11Gas10PoolLurker1191%
11HatchTurtleLurker51100%
9PoolLurker3797%
OverpoolLurker10%
4 openings10097%
planpredictedrecognizedaccuracy
countgameswinscountgameswinsgood?
Heavy rush100100%97%6767%96%67%33%
Unknown0%0%3333%100%0%0%

#19 ualbertabot

openinggameswins
3HatchLurker10%
7PoolHard1182%
AntiZeal_12Hatch757%
OverhatchExpoMuta10%
OverpoolTurtle8098%
5 openings10091%
planpredictedrecognizedaccuracy
countgameswinscountgameswinsgood?
Factory22%100%1111%100%0%0%
Fast rush1212%92%1515%80%33%25%
Heavy rush8585%91%4545%89%45%22%
Naked expand11%100%77%100%0%0%
Unknown0%0%2222%95%0%0%


Getting that 98% win rate is one of the reasons I added the seemingly nonsensical overpool turtle opening, which makes an absurd 6 sunkens on one base. It works against all kinds of rushes, fast or slow, when the rusher does not know how to adapt.

#20 ximp

openinggameswins
3HatchHydraExpo1782%
4HatchBeforeGas3683%
9Hatch8Pool10%
AntiFactory10%
ZvP_2HatchMuta978%
ZvP_3BaseSpire+Den3678%
6 openings10079%
planpredictedrecognizedaccuracy
countgameswinscountgameswinsgood?
Safe expand33%100%1818%94%0%0%
Turtle9797%78%7878%76%77%4%
Unknown0%0%44%75%0%0%


Why didn’t Steamhammer try the 3 hatch before pool opening even once in 100 rounds? I expect it would have scored higher. Well, I know why; when the win rate is so convincing, Steamhammer doesn’t explore much.

#21 cdbot

openinggameswins
11HatchTurtleHydra10%
9PoolSunkSpeed1547%
OverpoolSunk8296%
ZvP_Overpool3Hatch10%
ZvZ_12PoolLing10%
5 openings10086%
planpredictedrecognizedaccuracy
countgameswinscountgameswinsgood?
Fast rush9696%85%3131%71%29%57%
Heavy rush44%100%1313%100%0%25%
Unknown0%0%5656%91%0%0%

#22 aiur

openinggameswins
11Gas10PoolLurker10%
3HatchHydraExpo2889%
5PoolHard2Player10%
AntiZeal_12Hatch4691%
Over10Hatch2492%
5 openings10089%
planpredictedrecognizedaccuracy
countgameswinscountgameswinsgood?
Heavy rush9595%89%6565%91%64%18%
Naked expand44%75%1515%73%0%25%
Proxy0%0%22%50%0%0%
Turtle11%100%0%0%0%0%
Unknown0%0%1818%100%0%0%


Turtle was predicted once but never recognized in the last 100 games. That implies that Steamhammer recognized a turtle opening in the first 3 rounds—and it was wrong, since AIUR doesn’t do that; it must have been a misrecognized cannon rush, a bug that has crept in. Comparing against what AIUR learned, I see that AIUR cannon rushed Steamhammer 3 times total, all failures, and favored its defensive strategy.

#23 killall

openinggameswins
6PoolSpeed10%
9PoolSpeed37100%
ZvZ_12PoolMain10%
ZvZ_OverpoolTurtle6193%
4 openings10094%
planpredictedrecognizedaccuracy
countgameswinscountgameswinsgood?
Heavy rush7575%93%4343%91%49%36%
Naked expand55%80%1212%100%20%20%
Turtle2020%100%1010%100%45%35%
Unknown0%0%3535%94%0%0%

#24 willyt

openinggameswins
11Gas10PoolLurker3097%
11HatchTurtleLurker786%
12HatchTurtle20%
2HatchLurkerAllIn2496%
6PoolSpeed10%
9PoolLurker10%
OverpoolLurker35100%
7 openings10093%
planpredictedrecognizedaccuracy
countgameswinscountgameswinsgood?
Heavy rush100100%93%8585%96%85%15%
Unknown0%0%1515%73%0%0%

#25 ailien

openinggameswins
3HatchLurker10%
6PoolSpeed10%
9PoolSpeedAllIn10%
OverhatchLing10%
ZvT_3HatchMuta10%
ZvZ_Overgas9Pool743%
ZvZ_Overpool9Gas2085%
ZvZ_OverpoolTurtle6893%
8 openings10083%
planpredictedrecognizedaccuracy
countgameswinscountgameswinsgood?
Naked expand9898%85%33%0%2%98%
Unknown22%0%9797%86%0%50%

#26 cunybot

openinggameswins
11Gas10PoolMuta10%
5PoolHard2Player367%
OverhatchLing1593%
OverpoolSpeed10%
ZvZ_12HatchExpo250%
ZvZ_OverpoolTurtle77100%
6 openings9995%
planpredictedrecognizedaccuracy
countgameswinscountgameswinsgood?
Fast rush44%100%33%100%0%75%
Heavy rush1313%100%66%83%0%62%
Naked expand6263%94%2020%90%19%61%
Turtle1919%100%1010%100%11%58%
Unknown11%0%6061%97%0%0%

#27 hellbot

openinggameswins
2HatchHydraBust580%
3HatchHydra7100%
3HatchHydraBust12100%
3HatchHydraExpo14100%
3HatchLingBust8100%
4HatchBeforeGas16100%
Over10Hatch1Sunk3100%
ZvP_2HatchMuta11100%
ZvP_3BaseSpire+Den15100%
ZvP_3HatchPoolHydra9100%
10 openings10099%
planpredictedrecognizedaccuracy
countgameswinscountgameswinsgood?
Turtle100100%99%7676%99%76%24%
Unknown0%0%2424%100%0%0%

overall

totalZvTZvPZvZZvR
openinggameswinsgameswinsgameswinsgameswinsgameswins
11Gas10PoolLurker5375% 4489% 911%
11Gas10PoolMuta5024% 10% 2015% 2931%
11HatchTurtleHydra2446% 10% 2250% 10%
11HatchTurtleLurker6095% 5898% 20%
12HatchTurtle1020% 50% 540%
2.5HatchMuta50% 10% 30% 10%
2HatchHydra1625% 1625%
2HatchHydraBust4520% 10% 4420%
2HatchLurker617% 617%
2HatchLurkerAllIn5260% 2496% 2730% 10%
3HatchHydra1164% 1164%
3HatchHydraBust4236% 4038% 20%
3HatchHydraExpo10380% 10% 10280%
3HatchLing1656% 10% 1464% 10%
3HatchLingBust5925% 4723% 1233%
3HatchLingExpo1638% 1540% 10%
3HatchLurker60% 10% 20% 20% 10%
3HatchPoolMuta119% 911% 10% 10%
4HatchBeforeGas7363% 20% 7066% 10%
4PoolHard3546% 30% 812% 2462%
4PoolSoft3921% 50% 3424%
5PoolHard40% 10% 30%
5PoolHard2Player1020% 60% 450%
5PoolSoft30% 10% 20%
6Pool10% 10%
6PoolSpeed7564% 1258% 633% 5768%
7Pool12Hatch10% 10%
7PoolHard3534% 2313% 10% 1182%
7PoolMid10% 10%
7PoolSoft40% 20% 20%
8Hatch7Pool40% 30% 10%
8Pool60% 60%
9Hatch8Pool40% 20% 10% 10%
9HatchExpo9Pool9Gas3921% 729% 3219%
9HatchMain9Pool9Gas60% 30% 30%
9Pool10% 10%
9PoolExpo1020% 922% 10%
9PoolHatch633% 633%
9PoolLurker9181% 9181%
9PoolSpeed4386% 50% 3897%
9PoolSpeedAllIn2941% 10% 119% 1765%
9PoolSpire30% 30%
9PoolSunkHatch2726% 10% 40% 2232%
9PoolSunkSpeed2232% 10% 30% 1839%
AntiFact_13Pool4617% 4319% 30%
AntiFact_2Hatch200% 140% 50% 10%
AntiFactory210% 170% 20% 20%
AntiZeal_12Hatch6373% 30% 5379% 757%
Over10Hatch3174% 3077% 10%
Over10Hatch1Sunk1233% 838% 425%
Over10Hatch2Hard333% 333%
Over10Hatch2Sunk90% 90%
Over10Hatch2SunkHard60% 10% 40% 10%
Over10HatchBust50% 40% 10%
Over10HatchSlowLings40% 30% 10%
OverhatchExpoLing1828% 1729% 10%
OverhatchExpoMuta2326% 2129% 10% 10%
OverhatchLateGas3027% 10% 2928%
OverhatchLing2458% 10% 2361%
OverhatchMuta922% 10% 825%
Overpool+130% 10% 20%
OverpoolHatch1833% 862% 1010%
OverpoolHydra70% 60% 10%
OverpoolLurker7679% 6589% 1118%
OverpoolSpeed2236% 10% 1942% 20%
OverpoolSunk11179% 10% 20% 10881%
OverpoolTurtle8394% 30% 8098%
PurpleSwarmBuild70% 10% 50% 10%
Sparkle 1HatchMuta40% 40%
Sparkle 2HatchMuta40% 20% 20%
Sparkle 3HatchMuta20% 20%
ZvP_2HatchMuta4146% 4048% 10%
ZvP_3BaseSpire+Den8659% 8560% 10%
ZvP_3HatchPoolHydra4927% 10% 4628% 20%
ZvP_4HatchPoolHydra40% 10% 20% 10%
ZvP_Overpool3Hatch60% 50% 10%
ZvT_12PoolMuta90% 20% 60% 10%
ZvT_13Pool20% 20%
ZvT_2HatchMuta60% 10% 50%
ZvT_3HatchMuta40% 10% 10% 20%
ZvT_3HatchMutaExpo922% 20% 729%
ZvZ_12HatchExpo333% 10% 250%
ZvZ_12HatchMain3918% 20% 3719%
ZvZ_12Pool30% 30%
ZvZ_12PoolLing128% 10% 20% 911%
ZvZ_12PoolMain160% 10% 20% 130%
ZvZ_Overgas11Pool1644% 1450% 20%
ZvZ_Overgas9Pool4035% 10% 40% 3540%
ZvZ_Overpool11Gas6025% 1315% 40% 4330%
ZvZ_Overpool9Gas10045% 2343% 30% 7447%
ZvZ_OverpoolTurtle26782% 10% 2556% 24185%
total259052%50059%109139%89958%10091%
openings played915287555

Steamhammer played all of its openings during the tournament, almost all of them multiple times. It even tried the 3 specialized openings for the island map Sparkle. Nearly as many were played in ZvP alone, since it spent so much time desperately seeking an answer to the Locutusoids (or possibly Susan). Some openings were highly successful in given matchups, which generally means that the opening defeated one opponent reliably and so was played many times. For example, OverpoolSunk wiped out CDBot, which makes it look in this table as though it wiped out all zergs. If only it were so simple! The opening with the best success across matchups is 6PoolSpeed, an opening that I have never seen in human play.

Steamhammer 2.1 change list

Steamhammer 2.1 is uploaded. The headline feature is that terran and protoss play acceptably well again, unlike in version 2.0, so Randomhammer is updated. Zerg should also play significantly better: Zergling micro is fixed, scourge are more effective (I hope), and defilers are more active.

I reset Steamhammer’s learned data for version 2.0, because 2.0 plays differently. Since then it has learned enough to play its best against some opponents, but it is still short of equilibrium. It reached final elo 2164, which is probably lower than its elo if it had enough games under its belt. Version 2.1 is not that different from 2.0, so it is continuing with the same data.

I reset Randomhammer’s data for 2.1, since the existing data is for version 1.4.7. It will have to figure its opponents out from scratch again, which will take months.

Stand by for source. I’m way behind in updating Steamhammer’s web page. Here is the change list:

opponent model

• Fixed a bug in InformationManager that could fail to recognize an in-base proxy.

macro

• Configured WorkersPerPatch to 2.0 for terran and protoss, to reflect mineral locking. Mineral locking helps terran and protoss over zerg, because bases tend to have more workers. Reducing the maximum worker count per base while maintaining full mining efficiency means that much more cash and supply to spend on tech and army.

tactics

• Medics and tanks act in clusters. They are controlled by their own code, which needed updating.

• Bug fix: A cluster of all medics which happened to reach the front line would then continue to advance heedlessly into the enemy position and die. Now it falls back toward the base—normally it will soon merge with another cluster that is on the way. To implement this, I split the former “no fight” case into 2 cases, “I have no fighting units” and “there are no enemies nearby,” which behave differently. All medics is an example of no fighting units.

• Steamhammer knows a number of places that a cluster of units can retreat to. I moved “retreat to join up with another cluster” (which can be an advance rather than a retreat) ahead of “retreat to the location of a cluster unit which is not near the enemy” in priority order. It helps clusters merge a little more often.

• When there are many clusters, Steamhammer saves execution time by not updating all clusters every frame. It divides the clusters into “phases” and updates one phase per frame. In Steamhammer 2.0, the phases were calculated incorrectly, which contributed to bad micro (though it wasn’t the biggest cause). Fixed.

combat sim

• Combat sim scores are based on the cost of units, not the destroyScore, because destroyScore is sometimes strange. For now I set score = mineral cost + gas cost.

• Steamhammer uses the combat sim scores in an unusual way to decide who won the simulation: It’s the side that ended up with more stuff surviving. It seems illogical, but it tested better than alternatives I tried, such as the side that lost less. Still, there are pathological cases where it gives a wrong answer. I fixed this pathological case: If you lost nothing, then you won the simulation, even if you finished with less stuff surviving. (If the other side also lost nothing, then you still won, because a draw counts as a win.)

• I also changed the units included in the combat sim in special cases. 1. If you have nothing but ground units that can’t shoot up, then ignore enemy air units that can’t shoot down. Because the side with more surviving stuff wins, this can affect who wins the simulation. This fixes another pathological case, where for example zerglings might run away from corsairs. 2. If you’re scourge, include only ground enemies that can shoot up. Scourge are never afraid of the air units that they want to destroy, only of useless death by ground enemies.

At some point I’ll add the other natural special case, for air units that can’t shoot down. All this combat sim stuff could be way more sophisticated....

micro

• I fixed the biggest cause of poor micro in Steamhammer 2.0. As part of choosing an enemy target, the melee and ranged unit controllers called CanCatchUnit() to see whether the enemy unit would be able to escape if chased. It was meant to reduce goose chases. Anyway, the results of CanCatchUnit() are apparently wrong. I haven’t looked into what the trouble was, because I found that removing the calls had no effect on goose chases—long chases have become rare due to other changes. The error caused units to overlook targets that they could, and often should, attack. Zergling micro became weak, and zealot micro was worse. It’s all back to normal now.

• Vultures and wraiths would become fixated on their targets, unable to switch away even to retreat in an emergency. Fixed.

• Like clusters, defiler actions are divided into phases. There was a bug in coordinating the cluster phases and defiler phases, so that defiler actions might be skipped for a long time depending on the phase of the cluster the defiler was in. Fixing it makes defilers more active, though they still don’t swarm or plague as often as they should.

• Scourge is allowed to spread out more in regrouping. Mutalisks should usually group tight, scourge should spread out some. Formerly, all air units behaved the same.

• I made a couple adjustments to defiler plague. 1. Plague on a building was formerly worth 0.6 of plague on units with the same hit point loss; I changed the discount to 0.3, half as much, so that defilers will try harder to plague units. Buildings have a lot of hit points and threaten to dominate the scoring. (Static defense buildings are treated the same as mobile units, though.) 2. Plague gets a bonus for carrier interceptors, to exploit the plague-on-interceptor behavior, but I didn’t see Steamhammer trying hard to plague XIMP’s interceptors (only the carriers themselves). I increased the bonus by a factor of 4.

zerg

• Scourge are in their own squad, the Scourge squad. They behave somewhat better in my tests, but it’s primitive and they still have a long way to go. I mentioned a couple other improvements to scourge behavior above. It was surprisingly difficult to get scourge to do anything sensible.

• Get an evolution chamber and a spore colony for air defense when needed even if still in book. Steamhammer formerly waited until the book line came to an end before it dared defend itself. I think this will be a net gain, though it will make mistakes sometimes.

• Tweak: Enemy dragoons and dark templar loom a little larger as reasons to make static defense.

• Fixed a bug in deciding to get defilers. Battlecruisers are an excellent reason to get defilers; valkyries, not so much.

• Strongly avoid spawning mutalisks versus large valkyrie counts. Valkyries in numbers pass through mutas like they’re hardly there.

openings

• Fixed a typo in the opening name Over10Hatch2SunkHard in the AntiZealot strategy combo. When this opening was selected, Steamhammer couldn’t find it and played its default 9 pool instead, a poor choice against mass zealots.

• Added the zerg opening AntiFactoryHydra, which may be better against SAIDA’s unit mix than Steamhammer's original AntiFactory, and the terran opening 10-10-10FD in a form close to that popularized by Flash. 10-10-10 is an opening stem that gets a super-fast factory, and 10-10-10 FD is a followup that continues into an attack with 2 tanks and 8 marines, which is strong against protoss that techs too hard or expands fast.

• I configured terran and protoss counters to Naked expand by protoss. That means configuring which openings are to be tried as counters to an expected enemy plan. 10-10-10FD should be a good counter to protoss Naked expand.

debug drawing

• In the game info display (drawn in the upper left of the screen when turned on), Steamhammer 2.0 added an overall score versus this opponent, shown next to the opponent name, “2-3” meaning 2 wins and 3 losses. Steamhammer 2.1 also adds a score for the chosen opening, drawn next to the opening name. The context makes it easier to interpret Steamhammer’s choices. The numbers are specific to the matchup. Randomhammer will show different numbers depending on what race it rolled.

• Squads have 2 settable flags, “fight visible only” (only include visible enemies in the combat sim, not all known enemies) and “meatgrinder” (be more aggressive, willing to accept high losses). Visible-only is used by the Recon squad, and meatgrinder tested poorly and is not used. If the squad info display is turned on, it draws cyan V and M left of the squad’s information line if the flags are turned on.

Steamhammer 2.1 progress

I have fixed the bugs affecting terran play, a bug affecting defilers, and a few bugs and weaknesses affecting all races. I also improved scourge control, and added a new opening to maintain my sanity. There is still a critical bug affecting protoss, which causes units to wander around without fighting, carrying banners “make levity not war.” Another severe weakness affects base defense, causing defenders to hang back from the action. I’ve spent the last 2 days trying to fix base defense, and it doesn’t work. I might have to think up a different solution.

Everything is good except the last 2 critical problems. Not that there’s any shortage of other weaknesses, but these 2 are so bad that they can’t be ignored. Surely they won’t resist me for long, though. Stand by!

Update the next day: I got everything working well enough, so I thought. I ran final tests and found... the newly implemented scourge micro had stopped working, though I hadn’t touched anything related. Now what has gone wrong?

various short items

SAIDA

SAIDA has been updated and is again defeating Krasi0 and Locutus. The arms race continues!

CIG 2018

I started poking at the detailed results file to figure out how to reproduce the official results exactly... then I discovered that the build order problem was wider than it first seemed. I canceled my plans. We don’t need per-map crosstables and race balance analysis of a tournament with such badly distorted results.

Steamhammer 2.1

I haven’t been working that hard on it, but I have made progress. I fixed some of the bugs introduced along with squad clustering, and found the causes of others. 2.1 should have smoother play in many cases. To say the same thing differently, Steamhammer 2.1 is suffering from feature creep, or at least bug fix creep. Hang on, it shouldn’t take too much longer.

CIG 2018 - what Steamhammer learned

I wrote a new script to analyze Steamhammer’s learning data. A couple points: 1. Steamhammer crashed in nearly half of its games in CIG 2018. It can’t save learning data after a crash, so against some opponents Steamhammer had few opportunities to experiment. The number of crashes varied strongly depending on the opponent. 2. Steamhammer was set to remember the previous 100 games, since I figure there’s no play advantage to remembering more. The tournament was 125 rounds long. So in the tables below, “100 games” means that Steamhammer played at least 100 games without crashing, and up to 25 games may have been dropped, the early games. Against some weak opponents, Steamhammer learned, within 25 games, how to win 100% of the remaining games, and those tables give a 100% win rate for remembered games. Steamhammer did not score 100% against any opponent overall; it always had some losses in early games.

I should be able to run the same analysis for Steamhammer forks which retain Steamhammer’s opponent model file format.

#1 Locutus

openinggameswins
2HatchHydraBust10%
3HatchHydraExpo20%
3HatchLingBust10%
3HatchLingExpo10%
4HatchBeforeGas10%
OverpoolSpeed956%
6 openings1533%

A mystery is solved. Why was Steamhammer’s crash rate higher than I expected? Because many opponents learned to make Steamhammer crash. A crash for the opponent is a win, and the bot doesn’t care how it wins, so if it can learn a plan that makes the opponent crash reliably, it will. The stronger opponents tend to be learning bots, so Steamhammer crashed more often on average against strong opponents. This also means that my glib conclusion that Steamhammer won 66% of non-crash games, so it seems to have kept up with general progress is not sound. The non-crash games were mostly against weak opponents.

Locutus was lucky that it could figure out how to break Steamhammer. As Bruce mentioned in a comment, this Locutus version had a bug when facing certain zergling timings, and Steamhammer quickly figured out how to exploit the bug. It’s possible that Steamhammer minus the crash would have upset Locutus.

#2 PurpleWave

openinggameswins
11Gas10PoolMuta10%
3HatchHydra30%
3HatchLurker10%
4PoolSoft10%
7Pool12Hatch10%
7PoolSoft10%
9Hatch8Pool10%
9HatchExpo9Pool9Gas10%
9PoolSpeed10%
AntiFactory10%
Over10Hatch60%
Over10Hatch1Sunk70%
Over10Hatch2Sunk180%
Over10HatchBust10%
Over10HatchSlowLings40%
OverhatchMuta10%
OverpoolHatch10%
OverpoolTurtle30%
ZvP_3HatchPoolHydra20%
ZvP_4HatchPoolHydra10%
ZvT_12PoolMuta10%
ZvZ_Overpool11Gas10%
22 openings580%

PurpleWave shut out Steamhammer. It didn’t learn to make Steamhammer crash because every game was a win for it anyway. Steamhammer desperately tried alternatives all over the map, including crazy all-ins and openings intended for ZvT and ZvZ, and nothing worked.

#3 McRave

openinggameswins
11Gas10PoolLurker10%
4HatchBeforeGas10%
9HatchExpo9Pool9Gas10%
9PoolSpeed5100%
ZvP_3HatchPoolHydra20%
5 openings1050%

#4 tscmoo

openinggameswins
9PoolExpo10%
9PoolHatch10%
9PoolSunkHatch10%
AntiFact_2Hatch10%
Over10Hatch2Sunk10%
OverhatchExpoLing1315%
OverpoolSpeed2223%
7 openings4018%

#5 ISAMind

openinggameswins
3HatchHydraExpo10%
4HatchBeforeGas10%
OverpoolSpeed4100%
ZvP_2HatchMuta70%
ZvP_3HatchPoolHydra60%
5 openings1921%

#6 Iron

openinggameswins
2HatchHydra10%
3HatchLingExpo20%
4PoolHard10%
6PoolSpeed10%
9Hatch8Pool10%
9HatchMain9Pool9Gas10%
9PoolSunkSpeed10%
AntiFact_13Pool40%
AntiFact_2Hatch8312%
AntiFactory10%
Over10Hatch10%
PurpleSwarmBuild10%
ZvP_2HatchMuta10%
ZvT_12PoolMuta10%
14 openings10010%

Iron is not a learning bot, so it did not learn to crash Steamhammer. Still, these results show a weakness in Steamhammer: Its best opening against Iron is AntiFactory, which it tried only once in these 100 games. Steamhammer did not explore enough. I tried to fix the weakness in Steamhammer 2.0.

#7 ZZZKBot

openinggameswins
11Gas10PoolMuta10%
8Pool729%
9HatchMain9Pool9Gas10%
9PoolSpeed10%
OverhatchMuta10%
Overpool+110%
OverpoolSpeed10%
ZvZ_12HatchMain20%
ZvZ_12Pool10%
ZvZ_12PoolLing4858%
ZvZ_Overgas9Pool20%
ZvZ_Overpool9Gas20%
12 openings6844%

#8 Microwave

openinggameswins
9PoolSunkHatch580%
9PoolSunkSpeed2767%
OverpoolSunk10%
OverpoolTurtle333%
ZvZ_12PoolLing10%
5 openings3762%

This looks like successful learning. Too bad Steamhammer only successfully played 37 of the 125 games.

#9 LetaBot

openinggameswins
11Gas10PoolLurker10%
2HatchLurkerAllIn40%
3HatchHydraExpo10%
3HatchLurker1338%
9HatchExpo9Pool9Gas4536%
OverpoolLurker1331%
ZvP_2HatchMuta10%
ZvT_12PoolMuta10%
ZvT_13Pool10%
ZvT_3HatchMuta10%
10 openings8131%

#10 MegaBot

openinggameswins
11Gas10PoolLurker10%
3HatchHydra10%
3HatchHydraExpo10%
3HatchLingExpo2143%
Over10Hatch10%
OverhatchExpoLing1100%
ZvP_3HatchPoolHydra20%
7 openings2836%

#11 UAlbertaBot

openinggameswins
3HatchLingExpo10%
5PoolHard2Player10%
9PoolExpo10%
9PoolSpeed10%
9PoolSunkHatch4633%
9PoolSunkSpeed2948%
Over10Hatch1Sunk20%
OverpoolSpeed10%
ZvZ_Overpool9Gas10%
9 openings8335%

#12 Tyr

openinggameswins
9PoolHatch5100%
ZvP_3HatchPoolHydra50%
2 openings1050%

#13 Ecgberht

openinggameswins
11Gas10PoolLurker1050%
2HatchLurker2361%
2HatchLurkerAllIn4475%
Over10HatchBust333%
OverpoolLurker875%
OverpoolSpeed333%
ZvT_13Pool10%
7 openings9265%

#14 Aiur

openinggameswins
11Gas10PoolLurker1100%
5PoolHard2Player1100%
9PoolSunkHatch1100%
9PoolSunkSpeed2100%
Over10Hatch10%
Over10Hatch1Sunk250%
Over10Hatch2Hard1100%
Over10HatchSlowLings1100%
OverpoolSpeed2100%
OverpoolTurtle367%
10 openings1580%

#15 TitanIron

openinggameswins
3HatchLingBust10%
AntiFact_13Pool650%
AntiFact_2Hatch10%
AntiFactory7442%
Over10Hatch2Sunk10%
OverhatchExpoMuta10%
OverpoolLurker10%
ZvZ_Overgas9Pool1421%
ZvZ_Overpool9Gas10%
9 openings10037%

This selection of openings implies that TitanIron plays a factory-first build against zerg, like Iron, and is a non-learning bot, like Iron. Later I’ll look into the source and find out for sure.

#16 Ziabot

openinggameswins
11Gas10PoolMuta425%
2.5HatchMuta10%
3HatchHydraBust10%
6PoolSpeed10%
8Pool771%
9Hatch8Pool10%
9PoolHatch450%
ZvP_2HatchTurtle10%
ZvZ_12Pool10%
ZvZ_12PoolMain1625%
ZvZ_Overpool11Gas1050%
ZvZ_Overpool9Gas5374%
12 openings10056%

Low win rates against Zia and some other opponents suggest to me that Steamhammer had other new weaknesses besides crashing. I think Steamhammer should score over 80% against Zia.

#18 Overkill

openinggameswins
11Gas10PoolMuta1090%
4PoolHard2396%
6PoolSpeed28100%
9Hatch8Pool10%
OverhatchLing250%
OverpoolSpeed1392%
ZvZ_12HatchExpo250%
ZvZ_12PoolMain10%
8 openings8091%

#19 TerranUAB

openinggameswins
2HatchLurker5290%
AntiFact_13Pool888%
AntiFact_2Hatch978%
AntiFactory3190%
4 openings10089%

#20 CUNYbot

openinggameswins
11Gas10PoolMuta978%
OverhatchLing3497%
ZvZ_12PoolLing2796%
ZvZ_Overgas9Pool10%
ZvZ_Overpool9Gas1989%
5 openings9092%

#21 OpprimoBot

openinggameswins
11Gas10PoolLurker367%
2HatchLurker250%
2HatchLurkerAllIn683%
6PoolSpeed19100%
OverpoolLurker10%
OverpoolSpeed580%
ZvT_12PoolMuta2095%
ZvT_3HatchMuta20100%
ZvT_3HatchMutaExpo24100%
9 openings10094%

#22 Sling

openinggameswins
4PoolHard475%
4PoolSoft6100%
5PoolHard2Player3100%
ZvZ_12HatchMain10%
ZvZ_Overgas9Pool10%
5 openings1580%

The selection of fast rush openings suggests that Sling played a macro strategy which was countered by fast rushes. But I don’t want to draw strong conclusions based on 15 non-crash games out of 125.

#23 SRbotOne

openinggameswins
11Gas10PoolLurker1493%
2HatchLurker1090%
2HatchLurkerAllIn1090%
3HatchLurker17100%
4PoolSoft17100%
5PoolHard7100%
9HatchExpo9Pool9Gas475%
9PoolLurker3100%
OverpoolLurker5100%
9 openings8795%

The wide range of lurker openings means that SRbotOne by Johan Kayser fought with mostly barracks units. Well, we already knew that.

#24 Bonjwa

openinggameswins
9PoolExpo6100%
9PoolSunkHatch5100%
9PoolSunkSpeed5100%
AntiFact_2Hatch3100%
AntiFactory5100%
ZvT_2HatchMuta1100%
6 openings25100%

#25 Stormbreaker

openinggameswins
11Gas10PoolMuta1100%
4PoolHard1100%
9PoolSunkHatch8100%
9PoolSunkSpeed8100%
OverhatchLing1100%
OverhatchMuta7100%
OverpoolSpeed1100%
OverpoolSunk7100%
ZvZ_12HatchExpo2100%
ZvZ_12HatchMain3100%
ZvZ_12PoolLing1100%
ZvZ_12PoolMain3100%
12 openings43100%

#26 Korean

openinggameswins
4PoolHard1100%
4PoolSoft3100%
5PoolHard5100%
5PoolHard2Player3100%
5PoolSoft1100%
6PoolSpeed6100%
OverhatchLing9100%
OverhatchMuta12100%
ZvZ_12HatchExpo13100%
ZvZ_12HatchMain16100%
ZvZ_12PoolLing14100%
ZvZ_12PoolMain17100%
12 openings100100%

#27 Salsa

openinggameswins
4PoolHard2100%
4PoolSoft4100%
5PoolHard7100%
5PoolHard2Player1100%
5PoolSoft1100%
6PoolSpeed8100%
OverhatchLing11100%
OverhatchMuta8100%
ZvZ_12HatchExpo12100%
ZvZ_12HatchMain20100%
ZvZ_12PoolLing13100%
ZvZ_12PoolMain12100%
ZvZ_Overgas9Pool1100%
13 openings100100%

overall

totalZvTZvPZvZZvR
openinggameswinsgameswinsgameswinsgameswinsgameswins
11Gas10PoolLurker3168% 2871% 333%
11Gas10PoolMuta2669% 10% 2572%
2.5HatchMuta10% 10%
2HatchHydra10% 10%
2HatchHydraBust10% 10%
2HatchLurker8782% 8782%
2HatchLurkerAllIn6473% 6473%
3HatchHydra40% 40%
3HatchHydraBust10% 10%
3HatchHydraExpo50% 10% 40%
3HatchLingBust20% 10% 10%
3HatchLingExpo2536% 20% 2241% 10%
3HatchLurker3171% 3073% 10%
4HatchBeforeGas30% 30%
4PoolHard3291% 10% 3194%
4PoolSoft3197% 17100% 10% 13100%
5PoolHard19100% 7100% 12100%
5PoolHard2Player989% 1100% 7100% 10%
5PoolSoft2100% 2100%
6PoolSpeed6397% 2095% 4398%
7Pool12Hatch10% 10%
7PoolSoft10% 10%
8Pool1450% 1450%
9Hatch8Pool40% 10% 10% 20%
9HatchExpo9Pool9Gas5137% 4939% 20%
9HatchMain9Pool9Gas20% 10% 10%
9PoolExpo875% 6100% 20%
9PoolHatch1070% 5100% 450% 10%
9PoolLurker3100% 3100%
9PoolSpeed862% 683% 10% 10%
9PoolSunkHatch6650% 5100% 1100% 1392% 4732%
9PoolSunkSpeed7265% 683% 2100% 3574% 2948%
AntiFact_13Pool1856% 1856%
AntiFact_2Hatch9721% 9621% 10%
AntiFactory11257% 11158% 10%
Over10Hatch90% 10% 80%
Over10Hatch1Sunk119% 911% 20%
Over10Hatch2Hard1100% 1100%
Over10Hatch2Sunk200% 10% 180% 10%
Over10HatchBust425% 333% 10%
Over10HatchSlowLings520% 520%
OverhatchExpoLing1421% 1100% 1315%
OverhatchExpoMuta10% 10%
OverhatchLing5796% 5796%
OverhatchMuta2993% 10% 2896%
Overpool+110% 10%
OverpoolHatch10% 10%
OverpoolLurker2854% 2854%
OverpoolSpeed6156% 862% 1573% 1587% 2322%
OverpoolSunk888% 888%
OverpoolTurtle933% 633% 333%
PurpleSwarmBuild10% 10%
ZvP_2HatchMuta90% 20% 70%
ZvP_2HatchTurtle10% 10%
ZvP_3HatchPoolHydra170% 170%
ZvP_4HatchPoolHydra10% 10%
ZvT_12PoolMuta2383% 2286% 10%
ZvT_13Pool20% 20%
ZvT_2HatchMuta1100% 1100%
ZvT_3HatchMuta2195% 2195%
ZvT_3HatchMutaExpo24100% 24100%
ZvZ_12HatchExpo2997% 2997%
ZvZ_12HatchMain4293% 4293%
ZvZ_12Pool20% 20%
ZvZ_12PoolLing10479% 10479%
ZvZ_12PoolMain4973% 4973%
ZvZ_Overgas9Pool1921% 1421% 520%
ZvZ_Overpool11Gas1145% 10% 1050%
ZvZ_Overpool9Gas7674% 10% 7476% 10%
total159664%68562%15526%63382%12329%
openings played6937363113

This summary table took me hours to get right, so I hope it's useful.

Steamhammer played 69 openings in 1596 non-crash games, which is around 2/3rds of the openings it knows. No single matchup had more than 37 different openings. There were far more games against terran and zerg than against protoss and random, partly due to the crashing pattern. Against the random opponents (Tscmoo and UAlbertaBot), it settled on mostly general-purpose openings, as you might expect. Its best matchup was ZvZ, with a Jaedong-like 82% win rate (and lately, Jaedong crashes half the time too, so they’re just alike).

Openings that were both popular and successful include 2HatchLurker and 2HatchLurkerAllIn versus terran, 6PoolSpeed with a 97% win rate against mostly weak opponents, 9PoolSunkSpeed used across all matchups, and ZvZ specialties OverhatchLing, ZvZ_12PoolLing, and ZvZ_Overpool9Gas. None of the opening choices surprises me, though some of the win rates do.

Steamhammer 2.1 status

My energy is recovering slowly from “blrgh, is it day again?” toward “I wonder what’s for lunch?”

I got a modest amount of work done for Steamhammer 2.1. I fixed 4 different bugs in terran play, and now terran is up to snuff—there was a good one where medics liked to break away and advance on their own. Steamhammer is better than before with barracks units, still klutzy with factory units though vultures may get stuck on each other less often. At least one protoss bug is not as easy and needs actual work to solve. I also feel like fixing scourge, so we’ll see how long it takes. Should be more on the order of days than weeks.

For Steamhammer 2.2, I think the headline feature will be dropping BWTA. That will be a relief. When it looks solid, I can move to BWAPI 4.2.0 and be free of the bugs in 4.1.2. The 4.1.2 bugs effectively make drop more expensive for zerg, which has discouraged me from working on drop skills.

Last year, the end-of-year Steamhammer version 1.4a3 (gotta love that version number) was not only the absolutely strongest Steamhammer of the year, it was also relatively strongest: It showed the best results against other bots. Steamhammer finished higher in SSCAIT than in AIIDE. I’m seeing early signs that it might work out the same this year. This year, the AIIDE version includes a lot of necessary work, but not all of it is polished enough. By the end of the year, the new bugs should be smoothed out and other important problems fixed. I’m expecting a strong chance that Steamhammer will again finish higher in SSCAIT than in AIIDE. I think I am being taught a lesson in good tournament preparation.

Still coming soon-ish: CIG 2018 analysis.

Steamhammer 2.0 download

Here is the Steamhammer 2.0 download link. It’s the same zip file I submitted for AIIDE 2018, so unlike an SSCAIT upload it doesn’t include BWAPI.

Steamhammer 2.0 download with source and binary.

It is meant to play zerg only. The configuration file contains nothing for terran or protoss.

You can fill in openings yourself and it will play, but my testing shows unacceptable bugs for both terran and protoss. For example, vultures often get stuck on targets as if married to them, unable to switch away until one or the other dies (this bug allows no divorce for any cause). In zealots versus zerglings, the zealots like to move back and forth and give the zerglings free hits. “It’s only fair, we’re so much taller and stronger.”

Steamhammer 2.1 will come out when the bot again plays all races acceptably. I’m not sure how long it will take. After the big effort for AIIDE, my energy is low and I need a break. I haven’t even updated Steamhammer’s web page yet.

Steamhammer 2.0 change list

Some parts of the change list are already posted; think of those posts as part of this one (ahem, “included here by reference are....”). Here is the rest. You may notice that it is slightly long.

code changes

• More stuff in UnitUtil: Cooldown and FramesToReachAttackRange() functions added, and used in micro. GetWeapon() functions reworked for simplicity. Damage-per-frame functions added to compare weapon strengths. IsCompletedResourceDepot() added, factoring out code that was repeated in several places.

UnitInfo::estimateHealth() estimates the health of a unit which may not been seen for a while, accounting for protoss shield regeneration and zerg hp regeneration. (Terran medic healing and SCV repair are not easy to predict.)

InformationManager::enemyHasSiegeMode() added, and used in tactical calculations.

• In GameCommander, I sorted the manager calls so that managers which gather information are called first, and managers which use the information are called later. They had gotten jumbled over time. The main effect is that Steamhammer reacts 1 frame faster after discovering the race of a random opponent, a crucial difference that I estimate will, over Steamhammer’s lifetime, save approximately zero games.

• I renamed SquadData::addSquad() to createSquad(), since that’s what it does, and reworked it for simplicity. I removed the declaration of SquadData::clearSquad(), which was not implemented.

• Some calls in WorkerManager iterate through bases instead of through units to find base-related information. It’s faster and simpler (but I did have to spend time to fix a bug that I introduced in the process).

• More unnecessary includes removed, bringing a negligible improvement in compile times.

• I removed the configuration option Config::Micro::UnitNearEnemyRadius. The value is now chosen dynamically in code.

• In the game info display (turned on with Config::Debug::DrawGameInfo and drawn in the upper left), most labels were not needed because the meaning is obvious. I removed the labels of items other than “Opp Plan”. Less clutter is better.

• The TimerManager display, turned on with Config::Debug::DrawModuleTimers, had grown disorganized and probably incorrect. I straightened it out. I also improved comments in the code to prevent future disorganization.

opponent model

The opponent model has always distinguished between opponents that appear to follow the same plan every game, and opponents that vary their play. Until this version, it used the information only in a minor way. Now it selects openings using an entirely different method for multi-strategy enemies. If you play the same every game, Steamhammer will try to find the best single response, exploiting your predictability. If you mix up your play to confuse Steamhammer, then Steamhammer will mix up its play to confuse you; you get minimal predictability to exploit. We’ll see how well it works, but I’m expecting it to make a big difference in a long tournament like AIIDE.

• Against a single-strategy opponent, Steamhammer sticks with the variant of epsilon-greedy that it has always used: With probability epsilon, explore randomly; otherwise, choose the best known opening according to a weighted win rate that tries to take the maps into account. It’s not strictly classic epsilon-greedy, though, because epsilon varies according to the loss rate: If we are losing a lot, explore more often and play the best known opening less often. (It’s an adaptation to having more openings available than can be tried.) I have modified it so that the exploration rate increases more rapidly with the loss rate, because I found it was too often repeating an opening that won 1 game out of many, instead of looking for a better choice.

• Against a multi-strategy opponent, Steamhammer starts with the same weighted-win-rate calculation that it uses in the single-strategy case. Each opening it has already played is an option, and has a measured win rate. Exploring a new opening is an option, and its win rate is the mean win rate of openings that have been tried, its best estimate of how likely a newly explored opening is to win—but with a hard floor, so that the exploration rate never goes too close to zero. It randomly chooses among the possibilities, giving each a probability proportional to the square of its win rate. Squaring the rates gives openings with win rates near zero little chance of being chosen—unless most openings have win rates near zero. If all win rates are zero, because there are no wins yet, the hard floor on exploration means that Steamhammer explores every time. If the win rates are high for some openings and low for many others, exploration will be rare and Steamhammer will most often randomly choose one of the better openings. It’s ad hoc but makes a certain amount of sense.

macro

• Mineral locking. Steamhammer’s implementation follows Locutus in outline, but is different in detail. Mineral locking helps mainly in macro games, which Steamhammer is now able to play better because of the squad changes, so this was an opportune time to add it.

construction

• Prefer to expand to bases near the edge of the map. Bases near the edge are usually (not always) more protected than bases near the center of the map. In practice, Steamhammer now mostly avoids taking the risky center bases on Heartbreak Ridge and other maps, and the exposed mineral only bases on Python, at least until later in the game. I had to tune it carefully so that the natural of the 1 o’clock base on Tau Cross, far from the edge, is still preferred over the exposed 3rd base at the edge. Someday I’ll implement map analysis and figure out a real measure of exposure to attack.

• Bug fix: Don’t try to build at a location which a worker cannot reach. It never happened, as far as I know, but there was a mistake in the code.

tactics

• In the overview I said that workers are not transferred to base that is in danger, but there is more to it than that. Each base keeps track of whether it is being attacked severely enough that workers appear to be in danger; the estimate is made by CombatCommander::updateBaseDefenseSquads(), which I wrote about under base defense, and can be accessed via the Base objects for each base with base->inWorkerDanger(). If a worker is idle, meaning it is due to be assigned a new task if one is available, then it is not assigned a task at a base where workers are in danger. A worker is normally made idle after completing any task: worker was just created, gas collection is being turned off so worker no longer needs to mine gas, worker is finished defending itself and should be put back to work, and other cases. Workers are not only not transferred to an endangered base, they are often (not always) transferred away from the endangered base because they had to defend themselves, or were pulled for defense, or otherwise changed tasks. It’s hardly perfect, but it saves workers and greatly improves Steamhammer’s resilience to attack. It was a critical improvement. Related weaknesses remain: Steamhammer may still try to build at the endangered base, or transfer drones to a distant base through the enemy army.

• Fixed CombatCommander bugs in deciding which enemy base to attack.

• Rules for recognizing enemy cloaking and assigning detectors to our squads are slightly improved. Steamhammer pays attention to whether it has cloaked units itself and needs to catch enemy observers. This allows overlords to stay safer in some game situations: We don’t have lurkers, therefore we don’t have a strong need to hunt observers, therefore overlords can stay home.

• In feeding units to the combat sim, an enemy building which was last seen uncompleted is entered as completed if is currently out of sight. It is sometimes an improvement, sometimes a mistake. It would be better to track the estimated completion time and use that (a number of bots do).

micro

• Previous versions changed former stateless module Micro into an object with state, but did nothing new. This version updates the state with each of our unit’s orders and a little more information, but still doesn’t use the state for anything. It’s all prepared for serious work, though.

• Enemy unit movement prediction is smarter. It takes distance into account. Also, prediction is used differently in different cases to get better results in practical situations. Mutalisks, wraiths, and vultures now use prediction; as instant-acceleration units they are kited by a different routine than other units, which didn’t use prediction until now.

• Kite only units which the enemy has targeted. If nobody wants to shoot you, you don’t have to step back from the shooting. This especially helps hydralisks, which fire more slowly when kited and tend to get in each other’s way.

• Some bits of micro explicitly take latency into account in their calculations, especially kiting. It’s more accurate.

• Don’t chase an enemy if we’re predicted to be unable to catch it. CanCatchUnit() (defined in Common.cpp) figures it out. It makes less difference than I expected.

• Targeting priority: A ghost which is nuking is the highest priority target. An enemy defiler is also a high priority. These two were oversights. There are other targeting tweaks, for example to reduce cases of attacking the pylon when the cannon behind it is firing; it’s not fully successful.

zerg

• If we are short of mutas or lurkers (by a simple hardcoded count), then do not substitute a drone for a muta or lurker, no matter how much we may want drones. This was the biggest cause of delayed tech switches, and fixing it makes strategic play crisper at key times. This was one of the most important fixes in version 2.0.

• Late in the game, add extractors willy-nilly everywhere that they are possible. Steamhammer was too often gas-starved in the late game, too slow to get more gas when it was needed. This is also an important fix.

• Limit scourge more stringently. Sometimes Steamhammer makes so much scourge that it has no gas for anything else, causing macro problems as it delays production to get more gas.

• The building manager is much more cautious about turning a failed expansion into a macro hatchery. It only orders the change if it appears that we actually need a macro hatchery.

• Build a queen’s nest sooner in some situations. This is to speed hive tech when it is needed. It doesn’t make a big difference.

• If the enemy has too many corsairs or valkyries, get air carapace. This gets air armor for overlords even if we are not making any other air units.

• Favor guardians more, especially versus mass cannons. Past Steamhammer versions reduced guardian use by too much, and this starts to correct it.

• Emergency reaction: If we’re dangerously short on drones, don’t spend one on a building. Oops.

• Emergency reaction: If we have no bases but do have hatcheries, then make sure that the drone limit is at least 3. Having “no bases” means that no hatchery is at a predefined base location; we might still have hatcheries that can mine. Steamhammer formerly thought that, without bases, it had no need for drones. That was OK if it had drones already, not if they were all dead. Now Steamhammer has a chance to recover, provided the enemy is also prostrate after a base trade.

• Don’t automatically make a sunken in reaction to a proxy. It was often an overreaction.

• Don’t automatically get an early sunken versus protoss 2 gate (the sunken was usually too early) or against zerg 2 hatch (it was often unnecessary).

• When planning a morphed unit type (such as a lurker), don’t count it as using up a larva. This minor bookkeeping fix should occasionally make for better production decisions.

• Cancel grossly excess overlords even in the opening book. This may help if an emergency situation comes up in the opening, but it is mainly meant to mitigate bugs which cause production loops. No simple production loops are possible, but there seem to still be some complex loops where unrelated emergency reactions fire, and each prevents the other from recognizing that it has already taken action. It’s rare, though.

• Don’t let rebuilding the spawning pool cause a production jam, and don’t allow multiple copies of the spawning pool. It was a rare but deadly bug in production unjamming.

• Fixed a crash if a hydralisk den, lair, or spire was dropped in the opening (in reaction to an emergency). It was that specific.

• Fixed a rare bug that could prevent gas from being retaken after it was lost.

• Fixed a bug in defensive reactions that could request zerglings when there was no spawning pool.

• Fixed an unimportant bug in deciding to make a hive. It had no real consequences.

zerg openings

• Fixed a number of openings that had suffered bit decay: They were broken or mistuned due to code changes, such as queue reordering and mineral locking.

• Added new turtle openings designed to exploit particular enemy strategies: 11HatchTurtleHydra, 11HatchTurtleLurker, 12HatchTurtle, ZvZ_OverpoolTurtle. These are meant to stop specific rushes and leave Steamhammer in a sound position.

• Finished up and optimized the anti-forge-expand macro openings ZvP_3BaseSpire+Den (a good success) and 4HatchBeforeGas (not as effective). Steamhammer is finally able to play macro games well, so this was important. To play these openings truly well, though, Steamhammer needs greater ability to understand and react to the enemy’s timings.

• I fiddled with opening probabilities, mainly to continue to make openings more equally likely so that the opponent model can explore more efficiently. But also to include the new openings and to adjust to Steamhammer’s new strengths and weaknesses.

• I split the opening 9PoolSpeed into 2 variants. One variant keeps the same name and makes fewer zerglings (hit them by surprise, then transition to a normal game), the other is called 9PoolSpeedAllIn and makes more zerglings (hit them hard and maintain pressure). Both are more effective in their ways than the former compromise opening.

• A few ZvZ openings make 1 drone fewer, to keep zergling numbers as high as possible.

• Some other changes.

Steamhammer 2.0 squad unit clustering

Squad unit clustering is the Steamhammer 2.0 change with the biggest effect on play. It was also the change that took the most effort to get working well, because it adds flexibility, which means more ways to go wrong.

Many bots form squads dynamically by clustering: Each cluster is a squad. Steamhammer forms squads as usual, and clusters the units in each squad into groups which act somewhat independently. The two arrangements are not necessarily different in effect; what matters is how decisions are made. Steamhammer’s system is meant to keep a clean distinction between levels of abstraction, the operational level at which squads are formed and given orders, and the tactical level at which units are maneuvered to carry out the orders. Each cluster in the squad makes decisions based on its local situation, but it is ultimately trying to carry out the same order as the other clusters in the squad.

Clustering is driven by a simple imperative: Units must react to their local environment. In the unified squad structure that Steamhammer inherited from UAlbertaBot, the squad runs a single combat simulation for front-line units which are in contact with the enemy, and the entire squad is told to advance or retreat based on the result. Units which are away from the front lines, but in contact with the enemy, are given nonsensical orders as often as not. For example, if the front line is advancing because the enemy army is away from home, then small groups of reinforcing units which run into the enemy army are also told to attack, and they end up dying. And conversely, if the front line is afraid to attack, then units behind the scenes which meet lone enemies are also afraid of them. Units must react to the situation they are in, not the situation some other unit is in.

With clustered squad units, each cluster that comes into contact with the enemy runs its own combat simulation, and advances or retreats independently depending on the result. When the army is large, the squad members tend to be spread over a wide area, and independent behavior is a necessity. The full set of cluster behaviors is complex; keep reading.

the clustering algorithm

The clustering algorithm itself is implemented in OpsBoss (intended to eventually replace CombatCommander), which is probably not the right place for it. Methods cluster either a given set of units (like the members of a squad) or all units of a player. The feature to cluster all units is intended for clustering enemy units, and not currently used, but I expect it will be valuable for deeper tactical analysis when I get that far.

A cluster is either an air cluster or a ground cluster. Air units and ground units have different movement possibilities—different decisions available—so they should be treated differently. Only an air cluster can retreat over a cliff.

Steamhammer makes circular clusters. I expect that rectangular clusters are as good, and probably a tad cheaper to calculate, but also a tad more complex. Pick an arbitrary unit as the seed of a cluster, find nearby units, calculate the center and radius of the cluster so far, and expand the radius by a fixed amount to see if that draws in any more units. If so, recalculate the center and radius, and so on; if not, the cluster is complete. Repeat until all units are in clusters. A cluster of size 1 is fine.

clustering in squads

Each squad reclusters its units every frame. That means that clusters have no continuity; there is no such thing as “the same cluster” the next frame. It’s a limitation. Some units, like overlords and defilers, are left out of clusters and handled separately. To save time, not every cluster makes decisions on every frame, especially in the late game when there may be many clusters. See Squad::update() for all this stuff.

The clusters then make decisions independently. Each is trying to reach the squad’s order position, and decides what to do based on its local situation. The clusters know that they are working together, so if they see a way, they will try to join up into larger clusters. If you turn on Config::Debug::DrawClusters in the configuration file (it is currently turned on for the SSCAIT stream), you’ll see (among other things) a status string for each cluster: Join Up, Advance, Attack, Retreat, and so on. The decisions work like this:

• If there is no enemy nearby that the cluster can attack, or that can attack the cluster, then the cluster is in a “no fight” situation—combat is impossible for the moment.

• If a “no fight” cluster finds itself in the vanguard, its status string is “Advance” and it moves toward the squad’s order position.

• If a “no fight” cluster is behind other clusters, its status string is “Join Up” and it tries to merge with a cluster that is ahead of it. If the cluster ahead is advancing, they will form a train; if the cluster ahead is stopped or in combat, the trailing cluster may be able to join it.

• Other clusters have to decide whether to attack or retreat (aka regroup). First, the code checks several shortcuts to see if combat sim can be skipped.

• If Steamhammer is near max supply, the status string is “Banzai!” and the decision is to attack..Every cluster of every squad with an attack order will try to get into the fight.

• If the cluster is near a static defense building that can help in the fight, the decision is to attack. There are a couple of different cases, which get different strings mentioning static defense. The behavior is not as good as it could be (most zerg units should move behind the static defense before turning around to fight, instead of standing in front), but it’s an improvement over past versions.

• If the cluster has retreated as far as it can, back into its base which is now under attack, the decision is to attack and the string is “Back to the wall”.

• If none of those checks fires, there is nothing for it but to run the combat sim. Depending on the result, the status string will be “Attack” or “Retreat”. On the enemy side, all the nearby enemies are added to the combat sim, as usual. On the friendly side, only the cluster’s own units are added; clusters assume that they are unable to cooperate. This works better than adding all nearby friendly units, because in fact different friendly units often do not cooperate. The downside is that clusters cannot cooperate when they should, for example to carry out a sandwich maneuver. A better system would be to identify top-down which clusters have the same enemies in their sights, and run one combat sim for all those clusters. I expect to do that at some point after I turn on enemy unit clustering.

• If the decision is to retreat, where should the cluster retreat to? There are several rules for this, checked in Squad::calcRegroupPosition(). I have said that Steamhammer’s old tactical misbehaviors are gone, but it’s not true: Clusters sometimes still try to retreat through the enemy force. There is plenty of room to improve retreating. At some point after I turn on enemy unit clustering, I’ll teach the retreat calculation more.

• Retreating: If there is nearby static defense in any direction, retreat toward it.

• Retreating: If part of the cluster is in range of the enemy (so we did a combat sim) and part is out of range (so it is a safe place to retreat to), retreat to the position of the cluster unit out of enemy range which is closest to the squad’s order position. This is a cluster variant of the classic UAlbertaBot retreat behavior. Restricting it to one cluster at a time makes it behave much more nicely—no more retreating to a random position because some reinforcing unit happens to be approaching from an unexpected angle.

• Retreating: Look for another cluster nearby to join up with. Favor nearby clusters that are closer to the order position and clusters which are attacking. It’s good in general for clusters to join up, but this rule also tries to fix a specific weakness: If a small cluster does its combat sim with its few units, it may be told to retreat, even though a large cluster in front of it has done its combat sim and decided to attack. It is much better for the small cluster to join the large one in its attack, so in this case Steamhammer tries to merge the clusters, or in other words, it retreats toward the enemy. It doesn’t always work; cases still occur of small clusters which are needlessly fearful.

• Retreating: If all else fails, retreat toward the main base.

other details

The call Squad::unitNearEnemy() decides whether a unit is “in range” of the enemy. In the past, Steamhammer often did not retreat far enough for safety, especially if the enemy had sieged tanks. I improved it in 2 ways:

• It uses the information manager’s records of all enemy units last known positions to decide whether an enemy is near, instead of using the MapGrid information about visible enemies only. Having to see the enemy to know to stay out of its firing range was especially bad for zerglings, which have a short sight range. It was also bad against sieged tanks, which can hit from out of sight range.

• If the enemy is known to have tanks with siege mode, then ground units make sure they stay outside of sieged tank range. Before, the assumed safe retreat distance was simply not far enough to be safe from tanks! It was painful to see a squad retreat to just inside siege range, lose the frontmost units to tank fire, and—move forward to stay centered on the retreat point. Ouch!

I made the minimum changes to Squad to get all this to work. The code is getting increasingly messy with special cases. For example, the micro managers which handle clustered units have to be told about the cluster and do a set intersection to figure out which units they should issue commands to, and the micro managers that handle unclustered units do not—squad code and micro code have to be coordinated, making refactoring more difficult. I will eventually rewrite the squads with a new and cleaner design, but probably not this year.

overall

This was a needed change. Units simply must pay attention to their own situations, there is no way around it.

Play versus protoss is vastly stronger. Voters have been feeding Steamhammer a lot of games against top protoss bots, which zerg mostly loses. Even in these losing games, it is easy to see that Steamhammer is putting up a much tougher fight than it used to. Since my home tests against DaQin, which Steamhammer learned to defeat, DaQin has been updated to be more aggressive and Steamhammer can no longer win (and I don’t know what version was entered into AIIDE, so we’ll see how the tournament goes). I can see the path to stronger zerg play, to earning wins over Locutus and PurpleWave. I can tell what needs to be done and I have confidence that it will succeed.

Play versus terran varies, and play versus zerg is weaker because of poor zergling behavior. A large part of the poor zergling behavior is due to clustering changes. In the past, when Steamhammer retreated a squad, it would not rerun the combat sim and consider attacking again until a time limit had passed (I changed the details thoroughly, but the behavior was inherited from UAlbertaBot). Since clusters do not persist from one frame to the next, it was impossible to retain this feature. The result is more indecision, and the indecision strongly affects zergling play, and causes other harm as well. It’s not easy to fix, and I’m still thinking about ways.

Part of the weakness is in retreating from a superior force that then advances. Not all of the enemy force is in sight range, and the rest is assumed to be still in its last-seen positions, so the combat sim says “ha, we can turn around and fight now!” With no retreat time limit, and the short sight range of zerglings, this happens fast and causes serious losses. The weakness was always there, and now it is worse.

Next: The big change list with everything else.

Steamhammer 2.0 base defense

I rewrote important parts of base defense. I fixed minor bugs in passing, but I had 2 main reasons: 1. Squad unit clustering caused bad defensive behaviors that had to be fixed. 2. The original base defense, as inherited from UAlbertaBot, was actually region defense. It iterated through regions of the map, and defended any region where the bot owned buildings. On some maps, one region can contain more than one base. Examples are the mineral-only bases on Python which are all in one big center region, and the center bases on Fortress which are laid out similarly. Base defense needed changes to defend these bases successfully.

• Iterate through bases, not regions, to check for areas that need defense. This means that buildings built outside any base area are no longer defended—not a serious loss, they were rarely defended well in the first place. See CombatCommander::updateBaseDefenseSquads(). The squads created to defend bases are called Base squads.

• A base is deemed to be in need of defense when an enemy unit (other than a single worker scout) is within a specified baseDefenseRadius distance of the base, OR if it is in the same region as the base and is within baseDefenseRadius + 300. The base region may be very large (and may contain multiple bases), in which case we don’t want to panic and send defenders when they aren’t needed. Or the base region may be very small, so that attackers outside the region can hit the base, a historical problem for Steamhammer. This condition covers both cases.

• A base is considered to be no longer under attack if there are no enemy units meeting the same criterion, except that the radius is larger by baseDefenseHysteresis. The hysteresis reduces indecisiveness. The numbers baseDefenseRadius and baseDefenseHysteresis are constants defined at the top of CombatCommander::updateBaseDefenseSquads(); at some point I may move them to the configuration file.

• Steamhammer used to ignore overlords, observers, and floating terran buildings in deciding whether the base needs defense. Now it counts them, and will send anti-air units if needed and available. It will also assign a detector if needed to target the observer. Thou Shalt Not Scout For Free.

• A Base squad is disbanded and the squad data structure destroyed when the squad is no longer needed. The squads used to be kept around even when empty. Dropping the squad mainly makes the debug display easier to understand.

• The Base squad’s order is centered on the enemy unit which is closest to the base location (the upper left corner of the command center, nexus, or hatchery). This guarantees that the Base squad won’t sit idle in the middle of the base while the enemy rampages on the outskirts.

• Release defending units that can’t attack any of the remaining intruders. For example, if the enemy shows up with both air and ground units, we might assign both zerglings and mutalisks for defense. If the enemy ground units are destroyed or leave and only air units remain, the zerglings become useless for defense and are released. The useless zerglings used to remain in the Base squad until the whole squad was released.

• Don’t double-count the same unit as both a ground and an air defender. Steamhammer used to think, “I have 4 hydralisks to drive off these corsairs, and I have the same 4 hydralisks to stop these 2 zealots. I have enough defenders!” The calculation to avoid double-counting is kind of involved.

• Fixed a bug introduced in a recent version which could overassign defenders. It would, for example, always assign at least 2 anti-ground defenders when under air attack.

pulling workers

Deciding whether to pull workers for defense—to place them in a Base squad—is also in this code. Pulling workers is sometimes necessary, but it has to be strictly regulated because it puts workers in danger. (Worker self-defense doesn’t involve putting them into a Base squad, and is not handled here.) I tried to fix the biggest weaknesses.

• Pull workers that are within a smaller radius: 18 tiles instead of 24. This is about the location of the worker. That should mostly prevent Steamhammer from pulling workers from another base to defend this one.

• Pull workers only when the enemy is very close to the mineral line. This is about the location of the enemy. Steamhammer used to pull workers to meet the enemy too far away from the mineral line, wasting time and putting workers in unnecessary danger.

• Release pulled workers much sooner. Steamhammer used to retain pulled workers in the Base squad until the squad was disbanded. Now it releases the workers when the “must pull workers!” condition is not satisfied.

Next: Squad unit clustering.

Steamhammer-Bereaver game with defiler

The game Steamhammer-Bereaver is a good example of Steamhammer’s defiler skills, both the good and bad points. Steamhammer gained an early advantage and contained Bereaver to its main, so the outcome of the game was not in doubt, hive tech or not. Bereaver mounted a strong defense at its ramp and held on for a long time. A timid zerg might have feared to attack and lost on points when the game time ran out—but of course Steamhammer is not timid.

The defiler dithered for a long time. Consume research finished at about 15:45 into the game, and the defiler filled up on energy within 15 seconds after, so that part was OK. A first attempt to break up the ramp was repelled with storm; the defiler was too far back and unable to help, due to lacking squad coordination. The second attempt to break up the ramp was at 18:20, and this time the defiler was in range. That’s about 2 and a half minutes from when the defiler was ready to act until it finally did; it had plenty of time in between to swarm or plague. It would have been worth it to sacrifice the defiler to plague the defenders.

swarm on the ramp

Excellent swarm placement! The defiler had energy to cast a second swarm farther into the enemy base, but did not. Even so, the one swarm nullified the dragoons and cannons and ensured that the attack would succeed if pressed. Thanks to my modifications, FAP understood that it would succeed and Steamhammer did press until it broke through. The attack had to be under way before the defiler could support it; Steamhammer has no ability to swarm (or plan to swarm) in advance of an attack. Steamhammer attacks when maxed, so in most winning games an eventual attack is guaranteed. When the swarm does come, it is generally well-positioned for where the units are at the moment, rather than where they are going or where they want to be.

The defiler seemed to get confused and did not contribute again until the very end, when it laid down a perfectly-placed plague over a few protoss buildings that were about to be destroyed anyway. The laser-precise plague hit as many protoss buildings as possible while missing zerg units. It’s impressive in a way, and it may even have shortened the game... by a fraction of a second.

Still next: Base defense.

Steamhammer 2.0 defilers

Defilers are complicated to use. I implemented a pile of features to get them to work acceptably, and I suspect that a bug has crept in since they don’t seem to work as well as when I first finished the implementation. They don’t swarm or plague as often as they used to. A likely source of the bug is the time control work.

The first step is to get defiler tech. The strategy boss decides when to get defilers. Currently, it delays defilers until fairly late versus terran that has a high ratio of tanks and/or vultures in its force, especially with spider mines, and otherwise uses the same criteria for all races: Do I have a hive, enough drones, and a few more items? When the defiler mound finishes, the strategy boss eagerly orders consume research. It is lazier about ordering plague, and later metasynaptic node (+50 energy). According to conventional wisdom, the energy upgrade is useful for defilers because then a full-energy defiler can swarm once and plague once before it has to consume again.

The strategy boss currently orders the production of 1 defiler at a time. A second defiler is not made unless the first one is lost. The defiler is sent toward the front in the hope that it will find something useful to do there.

consume

The consume implementation is on 3 levels. Strategy: If there are not enough zerglings on the field for defilers to consume, because the unit mix calls for other units, then the strategy boss orders up a few more. It makes sure that there exist at least 4 zerglings for each defiler. Tactics: A small number of zerglings are assigned to the MicroDefilers unit controller alongside any defilers. The number assigned depends on how much energy the defilers need; see Squad::addUnitsToMicroManagers(). The controller orders the zerglings to catch up to and stay near the defilers; each seeks the closest hungry defiler. Micro: If a defiler is hungry and finds an assigned zergling standing by, it’s lunch time.

A defiler counts as “hungry” if it has less than 150 energy. Defilers don’t consume anything other than zerglings which have been assigned for consumption. It’s not urgent, but it would be nice if they could consume irradiated units, or any units nearby that are destined to die. In an emergency, they should be willing to consume overlords. In the very late game, when minerals are gone and gas is plentiful, it may be more efficient to consume scourge.

plague

Plague is a spell of opportunity. If there is a big ball of enemies that aren’t already plagued and have a lot of hit points to lose, it virtually always pays to plague them if you can. Steamhammer is not smart enough to intentionally seek out good opportunities, but it is smart enough to recognize opportunities that arise.

So defilers keep their eyes open. If a defiler passes a cheap check (I have plague researched, I have enough energy, there are a bunch of enemies nearby) then it performs an expensive check to decide whether and where to cast plague. It draws a square of each place it can reach without moving far, and does a raster scan through the square, scoring each possible plague it might cast. For enemy units, it adds up the hit points the enemy will lose, counting it as 0 if the enemy is already plagued and adjusting for a few special cases: Buildings other than static defense get a discount, they are less important to plague, while a bonus goes to cloaked units (which are revealed by plague) and carrier interceptors (which will get stuck in the carrier until plague wears off, as the carrier tries to repair them). It also subtracts plague on friendly units, so that it is willing to plague itself if it covers enough enemies too. If the best score passes a threshold, cast the plague there.

Death rule: If the defiler thinks it is about to die, then plaguing any enemy is good enough. Theoretically, in this case Steamhammer might plague 1 stray probe that happens to be close enough.

This exhaustive search method is startlingly accurate at deciding where to plague (though I think I should increase the discount for buildings). I’m sure there are computationally cheaper ways to get good results.

dark swarm

Dark swarm is way more difficult to use well than plague. Swarm use ought to be part of a coordinated plan. A simple plan might be: Start the attacking units moving, then cast swarm around the time the attackers come into cannon range. The decision to attack should be informed by the intention to cast swarm during the attack—with enough swarms, one zergling can be the Klingon running man and kill all the marines. You need different plans for assaulting a fixed position, fighting mobile enemies that can evade swarm, or warding off an attack on your base. You have to take into account what units on both sides are able to do damage under swarm.

Steamhammer can’t plan like that. Those skills are far in the future. All zerg bots are weak with swarm.

Steamhammer chooses where to swarm with an exhaustive search similar to the plague search, and it is not as effective. First, the quick check only allows swarm over enemy buildings; Steamhammer can use swarm to attack, and not to maneuver or to defend, a major limitation. Protect the army in the middle of the map from air attack? No can do, boss: Besides the defiler skill, that would require more smarts in unit control. In the exhaustive search, it scores the units that end up under dark swarm, trying to cover friendly units that can hit under swarm and enemy units that can’t. It’s not the score you want; it ought to take into account nearby units that will want to move into the swarm, or will be unable to hit swarmed units from outside, or will have to suddenly flee.

Death rule: If the defiler is about to die, it will swarm wherever it thinks best, even if it doesn’t cover an enemy building. If the defiler doesn’t have any better idea, it will cast swarm over itself, which may save it depending on the situation. If the dying defiler could either swarm or plague, the choice depends on which happens to be checked first.

I implemented consume, plague, and swarm as micro skills, decided at the level where the code is controlling a single defiler. It makes sense for consume and plague. I think swarm should be decided at the squad level, because its use depends on the tactical situation and the squad’s goals. That will require a lot more cleverness in the squad, though.

combat simulation and micro

I modified the combat simulator FAP with a rough understanding of dark swarm. FAP performs a loose approximation of combat, and the dark swarm knowledge I added is equally loose. If a unit is under dark swarm at the start of the simulation, it is assumed to remain under dark swarm throughout, no matter how it may move around. (Movement ignores terrain and other units too, so FAP is already loose that way.) It understands which units can do damage under swarm, and has simulated units seek out only targets that they can damage.

All this happens only if dark swarm is already cast. There is no provision for planning ahead, “when the units start shooting, I’ll cast swarm here.” In other words, dark swarm influences the combat sim, but the combat sim does not influence dark swarm; Steamhammer doesn’t extract the full value. See the discussion above about coordinated plans.

Steamhammer also understands dark swarm at the unit micro level. Melee units seek out targets under dark swarm, on the theory that then they will be protected under swarm too (“ha ha, you’re under swarm, I’m perfectly safe... I hope?”). Ranged units skip targets under swarm that they can’t hit. The ranged unit controller understands which ranged units can do damage under dark swarm.

There is room for more smarts in exploiting dark swarm at the tactical level. Units under air attack, for example, or facing marines, should move into swarm for their own protection, and mostly they don’t. I’ve seen Steamhammer make serious mistakes because of that ignorance.

time control

My first implementation made 2 defilers at once and performed all the computation steps in the same frame. A disadvantage was that sometimes the 2 defilers would swarm the same place at the same time (scoring ensures that if they swarm at different times, they swarm different places). A bigger disadvantage is that it was too slow, with some frames taking over 150ms. I changed it to make only 1 defiler at a time, and arranged that consume, plague, and dark swarm are examined in different frames. That made it fast enough. There are ways to speed up the calculations, but slicing them apart seemed easier.

Overall, the defiler system is not industrial strength, but it’s a strong start. As I mentioned at the start, I suspect a bug due to the time controls. Steamhammer implements all the basic skills, which if you go through the above text you can estimate for yourself required 1.5 zillion different software features. Now that the pieces are in place, they can be improved one by one.

One of the emergent properties of the defiler system is that it is unpredictable. The defiler may plague this and then plague that, or swarm here and then swarm there—it gives the impression of running in streaks. And I can’t judge ahead of time what it will do, it surprises me.

Next: Base defense.

Steamhammer 2.0 uploaded

Steamhammer 2.0 is uploaded at SSCAIT. As I have mentioned, it is zerg only; Randomhammer is not updated. The only difference from the AIIDE 2018 version is that I turned on a few debug options, notably the new option to draw unit clusters.

I erased the learning data, so Steamhammer 2.0 is figuring out its opponents from scratch. It’s necessary since this version has different strengths and weaknesses. I expect its elo to plummet until it gets to know the different kinds of rushbot (just like the last time I erased the learning data).

Steamhammer 2.0 overview

Today I list the big changes in Steamhammer 2.0 without going into detail. There are tons of smaller changes. Details will follow.

The most effective changes:

  • squad units are clustered, and each cluster makes attack/retreat decisions independently
  • mutalisk and especially hydralisk micro is crisper
  • a base under attack does not receive transferred workers, improving resilience
  • greatly reduce cases where the bot gets a spire/lurker aspect and then delays getting mutas/lurkers

The squad unit clustering allows Steamhammer to play a big army macro game without the constant tactical blunders that it used to make (it makes smaller and mostly different blunders). Many bots use a similar system, with good reason. The tactics rework is substantial, and deserves the 2.0 version number by itself. In combination with the other improvements, Steamhammer is incomparably stronger at ZvP, which may now be its best matchup. I reported on DaQin, and Steamhammer (like Proxy) can open with 12 hatchery and still cope with Wuli’s rush (Proxy’s author called it easy, but it requires a combination of several skills that are not so easy).

I put in a ton of work, but the decisions that unit clusters make are still not as polished as they need to be. An interaction with the combat simulator causes dangerous mistakes in retreating from superior forces. It can happen in all matchups, but it is most obvious in zergling fights in ZvZ. What used to be Steamhammer’s most successful style of play in its best matchup is now its least successful in what may be its weakest matchup. It’s pretty funny, or at least it will be after I figure out how to fix it.

All these items deserve their places on the list. I fixed the case where Steamhammer’s spire used to finish and it would make a bunch of drones instead of mutalisks, and that may sound like the usual modest improvement to the strategy boss. In fact it is a critical fix that makes midgame tech switches more rapid and decisive. It wins games.

Other important changes:

  • mineral locking
  • base defense was reworked extensively
  • new openings added to exploit possibilities and old openings tweaked to fix flaws that had crept in
  • opponent model exploration and strategy randomization improved
  • defiler support with all spells: consume, dark swarm, plague

Many aspects of play have moved forward. As always, there are new bugs like the retreating problem I mentioned above. And as I blathered about yesterday, old weaknesses remain. The overall result is as I’ve reported before, hugely stronger play against some opponents and weaker play against others. Well, that’s in my testing, which is never enough. We’ll see how it goes in the wide world! Since we’re in a time of protoss domination, I’m thinking that strength against protoss is a good sign.

For AIIDE in particular, I expect that my changes to the opponent model are key. I made the couple needed improvements of a previous post. The academic papers I found turned out to be unhelpful, and my changes are ad hoc, but they address the problems. If the opponent chooses strategies unpredictably, Steamhammer will too. If the opponent model doesn’t find a winning counter, it will explore more and more widely until it is randomly trying anything it knows, including openings which are otherwise not played in any context. On the upside, I’m hoping it will eventually hit on surprise counters to the toughest opponents. On the downside, in the worst case it will explore a lot of bad ideas, and the convergence time could be longer than the tournament!

Later today: Notice after Steamhammer 2.0 is uploaded to SSCAIT. Tomorrow: Defiler support in detail.

what I didn’t do

Today, a post about things I wanted to do and didn’t get to, or started to do and rolled back or didn’t finish. I accomplished a lot, but the to-do list is functionally infinite.

• UAlbertaBot executes unit orders as they are issued during the frame, retaining no state beyond what BWAPI remembers. Steamhammer inherited the system. I am in the process of changing it to record the orders and save status info, then issue any needed orders at the end of the frame. Adding the Micro object in the last version was one step. The Micro object now records the order and status of each of our units, and has all the infrastructure it needs to issue orders, including its own update() method with TimerManager calls to track how long it takes. But it doesn’t actually issue orders; there is no effective change to the micro system.

When this is done, it will be easier or possible to unstick units, to make sure units don’t get stuck in the first place, and in general to control units precisely.

• I worked a bit on analyzing Steamhammer’s use of the combat simulator. Improvements are there for the taking, but my first try was not successful and I left it for later.

• McRave suggested that micro to avoid big damage attacks was key. Equally important is to pull off big damage attacks yourself. Besides plague, the zerg big damage attack is scourge suicide, and Steamhammer sucks with scourge. Scourge control is on my list, but never came to the top.

• I implemented mine dodging to reduce the danger of spider mines, but the way I did it was not useful for zerg. Reacting to mines is tricky: If a mine pops up, sometimes you should drag it to the enemy, sometimes drag it away from your other units, sometimes shoot it down. I lost the “just shoot it” case, and it was a net disadvantage. The feature is in the code but is disabled.

• Steamhammer’s lurker skills were adequate for when they were implemented, but have fallen behind the times. It needs to stop doing things like burrowing one lurker at a time in cannon range.

• I haven’t done anything to improve overlord safety, dark templar reactions, or any of that stuff. Many weaknesses there.

• I planned and promised a skill to put pressure on the enemy in the early or middle game, but did not finish one. I had several ideas, and all of them hinged on what I call raiding: Harassing where possible, moving around but staying near the enemy, not retreating to rejoin the main army. Harassing mutalisks can be considered raiders in that sense, and so can Krasi0’s vultures and Bereaver’s reaver drops. Runby units and dropped units should act as raiders, and Steamhammer doesn’t have the skill—with a Hold order, they go idle if they clear their area to hold, and with an Attack order they may try to retreat to the main base. Picking up dropped units is also a good raiding skill.

• I implemented a Watch squad, but did not polish it up enough that it became useful. It is turned off. It had several purposes. It could keep watch on expansions and chokes, sometimes making it possible to disband the Recon squad. It could prevent enemy expansions in some cases, and clear mines and verify the safety of expansions that we wanted to take.

• I thought of adding pre-learned opponent model data for the fixed opponents carried over from last year, plus opponent model hint configuration (like “try this first and see how it works”) for opponents that I think I know something about. PurpleWave, we’re told, did an elaborate job of that for CIG this year. The idea of hints is that the opponent model can save exploration time if the hints are right, winning more games, and correct itself with little loss if the hints are wrong. I decided that, since AIIDE is a long tournament with plenty of time for learning to converge, other work would probably help more.

upcoming

Done with the testing, today I am resting. I’ll upload zerg-only Steamhammer 2.0 to SSCAIT tomorrow. On the blog side, I think I’ll start with an overall evaluation post, what I’ve done and how successful it seems, and follow up with posts about specifics like defiler skills and squad restructuring, and then the big detailed change list. At some point soon Steamhammer 2.1 will slip in. 2.1 will likely have a few minor fixes and deserve its own little change list.

Shortly, CIG should release its detailed results. They promised source and replays. If they also provide a game result log, I’ll analyze it and post my usual colorful summary tables. Not sure how that will fit in with the other posts, the blog may have a busy time.