archive by month
Skip to content

AIIDE 2020 - what Steamhammer learned

Steamhammer’s tables are fuller than others, partly because Steamhammer records more information than most bots and partly because I put more effort into analyzing my own bot’s results. Even so, the game records contain far more information than is summarized here. I have many features in mind that I’d like to add to my analysis scripts.

Some bottom line findings: 1. My preparation for specific opponents was largely successful, as far as it went. All prepared openings had at least a fair win rate, and most were among the most successful openings Steamhammer discovered throughout the tournament. 2. Steamhammer’s gas steal skill had value against many opponents, even though my first analysis of the skill suggested that it might not. (I have known for a long time that my first analysis had missed the truth.) It was able to judge pretty accurately whether stealing gas was effective versus a given opponent, so it could exploit it when successful and reduce the cost of trying it when unsuccessful.


#1 stardust

openinggameswinsfirstlast
10HatchBurrow186%96146
10HatchHydra10%4949
10Pool9Hatch10%3434
11HatchTurtleHydra70%379
11HatchTurtleMuta10%111111
12-11HatchLing10%6060
12HatchTurtle40%1329
2x10HatchAllIn20%53147
2x10HatchSlow10%3838
3HatchHydra10%00
3HatchHydraBust10%5858
3HatchLateHydras+110%5959
3HatchLingExpo10%5454
3HatchLurker10%104104
4HatchBeforeLair10%101101
4PoolHard10%11
4Scout20%4348
5HatchBeforeGas10%7070
5HatchPoolLing10%148148
5HatchPoolLingBurrow10%120120
5PoolHard2Player20%36118
5Scout10%4545
7HatchSpeed30%41117
8DroneGas10%3232
8Gas7PoolLurker B10%5151
8Hatch7Pool20%47139
8Hatch7PoolBurrow10%6363
8Hatch7PoolSpeed10%3535
9Hatch8Pool20%6771
9HatchMain9Pool9Gas20%5062
9PoolHatch10%9999
9PoolHatchBurrow10%4646
9PoolHatchSpeed10%6969
9PoolHatchSpeedSpire20%3773
9PoolSpeedAllIn10%3333
9PoolSpireSlowlings10%5555
AntiTyrLurker10%6666
AntiZeal_12Hatch70%8138
GuardianRush10%4040
Over10Hatch20%683
Over10Hatch1Sunk30%224
Over10Hatch2Sunk40%516
Over10Hatch2SunkHard20%1452
Over10HatchBurrow10%105105
Over10HatchBust297%74145
Over10HatchHydra20%8691
Over10HatchSlowLings20%420
OverhatchLateGas20%7795
OverpoolHydra10%3939
OverpoolSpeed10%126126
OverpoolSunk10%5656
OverpoolTurtle50%11134
Overpool_3HatchLing10%149149
Overpool_4HatchLing20%5768
PurpleSwarmBuild20%129140
QueenRush10%144144
Sparkle 3HatchMuta10%137137
ZvP_2HatchFakeMuta10%130130
ZvP_4HatchPoolHydra20%4464
ZvP_Overpool3Hatch10%7272
ZvT_2HatchMuta10%6565
ZvZ_12HatchMain20%61142
ZvZ_12PoolLingB10%3131
63 openings1502%
planpredictedrecognizedaccuracy
countgameswinscountgameswinsgood?
Heavy rush14899%2%10167%2%68%32%
Unknown21%0%4933%2%0%50%
timing#medianearlylate
my combat unit1503:021:515:35
my gas1483:231:157:50
enemy scout1501:571:172:41
enemy combat unit1502:382:214:47
enemy gas1504:163:598:20
enemy air unit59:497:4711:21
enemy cloaked unit59:497:4711:21
game duration1508:146:1618:36
gas steal#medianearlylatewinsenemy gas
gas steal decision152:131:483:350%4:25
gas steal success112:092:002:270%4:27
none or failed139---2%4:15
gas steal killed112:442:382:59


Steamhammer managed 3 wins with 2 different openings, but basically nothing worked despite trying the full range from 4 pool to hive rush. Stealing gas did not help, but the situation was desperate so Steamhammer tried it 10% of the time. An interesting number is the enemy scout timing: The scout probe arrived at the zerg base with more consistent timing (arriving in a narrower time window) than against any other opponent. Part of Stardust’s recipe is good scouting.


#2 purplewave

openinggameswinsfirstlast
11Gas10PoolLurker10%4343
11Gas10PoolMuta10%6565
11HatchTurtleHydra30%189
11HatchTurtleMuta20%1419
12-11Hatch20%4656
12Hatch12Pool10%8181
12HatchTurtle1315%10147
2HatchLingAllInSpire10%6969
2HatchLurkerAllIn20%2584
2HatchLurkerPure1315%85148
2HatchMutaPure10%128128
2x10HatchSlow10%111111
3HatchHydra10%140140
3HatchHydraExpo20%2467
3HatchLing30%075
3HatchLingBust210%5555
3HatchLingExpo20%74138
3HatchLurker10%6060
5HatchBeforeGas20%116144
5HatchPoolLing10%6868
5PoolHard2Player10%146146
6PoolHide10%118118
6PoolSpeed20%5862
6Scout10%149149
7DroneHatch10%141141
8-8HydraRush10%109109
8Gas7PoolLurker B10%108108
8Hatch7Pool1513%37127
973HydraBust10%104104
9Hatch8Pool10%7272
9HatchExpo9Pool9Gas714%51143
9PoolExpo10%4848
9PoolHatch30%34119
9PoolHatchSpeed7DroneB10%6666
9PoolHatchSpeedAllInB20%8896
9PoolHatchSpeedSpire10%3131
9PoolSpeedAllIn10%5353
9PoolSunkHatch10%9898
AntiFact_13Pool10%4545
AntiFact_2Hatch10%6161
AntiFactoryHydra10%7373
AntiWraith_2Hatch10%114114
AntiZeal_12Hatch110%4112
Over10Hatch40%518
Over10Hatch+110%7171
Over10Hatch11Pool10%7979
Over10Hatch1Sunk10%99
Over10Hatch2Sunk10%1616
Over10Hatch2SunkHard40%3100
Over10HatchBust10%2323
Over10HatchHydra10%8080
OverhatchExpoLing10%121121
OverhatchExpoMuta40%828
OverhatchLateGas10%2929
Overpool+110%115115
Overpool2HatchLurker10%110110
OverpoolHatch10%6464
OverpoolHide10%9393
OverpoolSpeed30%3382
OverpoolTurtle30%213
OverpoolTurtle 010%4242
Overpool_3HatchLing10%106106
ZvP_2HatchMuta10%6363
ZvP_3BaseSpire+Den10%102102
ZvP_3HatchMuta10%4949
ZvP_3HatchPoolHydra10%101101
ZvT_13Pool10%9999
ZvZ_Overgas8Pool10%9797
ZvZ_Overpool11Gas10%7070
69 openings1505%
planpredictedrecognizedaccuracy
countgameswinscountgameswinsgood?
Fast rush--64%0%0%0%
Heavy rush13389%5%7147%4%47%26%
Naked expand--21%100%0%0%
Safe expand1510%7%2215%0%7%27%
Turtle11%0%107%0%0%0%
Unknown11%0%3926%5%0%0%
timing#medianearlylate
my combat unit1503:061:537:55
my gas1503:251:1411:39
enemy scout1502:111:1914:11
enemy combat unit1492:552:186:22
enemy gas1475:113:518:40
enemy air unit10211:074:3916:47
enemy cloaked unit8711:427:1516:58
game duration15013:095:4625:41
gas steal#medianearlylatewinsenemy gas
gas steal decision152:131:583:000%5:10
gas steal success102:222:182:410%5:16
none or failed140---5%5:11
gas steal killed103:052:535:08


Steamhammer again desperately tried every tech and timing known to zerg, and this time found a little success with a few of them—a sunken build, a lurker build, and two 2-hatch zergling wave builds. PurpleWave largely stuck with 2 gates. Stealing gas barely delayed Protoss from taking gas, but Steamhammer still tried 10% of the time—if you’re losing almost all games, it doesn’t hurt.


#3 bananabrain

openinggameswinsfirstlast
11HatchTurtleHydra2730%2149
12-12Hatch10%6363
2HatchHydra10%1515
3HatchHydraExpo10%5555
3HatchLateHydras+110%11
3HatchLingBurrow1828%5139
3HatchLingBust22938%4140
4HatchBeforeGas10%99
4PoolHard10%1010
5PoolHard10%143143
973HydraBust10%00
9PoolHatchSpeedAllInB10%5757
AntiFact_13Pool2438%3137
DefilerRush333%144147
OverhatchExpoLing10%6161
OverhatchExpoMuta10%9494
OverhatchLateGas10%9898
OverpoolSunk10%110110
Overpool_3HatchLing10%3939
Sparkle 2HatchMuta10%4848
ZvP_3HatchPoolHydra1020%26120
ZvT_12PoolMuta812%46146
ZvT_13Pool1547%108148
ZvT_3HatchMuta10%8181
24 openings15029%
planpredictedrecognizedaccuracy
countgameswinscountgameswinsgood?
Fast rush128%33%75%0%17%42%
Heavy rush4228%21%3020%10%19%26%
Naked expand43%25%53%80%0%25%
Proxy--53%0%0%0%
Safe expand7147%31%3725%38%21%31%
Turtle2114%38%1812%67%10%43%
Unknown--4832%23%0%0%
timing#medianearlylate
my combat unit1503:111:474:11
my gas1453:212:136:42
enemy scout1501:451:156:55
enemy combat unit1503:092:196:37
enemy gas1395:222:479:41
enemy air unit1316:022:4711:18
enemy cloaked unit967:113:2614:06
game duration15010:224:4132:00
gas steal#medianearlylatewinsenemy gas
gas steal decision652:131:483:2337%5:19
gas steal success462:191:542:4039%6:04
none or failed104---25%5:07
gas steal killed465:472:4520:00


BananaBrain was the first opponent weak enough that Steamhammer was able to find answers and did not feel a need to throw in the kitchen sink. 2 hatch muta builds were the most successful (and the best was one specialized for play against terran), but zergling builds and hydra builds were also OK. I love that the defiler rush won a game (it’s not at all a practical opening, but against a bot...). Unlike Stardust and PurpleWave, unpredictable BananaBrain played a variety of builds—for example, the appearance of an enemy cloaked unit at 3:26 in one game suggests a dark templar rush. The gas steal was successful and delayed protoss from taking gas for nearly an entire minute, so Steamhammer went with it frequently.


#4 dragon

openinggameswinsfirstlast
2HatchLingAllInSpire850%35140
3HatchLurker1656%0148
4PoolSoft520%1747
5HatchPool5985%5146
5PoolHard2Player10%11
6PoolSpeed10%44
9PoolSpeedAllIn20%23
UltraRush333%142149
ZvT_3HatchMuta771%121147
ZvT_3HatchMutaExpo4078%49145
ZvT_7Pool850%5384
11 openings15070%
planpredictedrecognizedaccuracy
countgameswinscountgameswinsgood?
Factory5637%70%3624%53%46%25%
Heavy rush21%50%11%100%0%50%
Naked expand1711%82%1510%93%18%35%
Safe expand128%33%128%83%8%58%
Turtle11%100%11%100%0%0%
Unknown--4631%74%0%0%
Worker rush6241%74%3926%67%42%29%
timing#medianearlylate
my combat unit1413:171:477:58
my gas1133:471:4710:51
enemy scout1492:151:056:47
enemy combat unit1212:392:218:45
enemy gas1186:022:4311:45
enemy air unit1089:154:2217:01
enemy cloaked unit859:545:4316:34
game duration15015:073:0137:21
gas steal#medianearlylatewinsenemy gas
gas steal decision392:211:564:2072%6:02
gas steal success172:222:143:0665%7:07
none or failed133---71%5:52
gas steal killed174:263:185:08


Steamhammer upset Dragon. The success of 5 hatcheries before spawning pool means that Dragon was not aggressive early, to its detriment—or that Steamhammer recognized any early aggression as a rush and reacted correctly. 3 hatchery mutalisk builds were also good. Even 3 hatchery lurker was not bad, though on the face it appears unsuited to counter Dragon’s play style. The gas steal was not successful in terms of win rate, but Steamhammer noticed that it delayed Dragon’s gas for a long time so it tried anyway. Fewer than half the attempts to steal gas ended with the extractor successfully made, though. The 37 minute game (here 37:21, officially 37:22) was Steamhammer’s longest game of the tournament, except for a couple games versus EggBot that went to the 60 minute limit and had to be adjudicated on points.


#5 mcrave

openinggameswinsfirstlast
12PoolLurker10%5555
3HatchLingBurrow520%97126
8DroneGas1164%106148
9HatchMain9Pool9Gas20%52138
9PoolHatchSpeedAllInB10%1919
9PoolSpire20%5995
Over10HatchBust1942%62149
Over10PoolLing10%00
OverpoolSpeed1520%5135
OverpoolSunk2138%30128
OverpoolTurtle2348%66139
ZvP_3HatchMuta10%134134
ZvZ_12HatchExpo10%77
ZvZ_Overgas9Pool20%13
ZvZ_OverpoolTurtle4558%2146
15 openings15043%
planpredictedrecognizedaccuracy
countgameswinscountgameswinsgood?
Heavy rush2013%35%85%50%0%70%
Naked expand11879%45%3322%42%21%69%
Turtle96%44%43%25%0%78%
Unknown21%0%10469%42%0%50%
Worker rush11%0%11%100%0%0%
timing#medianearlylate
my combat unit1502:262:133:15
my gas1462:321:313:30
enemy scout1502:470:375:51
enemy combat unit1502:341:116:03
enemy gas1303:232:3211:09
enemy air unit1234:313:3710:10
enemy cloaked unit515:0611:4524:23
game duration15010:583:4129:42
gas steal#medianearlylatewinsenemy gas
gas steal decision102:001:542:4830%3:15
gas steal success0-----
none or failed150---43%3:23
gas steal killed0---


Steamhammer failed to recognize McRave’s build in 2/3 of games, though we know from yeterday’s post exactly what they were, and that they should not have been hard to understand. I put more effort into recognizing rushes and proxies that change the whole course of the game than into regular builds, and the result is that Steamhammer’s understanding and prediction are sometimes spectacularly unhelpful. The 8DroneGas build is actually a 9 pool which makes a second hatchery; it’s called that because it ends up with 8 drones while flooding zerglings (it’s not the Styx build, but related). 5 games had cloaked units; I think that means that McRave researched burrow, because it does use burrow and does not seem to ever make lurkers. Steamhammer was unable to steal gas in 10 attempts, so it gave up trying.


#6 microwave

openinggameswinsfirstlast
6PoolBurrow10%5050
8-8HydraRush10%131131
9Hatch8Pool520%6887
9PoolHatchSpeedSpire10%6060
OverhatchLing10%22
OverpoolBurrow10%121121
ZvZ_12HatchExpo540%117141
ZvZ_12PoolLing1164%0149
ZvZ_12PoolMain333%171
ZvZ_Overpool11Gas4473%3147
ZvZ_Overpool9Gas6489%8148
ZvZ_OverpoolTurtle1354%9140
12 openings15071%
planpredictedrecognizedaccuracy
countgameswinscountgameswinsgood?
Fast rush128%67%85%88%8%67%
Heavy rush4429%75%3221%91%20%32%
Naked expand9463%70%4228%67%23%45%
Turtle--43%75%0%0%
Unknown--6443%62%0%0%
timing#medianearlylate
my combat unit1502:261:573:14
my gas1502:061:382:45
enemy scout1502:251:174:53
enemy combat unit1502:411:495:25
enemy gas1295:212:349:37
enemy air unit1157:343:4615:33
enemy cloaked unit0---
game duration15013:323:4130:36
gas steal#medianearlylatewinsenemy gas
gas steal decision61:581:502:200%5:04
gas steal success12:212:212:210%6:40
none or failed149---72%5:16
gas steal killed13:163:163:16


Steamhammer found a variety of overpool openings to be best. Overpool is flexible; those openings play out quite differently. Microwave didn’t play 5 pool often because it didn’t work: Steamhammer’s rush recognition is improved this year, and it reacted well. The burrow openings and 8-8 dawn hydra rush are not appropriate for ZvZ; those choices could be improved. Unlike McRave, Microwave did not use burrow. Stealing gas failed, so Steamhammer gave it up quickly.


#8 daqin

openinggameswinsfirstlast
10HatchLing10%139139
11Gas10PoolLurker10%6363
12-12Hatch10%4242
12Hatch_4HatchLing20%82126
2.5HatchMuta10%9999
2HatchHydraBust20%5131
3HatchHydra20%20113
3HatchHydraBust30%497
3HatchHydraExpo10%5353
3HatchLateHydras+110%107107
3HatchLing5944%0147
3HatchLingBust220%2269
4HatchBeforeGas2520%13144
4HatchBeforeLair10%142142
5HatchBeforeGas20%12
5HatchPool10%128128
5PoolHard2Player10%6666
5Scout10%9393
973HydraBust40%373
9Pool8GasLurker10%9191
9PoolHatchSpeed10%3838
9PoolHatchSpeedSpire210%114114
9PoolHatchSpire10%6767
9PoolSpireSlowlings10%3131
9PoolSunkHatch10%9292
AntiFact_2Hatch10%8787
AntiFact_Overpool9Gas10%141141
AntiFactory210%116116
Over10Hatch1Sunk10%7676
OverhatchExpoMuta30%1747
OverpoolSpeed10%7272
OverpoolTurtle 020%106146
Proxy8HatchNatural10%4141
Sparkle 3HatchMuta617%120136
ZvP_2HatchMuta10%2525
ZvP_3BaseSpire+Den10%115115
ZvP_3HatchPoolHydra714%133149
ZvT_2HatchMuta10%5757
ZvT_3HatchMuta10%4343
ZvT_7Pool10%5959
ZvZ_12PoolLing10%7777
ZvZ_12PoolLingB20%103129
ZvZ_Overpool11Gas10%8888
43 openings15022%
planpredictedrecognizedaccuracy
countgameswinscountgameswinsgood?
Heavy rush--107%20%0%0%
Naked expand--53%80%0%0%
Safe expand3523%11%4832%21%37%6%
Turtle11476%25%8557%20%59%0%
Unknown11%100%21%0%0%0%
timing#medianearlylate
my combat unit1503:111:515:01
my gas1503:221:475:53
enemy scout1491:301:1511:34
enemy combat unit1504:494:066:51
enemy gas1485:424:438:31
enemy air unit3813:159:1026:30
enemy cloaked unit4812:114:4317:37
game duration15011:166:2236:26
gas steal#medianearlylatewinsenemy gas
gas steal decision312:141:583:0635%6:16
gas steal success312:222:083:1335%6:16
none or failed119---18%5:32
gas steal killed312:532:3813:06


DaQin upset Steamhammer badly, and zerg fell back on exploring widely. One ling bust and a few macro builds were able to save some games against DaQin’s consistent forge expand (which Steamhammer often misrecognized as Turtle because it did not actively look for the expansion nexus). The gas steal is measured to increase the overall win rate from 18% to 22%, not bad.


#9 zzzkbot

openinggameswinsfirstlast
8Hatch7Pool560%103133
9PoolHatchSpire425%14148
9PoolSunkHatch3067%3149
9PoolSunkSpeed1771%0136
OverhatchLing1464%108140
OverpoolSunk2050%1143
ZvZ_12Pool10%7979
ZvZ_OverpoolTurtle5997%13147
8 openings15075%
planpredictedrecognizedaccuracy
countgameswinscountgameswinsgood?
Fast rush4027%80%107%100%25%68%
Turtle11073%73%2718%70%22%78%
Unknown--11375%73%0%0%
timing#medianearlylate
my combat unit1502:252:143:06
my gas1482:382:017:07
enemy scout1502:380:394:01
enemy combat unit1502:411:534:31
enemy gas1215:272:248:21
enemy air unit626:346:238:35
enemy cloaked unit0---
game duration1507:544:2615:23
gas steal#medianearlylatewinsenemy gas
gas steal decision82:372:013:0175%5:27
gas steal success0-----
none or failed150---75%5:27
gas steal killed0---


ZZZKBot switches between its famous 4 pool (recognized as Fast rush; see the 100% win rate when the strategy was recognized) and a build with sunkens, two hatcheries, and 6 sudden mutalisks (recognized as Turtle). It seems that part of Steamhammer’s difficulty with ZZZKBot (I consider a 75% win rate to be low in this case) is due to poor scouting: See the rate of Unknown enemy strategies. A bigger part of it may be a problem with the exploration policy. ZvZ_OverpoolTurtle scored 97% and was discovered early, but was played in only 59 games out of 150.

Steamhammer does not use enemy scout timing as a clue to the enemy strategy, and it should. When a scout appears at your base in 39 seconds it must have been sent almost immediately. Either the enemy is rushing, or is terrified that you might. A comparison of past scout timings versus recognized strategies for this opponent could be strong evidence.

ZZZKBot takes gas only in its muta strategy, and then it has sunkens so that a gas steal cannot succeed. Steamhammer figured that out fairly quickly.


#10 ualbertabot

openinggameswinsfirstlast
973HydraBust10%129129
AntiZeal_12Hatch771%0142
Over10Hatch475%2141
OverpoolTurtle13799%1148
4 openings14996%
planpredictedrecognizedaccuracy
countgameswinscountgameswinsgood?
Factory107%100%1711%100%0%50%
Fast rush2819%93%2315%96%14%36%
Heavy rush11174%96%6040%93%44%22%
Naked expand--107%100%0%0%
Unknown--3926%97%0%0%
timing#medianearlylate
my combat unit1492:262:223:15
my gas1472:582:544:46
enemy scout1402:021:187:41
enemy combat unit1182:391:424:33
enemy gas1273:382:3713:12
enemy air unit3314:3110:4616:33
enemy cloaked unit3214:162:3716:33
game duration1498:273:4220:54
gas steal#medianearlylatewinsenemy gas
gas steal decision0-----
gas steal success0-----
none or failed149---96%3:38
gas steal killed0---


Steamhammer recorded only 149 games against UAlbertaBot, because it crashed one game, its only crash in the tournament. Against every other opponent, Steamhammer recorded all 150 games.

There was no need to test the gas steal. If you’re winning nearly all games, spending a drone to vary your play is not likely to gain anything. Another point is that UAlbertaBot often takes gas quite late, so stealing gas early is unlikely to pay off.


#11 willyt

openinggameswinsfirstlast
11Gas10PoolLurker4774%4149
12-12Hatch10%4646
2HatchLurker10%115115
4PoolHard520%258
9HatchMain9Pool9Gas1638%7148
9PoolSpeed3358%1141
9PoolSpeedAllIn2854%3145
GuardianRush540%123143
Over10Hatch2Sunk10%146146
Overpool_3HatchLing10%113113
Sparkle 3HatchMuta1145%65132
ZvT_3HatchMuta10%00
12 openings15055%
planpredictedrecognizedaccuracy
countgameswinscountgameswinsgood?
Factory--11%0%0%0%
Fast rush--11%0%0%0%
Heavy rush1611%62%1510%27%12%50%
Naked expand8657%53%3523%100%17%52%
Safe expand4832%56%3020%77%25%31%
Unknown--6845%31%0%0%
timing#medianearlylate
my combat unit1502:421:463:38
my gas1451:491:455:17
enemy scout1422:111:387:19
enemy combat unit1502:592:056:41
enemy gas1125:134:0410:07
enemy air unit1117:1310:4530:58
enemy cloaked unit2214:237:1019:33
game duration1508:484:4231:49
gas steal#medianearlylatewinsenemy gas
gas steal decision272:131:482:4367%5:45
gas steal success232:211:562:5770%6:19
none or failed127---53%5:11
gas steal killed234:063:004:43


WillyT was a tough opponent for Steamhammer. The choice of zerg builds does not seem strong. I have no idea how the guardian rush won 2 games out of 5.


#12 ecgberht

openinggameswinsfirstlast
11HatchTurtleLurker10%11
11HatchTurtleMuta757%8148
12HatchTurtle10%119119
9PoolLurker4791%0149
9PoolSpeed2576%3142
AntiStyx_9Pool475%121141
HiveRush875%89140
Over10HatchBust2282%2135
OverpoolLurker3591%4147
9 openings15083%
planpredictedrecognizedaccuracy
countgameswinscountgameswinsgood?
Factory3926%79%2416%79%28%26%
Fast rush3020%80%2114%90%10%40%
Heavy rush5637%89%2315%87%18%39%
Naked expand64%67%64%83%17%33%
Proxy85%75%53%60%0%50%
Safe expand85%100%85%75%0%50%
Unknown--5537%87%0%0%
Worker rush32%67%85%62%0%33%
timing#medianearlylate
my combat unit1502:182:113:17
my gas1501:551:457:07
enemy scout1441:270:305:18
enemy combat unit1483:011:556:53
enemy gas985:052:518:43
enemy air unit495:584:0119:55
enemy cloaked unit315:545:217:15
game duration1508:363:5222:29
gas steal#medianearlylatewinsenemy gas
gas steal decision222:171:485:4586%5:10
gas steal success132:232:005:5185%5:24
none or failed137---83%5:03
gas steal killed133:272:176:10


Ecgberht is a tricky opponent. If it knew how to defeat fast lurker builds, it would score a lot higher against Steamhammer.


#13 eggbot

openinggameswinsfirstlast
2HatchHydraBust367%3286
3HatchHydra786%70105
3HatchHydraBust367%52103
3HatchHydraExpo8100%15137
3HatchLateHydras+1683%1375
3HatchLingBust26100%12121
4HatchBeforeGas6100%7149
4HatchBeforeLair11100%16142
5HatchBeforeGas8100%1118
6PoolHide19100%5145
973HydraBust9100%6130
9PoolHide10100%27115
9PoolSunkHatch11100%0138
9PoolSunkSpeed7100%18148
AntiStyx_9Pool6100%8129
OverpoolHide14100%2146
ZvP_3BaseSpire+Den10100%11141
ZvP_3HatchPoolHydra683%30147
18 openings15097%
planpredictedrecognizedaccuracy
countgameswinscountgameswinsgood?
Contain5637%98%3322%100%23%43%
Proxy3523%97%2517%80%14%37%
Turtle5939%95%3725%100%20%31%
Unknown--5537%100%0%0%
timing#medianearlylate
my combat unit1502:261:584:09
my gas1393:432:388:31
enemy scout791:290:3110:17
enemy combat unit326:504:318:59
enemy gas0---
enemy air unit0---
enemy cloaked unit0---
game duration1506:504:0460:00
gas steal#medianearlylatewinsenemy gas
gas steal decision0-----
gas steal success0-----
none or failed150---97%-
gas steal killed0---


EggBot is a cannon bot. Its builds were recognized as Proxy for close cannons, Contain for cannons farther away from zerg bases, or Turtle for distant cannons. Steamhammer tried a variety of openings, discarding one as soon as it had lost a single game because there were others that still scored 100%. Steamhammer understood that EggBot never took gas, so gas steal would gain nothing.


overall

totalZvTZvPZvZZvR
openinggameswinsgameswinsgameswinsgameswinsgameswins
10HatchBurrow186% 186%
10HatchHydra10% 10%
10HatchLing10% 10%
10Pool9Hatch10% 10%
11Gas10PoolLurker4971% 4774% 20%
11Gas10PoolMuta10% 10%
11HatchTurtleHydra3722% 3722%
11HatchTurtleLurker10% 10%
11HatchTurtleMuta1040% 757% 30%
12-11Hatch20% 20%
12-11HatchLing10% 10%
12-12Hatch30% 10% 20%
12Hatch12Pool10% 10%
12HatchTurtle1811% 10% 1712%
12Hatch_4HatchLing20% 20%
12PoolLurker10% 10%
2.5HatchMuta10% 10%
2HatchHydra10% 10%
2HatchHydraBust540% 540%
2HatchLingAllInSpire944% 850% 10%
2HatchLurker10% 10%
2HatchLurkerAllIn20% 20%
2HatchLurkerPure1315% 1315%
2HatchMutaPure10% 10%
2x10HatchAllIn20% 20%
2x10HatchSlow20% 20%
3HatchHydra1155% 1155%
3HatchHydraBust729% 729%
3HatchHydraExpo1267% 1267%
3HatchLateHydras+1956% 956%
3HatchLing6242% 6242%
3HatchLingBurrow2326% 1828% 520%
3HatchLingBust23845% 3845%
3HatchLingExpo30% 30%
3HatchLurker1850% 1656% 20%
4HatchBeforeGas3234% 3234%
4HatchBeforeLair1385% 1385%
4PoolHard714% 520% 20%
4PoolSoft520% 520%
4Scout20% 20%
5HatchBeforeGas1362% 1362%
5HatchPool6083% 5985% 10%
5HatchPoolLing20% 20%
5HatchPoolLingBurrow10% 10%
5PoolHard10% 10%
5PoolHard2Player50% 10% 40%
5Scout20% 20%
6PoolBurrow10% 10%
6PoolHide2095% 2095%
6PoolSpeed30% 10% 20%
6Scout10% 10%
7DroneHatch10% 10%
7HatchSpeed30% 30%
8-8HydraRush20% 10% 10%
8DroneGas1258% 10% 1164%
8Gas7PoolLurker B20% 20%
8Hatch7Pool2223% 1712% 560%
8Hatch7PoolBurrow10% 10%
8Hatch7PoolSpeed10% 10%
973HydraBust1656% 1560% 10%
9Hatch8Pool812% 30% 520%
9HatchExpo9Pool9Gas714% 714%
9HatchMain9Pool9Gas2030% 1638% 20% 20%
9Pool8GasLurker10% 10%
9PoolExpo10% 10%
9PoolHatch40% 40%
9PoolHatchBurrow10% 10%
9PoolHatchSpeed20% 20%
9PoolHatchSpeed7DroneB10% 10%
9PoolHatchSpeedAllInB40% 30% 10%
9PoolHatchSpeedSpire40% 30% 10%
9PoolHatchSpeedSpire210% 10%
9PoolHatchSpire520% 10% 425%
9PoolHide10100% 10100%
9PoolLurker4791% 4791%
9PoolSpeed5866% 5866%
9PoolSpeedAllIn3247% 3050% 20%
9PoolSpire20% 20%
9PoolSpireSlowlings20% 20%
9PoolSunkHatch4372% 1385% 3067%
9PoolSunkSpeed2479% 7100% 1771%
AntiFact_13Pool2536% 2536%
AntiFact_2Hatch20% 20%
AntiFact_Overpool9Gas10% 10%
AntiFactory210% 10%
AntiFactoryHydra10% 10%
AntiStyx_9Pool1090% 475% 6100%
AntiTyrLurker10% 10%
AntiWraith_2Hatch10% 10%
AntiZeal_12Hatch2520% 180% 771%
DefilerRush333% 333%
GuardianRush633% 540% 10%
HiveRush875% 875%
Over10Hatch1030% 60% 475%
Over10Hatch+110% 10%
Over10Hatch11Pool10% 10%
Over10Hatch1Sunk50% 50%
Over10Hatch2Sunk60% 10% 50%
Over10Hatch2SunkHard60% 60%
Over10HatchBurrow10% 10%
Over10HatchBust7139% 2282% 307% 1942%
Over10HatchHydra30% 30%
Over10HatchSlowLings20% 20%
Over10PoolLing10% 10%
OverhatchExpoLing20% 20%
OverhatchExpoMuta80% 80%
OverhatchLateGas40% 40%
OverhatchLing1560% 1560%
Overpool+110% 10%
Overpool2HatchLurker10% 10%
OverpoolBurrow10% 10%
OverpoolHatch10% 10%
OverpoolHide1593% 1593%
OverpoolHydra10% 10%
OverpoolLurker3591% 3591%
OverpoolSpeed2015% 50% 1520%
OverpoolSunk4342% 20% 4144%
OverpoolTurtle16887% 80% 2348% 13799%
OverpoolTurtle 030% 30%
Overpool_3HatchLing40% 10% 30%
Overpool_4HatchLing20% 20%
Proxy8HatchNatural10% 10%
PurpleSwarmBuild20% 20%
QueenRush10% 10%
Sparkle 2HatchMuta10% 10%
Sparkle 3HatchMuta1833% 1145% 714%
UltraRush333% 333%
ZvP_2HatchFakeMuta10% 10%
ZvP_2HatchMuta20% 20%
ZvP_3BaseSpire+Den1283% 1283%
ZvP_3HatchMuta20% 10% 10%
ZvP_3HatchPoolHydra2433% 2433%
ZvP_4HatchPoolHydra20% 20%
ZvP_Overpool3Hatch10% 10%
ZvT_12PoolMuta812% 812%
ZvT_13Pool1644% 1644%
ZvT_2HatchMuta20% 20%
ZvT_3HatchMuta1050% 862% 20%
ZvT_3HatchMutaExpo4078% 4078%
ZvT_7Pool944% 850% 10%
ZvZ_12HatchExpo633% 633%
ZvZ_12HatchMain20% 20%
ZvZ_12Pool10% 10%
ZvZ_12PoolLing1258% 10% 1164%
ZvZ_12PoolLingB30% 30%
ZvZ_12PoolMain333% 333%
ZvZ_Overgas8Pool10% 10%
ZvZ_Overgas9Pool20% 20%
ZvZ_Overpool11Gas4670% 20% 4473%
ZvZ_Overpool9Gas6489% 6489%
ZvZ_OverpoolTurtle11777% 11777%
total179954%45070%75031%45063%14996%
openings played15129130304


This is not all of Steamhammer’s zerg openings! The tournament wasn’t long enough for it to try everything.

Steamhammer 3.2.20 is out

Steamhammer 3.2.20 is uploaded to SSCAIT, source code to follow shortly. It has minor bug fixes and tweaks, nothing earthshaking. I turned on the DrawWorkerInfo debug flag to add fun. Here’s what’s new.

squad targeting

• A squad that is empty or otherwise cannot attack is given a default target. This “amazing” optimization may save a few hundred microseconds of computation per game, though I think it’s less. I made this change after investigating what I suspected was a serious bug that gave squads bad targets. The cause turned out to be a race between squad updating and squad targeting that went wrong a few times per game and affected a squad for only one frame, and only when the squad wasn’t able to take action anyway—the bug actually had no bad effects. This change papers over the bug without addressing the unimportant race condition.

infrastructure

go post worker now works on frame 0. The feature worked when I originally released it, but a change I made to fix a problem for AIIDE (reordering manager calls to prevent double commanding) caused go post worker to fail when issued at the very beginning of the build order. I fixed it by removing the worker job type Default; a worker that has not yet been given a job is now Idle, as it logically should be. I like it when I can fix a bug by cutting out unnecessary parts. The effect of the bug was to break one protoss build, Proxy2Gate, that sends out a worker first thing.

MapGrid::getLeastExplored() no longer accepts a zone argument. It’s not needed since getLeastExploredNear() was added.

construction

The building manager correctly counts the number of workers sent to construct a building. If the first worker dies and it has to send another, the count goes to 2, and so on. It used to often miscount. This is the most important fix here, and solves the zerg macro hatch conversion bug. It should also solve misbehaviors by terran and protoss.

terran

• It was rare but possible for a terran building to be abandoned while incomplete, lost from the building queue so that it was never canceled, permanently wasting resources. Fixed.

• When going bio, get gas and academy slightly earlier.

zerg

• Assign an overlord to look over the next base that Steamhammer intends to take. That will let it spot any spider mines or other obstacles to taking the base. The overlord usually arrives well before any drone is sent. The overlord stays home if the enemy has flying overlord hunters out on the map, though.

• Adjust desired drone counts so that Steamhammer is willing to make more queens. For some reason, Steamhammer was rarely making more than 1 queen. With this change, it often makes 2 when the enemy units and queen research justify it (many tanks means more queens for broodling). It’s configured to make up to 6 queens, so 2 is still low, but the issue is not worth a close look right now.

openings

Over10PoolHydra hydra bust added. This was inspired by a CUBOT build that I saw drive BananaBrain to its knees (CUBOT broke the protoss natural, continued its attack into the main and killed nearly all probes, then lost despite a winning advantage when already queued dragoons popped out of the gates). Steamhammer’s version is entirely different in detail and I think stronger.

Next should be Steamhammer 3.3, finally ported to BWAPI 4.4.0. Tomorrow I’ll start looking at what different bots learned from their experience in AIIDE. Meanwhile, the AIIDE unknown maps competition must be running now, and the results may be out this weekend or thereabouts. I’m eager to see what maps came up this time.

opening timing data for Steamhammer

Here are my implementation thoughts about opening timing data, as mentioned yesterday. I haven’t decided whether this is what I’ll do next, still thinking. I will at least do something similar eventually.

the data

1. Record timings for all of Steamhammer’s openings, in a static data file to be read at startup. The timings should include the time when each tech or production building finishes, plus the number of workers and the army size and composition at the end of the book line (meaning the units produced; some may have been lost), and maybe a few other things. Time resolution of one second or a few seconds is probably fine. Even so, timings will vary from game to game, so maybe the timings should give low and high values, or mean and variance, or something.

Another idea is to accept that new openings will be added and reject the work of timing them before they can be played. Keep a database of opening timings and update it after each game. That’s only safe on a server which plays one game at a time; for tournaments like AIIDE the database would have to be frozen and read-only.

2. For each game against a given opponent, record the earliest time that each enemy unit type is scouted, including buildings. Steamhammer already does this, with its “unit timing” skill (implemented using the skill kit). Also record the timing and army size and composition of the enemy’s first attack, or maybe its first few attacks, or maybe all of its major attacks. I’ll see what helps.

using the data

The data about the enemy can be used to recognize enemy builds earlier and more consistently. Most bots have a small repertoire of openings. As Steamhammer plays, it can check its scouting data for the current game for the closest matches among recorded games. If the records say that the enemy followed up the same way in all of the close matches, then the enemy strategy is predicted to that extent. You can see it as a kind of case-based reasoning: Find approximately matching cases and generalize from them.

We don’t have to fully predict the enemy strategy to react to it, we only need to know constraints on it. For example, if we’re going to add static defense (whether written into the opening or in reaction to the enemy army size), then we can check records of when the enemy first attacked: Don’t build sunks too early. If a clever enemy notices the vulnerability and attacks early, too bad, but then we have a new game record and will know for next time.

The main purpose of the opening timings is to choose openings. The records of enemy games tell us the range of enemy play. When choosing an opening at the start of the game, before any scouting information is available, we can try to pick one with unit mix and timings that counter the range of enemy play. One basic adaptation is to try to always be a little greedier than the enemy, to get ahead in economy (except when the enemy is too greedy, then we can rush). That’s a principled way to choose 5 hatch before pool versus Dragon. Another is, if the enemy prefers certain units, we can pick openings that produce counter units at the right time.

Of course the data can also be used to adapt openings when our first choice was not right for the enemy’s actual play. It will be a while before Steamhammer can do that with generality.

Steamhammer plans

Time for another update on my plans, since they change almost as fast as I can think up changes. After the big push for AIIDE 2020 I have been working slowly, but I’m still making progress.

I’ll release a version 3.2.20 soonish, with small bug fixes and other minor tweaks. For example, I found the cause of failed macro hatchery conversion, and I’m correcting it now. None of the fixes should make a big difference in playing strength, but I know from experience that many small improvements add up to a big improvement. Next, if I can get it to work this time, will be version 3.3 on BWAPI 4.4.0, a necessary upgrade. I expect I will be unable to resist features enabled by 4.4.0, like delaying overlord speed until after hive and tracking enemy terran scans.

Then I want to at long last make visible progress on my main objective of strategy adaptation. I’ve changed my mind repeatedly about what the next step should be, and the result is that I have nonworking partial implementations of several complex features. I don’t see it as wasted work, because all the features are necessary, but it does mean I have no progress to show off. I want to bite off a piece small enough that I can swallow it down in time for the year-end SSCAIT tournament. I think it should be either the opening timing stuff that came up yesterday (it does give useful though ambivalent hints), or else some machine learning stuff I’ve mentioned earlier, whose code has been sitting in an almost-finished state, not yet passing small-scale tests and unready to be integrated into the whole program for its big test. Whether I make it in time for SSCAIT or not, I expect my choice to be the theme of the 3.4.x series.

Next: Specifics on opening timing.

Steamhammer-Dragon games

The latest SSCAIT weekly broadcast included a Steamhammer-Dragon game where Steamhammer went up to five hatcheries before it started its spawning pool, a crazy risky build that loses to any early attack. Dragon did not attack early and was hammered into the ground by huge macro. Sonko, narrating the game, rightly concluded that Steamhammer’s opening was the result of learning, though the opening timing idea he mentioned is still on my to-do list. Anyway, five hatches before pool is one of Steamhammer’s favorite builds versus Dragon, but it also plays others, and not always successfully. I thought I’d briefly list a few recent games to show how tricky it can be to choose openings. Even if you know the enemy’s timings, it is still tricky.

7 hatch 6 pool speed, a zergling rush that starts slower than the pool-first rushes but hits harder because of the two hatcheries and the zergling speed research. The opening leaves only 7 drones to power the two hatchery production, so it’s very much all-in. Dragon saw it coming and reacted with a bunker in its main, though for some reason it followed with an expansion CC which it lost without canceling. Even so, Dragon’s defense was better than Steamhammer’s attack, the all-in failed after vultures arrived, and Dragon was in a winning position. But (no doubt due to some bug) terran left only 1 SCV on gas and suffered a severe vespene shortage, and compensated by going mass vultures, not a strong backbone unit for a terran army. The game turned much more exciting than it should have been.

9 pool into 2 hatcheries, with early but not heavy pressure. Again Dragon made a bunker in main and defended easily. Steamhammer droned up well, keeping pace with the terran economy, but could not also make a strong army. Zerg ran into trouble.

5 hatch before pool, like the broadcast game, except this time Dragon got a vulture into the zerg base before defense was quite ready, then followed up with wraiths when defense was not even close to ready. Zerg struggled but finally stabilized, and the game was on. This is the most interesting of the games.

The first two games are fast rushes. One was all-in and the rush failed, but the opponent’s game plan was discomposed by an unforeseeable factor. The other was not all-in and looked successful at first, but did not actually keep up. Even if you recognize the enemy’s tech and attack timings, it’s tricky to choose an opening that exploits them successfully. Starcraft is complicated! The third game is a reminder that the enemy gets a vote, and can change up its timings, or can play its builds sloppily so that the timings vary. At a minimum, you have to take into account the range of timings.

broodling!

Today’s ASL 10 games were excellent. Every game was exciting. There were cool and unusual events, such as turrets placed solely for deception, and 3-base zerg versus 3-base zerg. Recommended.

Meanwhile, to fill the time as I make my second attempt to upgrade Steamhammer to BWAPI 4.4.0, here is another unusual game. The pictures show a queen killing an ultralisk with broodling, something I mentioned by name in the latest change list. See the queen’s energy level and the ultralisk remains. The game is weak on both sides, but as I forecast, Steamhammer was more ready than its opponent for the rare situation.

the queen is ready

scratch one ultralisk

The game was played over a week ago. If Crona is already updated to fix some of the mistakes here, that’s no surprise. Steamhammer has a related improvement.

a bug and its antimatter twin

Steamhammer has a special case reaction in the building manager to ensure that it builds enough macro hatcheries when it is contained: If a drone sent to build an expansion hatchery did not make it there, and zerg suffers from a larva shortage, then the expansion is converted to a macro hatchery instead. A drone is assigned to build the hatchery in base.

The feature seems to have bit-decayed and it is not working reliably. I’ve seen a few games where Steamhammer was contained and desperately kept sending drones to try to expand, while it had a larva shortage and its mineral bank was building up.

At the same time I see the diametrically opposite bug in Steamhammer’s terran play: When terran is contained for a long time, it starts to build “macro command centers” inside its base, which essentially act as oversize 400 mineral supply depots. It doesn’t know how to lift them off and land them elsewhere, and it doesn’t need more SCV production, so it’s pure loss.

What the what?!?

Logically, the bugs must be unrelated. The zerg special case explicitly checks that the building is a zerg hatchery. But it behaves exactly as though it had the races mixed up. If the two bugs annihilated like matter and antimatter, they would create energetic play.

Both bugs are on my list to solve soon. The terran bug is as serious as the zerg one in terms of wasted resources.

Steamhammer’s prepared learning data for AIIDE 2020

What is the best way to prepare initial learning files for a tournament when you have partial knowledge of how your opponents will play? How should you seed your opponent model? Certainly it depends on your learning algorithm. I did not find the answer, but I poked at it and took my best guess for Steamhammer.

I tried an informal experiment on the Starcraft AI Ladder. The ladder is reset to zero once a week—it erases the game records, everybody’s learned data, everything, and makes a fresh start. One week I collected recent full-length data files and set those as Steamhammer’s prepared learning data for use after the weekly reset. (Because of how Steamhammer uses its prepared learning data, the files were not read at all until the reset.) The opponent is reset too, and may not play the same way that the old learning files expect, so it’s not guaranteed that the old learning files are the best seed for new learning. Still, I expected them to provide an advantage over starting from scratch. It makes intuitive sense that if the opponent is relatively constant, such as an opponent carried over in the tournament from a previous year, then keeping your learning files is good. But there may be cases where it’s not true, because both sides learn.

I was interested in whether the carried-over learning data would be helpful from the start, or would have trouble until it adjusted to the opponent’s reset. I let the ladder run overnight and collected data then. The carried-over data did seem to work well, certainly better than the missing or unmaintained initial data I had been using up to then.

The next week I tried an alternative, preparing minimal initial data. Steamhammer’s learning varies its approach depending on how much data is available, so I expect a difference between full-size and minimal prepared data. I looked through my records of previous weeks—not only one previous week—and selected by hand a small number of sample game records using varied openings that had scored well, never more than 4 games. This is the kind of preparation that makes intuitive sense if you have data on an opponent but you expect that the bot has enjoyed a major update—you want to be ready to exploit known weaknesses, but also to be ready to switch in case the weaknesses are gone. Again I set things up and grabbed the data the next morning. And the minimal data performed better. No opponent had worse numbers.

It was not in any sense a well-controlled experiment. Two weeks of data with the ladder’s small number of opponents is not enough to draw a statistically valid conclusion. Both Steamhammer and other bots were updated during the week between experiments, so the result is more than questionable, not solid but vapor. It’s entirely possible that Steamhammer performed better because I had made an important improvement during the week, and I know that I made improvements. Nevertheless this was the data I had, and I decided that it was more likely to be right than wrong. To my eye, Steamhammer’s performance curve over time looked more convincing with the minimal prepared data—not a scientific conclusion.

So in my AIIDE 2020 submission, I went with minimal prepared learning data. I selected the sample games with more care than in my experiment, trying to take everything into account. I could not prepare for the unknown bots, but I did invent one fictional game for EggBot so that Steamhammer will know it is a cannon bot. I did not prepare for Stardust because nothing has yet worked twice against Stardust. I also didn’t prepare against DaQin because I didn’t have recent data handy; I could have tried harder, but time was short.

We’ll see how it goes!

Surely the best preparation can’t be found by a fixed rule, but depends on the opponent and on what you know about it. And by nature it depends on your bot’s learning algorithm. It’s a question worth thought.

Steamhammer AIIDE 2020 version change list

Steamhammer 3.2.19 (you did memorize the version number as I required, yes?) is uploaded to SSCAIT. Randomhammer too, since a few quick games did not turn up any new bugs in terran or protoss, untested while I worked on zerg. I worked on basic skills (saving my tricks for later), smoothing some of Steamhammer’s long-standing jagged edges, and the bot is appreciably stronger. I’m excited to see how Newfangled Steamhammer copes with the great variety of opponents on SSCAIT and BASIL. Will the anti-cannon procedures work against Krasi0P? I didn’t test it, that opponent is not in the tournament. This Steamhammer has a lot of new fangling, there is sure to be some surprising interplay with other bots.

The SSCAIT upload is the same code and configuration as the AIIDE version. Since the configuration is the same, none of the debug display options is turned on (don’t want that for a tournament), so there’s no interesting drawing on the screen. However, the learning files that I prepared for AIIDE are not carried over to SSCAIT; I’m leaving the existing learning files in place. From experience, I expect that Steamhammer will perform worse on SSCAIT and BASIL for some weeks until the opening learning adjusts to the new behaviors—and to the opponents’ changed reactions to the changed behaviors.

I divide up the changes by the aspect of Steamhammer they affect, as usual. It may be a mistake, because it conceals how teams of changes are coordinated to meet goals. There are teams of changes which work together to help Steamhammer survive cheese, and teams which work together to reduce wasted units during the midgame. The different changes in each team are in different parts of the code, and I write each one up separately, but the important thing is that each team pulls its oars in synchrony.

Today’s list bundles together all the changes I made in versions 3.2 through 3.2.19 (20 versions in all). The test versions had short lifetimes, some of them a day or less. As usual, the more important items are in bold.

Whew, I needed the extra day to have any hope of writing up this, er, nearly endless list by today. I started it on Tuesday, worked on it all day yesterday, and didn’t finish until now.

safe movement

Micro::MoveSafely() is a drop-in alternative to Micro::Move() for use by units which prefer to never come under enemy fire. It follows the simple method of running away from the nearest dangerous enemy, gaining 80% of the benefit of optimized hazard avoidance with 20% of the effort. If you know what to look for it’s easy to see cases where it makes a worse decision than potential fields would, but you have to look.

Overlords use MoveSafely(), except for squad detector overlords which already have their own way to avoid danger. Formerly, one of Steamhammer’s great weaknesses was that it would generously donate overlords to the enemy cause. Sometimes it would try to transfer an overlord to a distant base when an enemy army happened to be on the path, fail, try again.... In the worst cases, overlords would appear to converge from all sides on a group of marines or dragoons as if they were flying ultralisks closing a surround. That is all gone. Overlords are lost at a reasonable rate and live longer, more fruitful lives.

Workers also move safely using some of the same code, though the implementation is more involved than MoveSafely() because of the special needs of workers. Micro has a suite of helper functions. There is one exception: When moving to construct a building, just go there. The scout worker does rely on MoveSafely(), and it has become more adept at surviving to see what is going on. Overall, it’s a clear benefit. When zealots raid, the workers scatter and have to be chased down, at worst causing delay to the enemy and at best surviving to return to mining.

If burrow is researched, workers burrow to avoid danger instead of running away, unless an enemy detector is seen to be in range. This behavior is a delight to watch. Zealots raid, or a reaver lands—and the enemy sees nothing but puffs of dust as the workers disappear under the ground. After the attack is cleared, the workers pop up and instantly return to work. Steamhammer still loves to transfer workers across the middle of the map where the enemy is roaming, but now the workers realize the risk and burrow for safety. The enemy may like to scan when it sees units burrow (Steamhammer terran does that), or may have an observer which was out of range when the workers burrowed but can be brought over, so it’s not entirely safe, but it’s a breakthrough compared to the former behavior of running willy-nilly into the grinder. Also if the enemy moves away a bit the workers may unburrow, try to continue, come too close again and reburrow—which is funny if nothing else.

Overall, safe movement is a huge gain. There is room to make it far better yet, but that will take incremental refinement over time. There are disadvantages in certain situations. For example, when there is only one base and it is raided, then the workers flee or burrow and there is no mining whatsoever to fuel production and defeat the attack. It might have been better to keep mining and accept the loss of workers. Terran could do something like send 1 wraith to each mineral line and stop all mining, and in fact I have seen Steamhammer lose in similar ways.

scouting and overlord assignments

Every overlord is assigned a location to move to and stay at. These parts are unchanged: One overlord is under the control of the scout manager early in the game. Some overlords are assigned to squads to serve as detectors and provide vision. The remaining overlords belong to the Overlord squad. What is different is that the Overlord squad assigns a location to every overlord it controls. Formerly, the Overlord squad assigned locations to some overlords and left the remainder floating wherever they happened to be, which might be in the middle of the map. It was not efficient scouting, and it was not safe for the overlords (but it was easy and I got it done).

The Overlord squad has gained a general assignment system similar to (but simpler than) what I plan for the deferred Scout Boss. It lists useful overlord destinations in priority order, then assigns the closest available overlord to each destination in order. If there are leftover overlords, as there generally are by the middle of the game, the remainder are sent to the front line of the front base (both “front” ideas are detailed in sections below)—basically, they wait together in a clump near where the enemy is likely to try to attack. It’s a reasonable try because the overlords use MoveSafely() to flee dangers.

• Early in the game, one overlord is assigned to survey the main base for hidden proxies. It uses the new function MapGrid::getLeastExploredNear() to repeatedly find what place inside the starting base has least recently been seen, and goes there. The result is that the overlord flies an irregular, adaptive, hard-to-predict and fairly efficient search pattern (and it takes literally 2 lines of code inside the Overlord squad thanks to the infrastructure). I was inspired to add this by a game versus Ecgberht where the terran built a hidden proxy factory in a far corner of the zerg base, a strategy that has earned it a lot of wins over Steamhammer. Typically Steamhammer has no idea that vultures are appearing in its base because of a proxy and fails to defend effectively, but in this game an overlord accidentally scouted the factory and Steamhammer crushed the proxy brutally. It was a short step to scout on purpose.

• If the enemy has no mobile anti-air units (somewhat uncommon), then an overlord is assigned to watch the enemy natural. Further overlords are assigned to guard our bases against cloaked units, just as formerly. If the enemy has transport and does not have flying overlord hunters, the main base scouting pattern restarts to watch for drops. If the enemy still does not have mobile anti-air units (rare by the point there are enough overlords for it, but possible versus Stone, versus a persistent zealot rush, versus a zerg going zerglings, or very late in the game after the enemy’s army is wiped out) then overlords are assigned to watch every base on the map. As always, if there are flying overlord hunters then overlords congregate at spore colonies instead. There is a lot of room to make strides in overlord deployment; future Steamhammer versions will do things like find overlord perches where they can watch without being seen.

• The scout manager also controls its overlord somewhat differently. If an enemy turret, cannon, or spore colony appears in range of the overlord (generally when it is in the enemy base), then the overlord is immediately released from scouting duty. It is reassigned either to a combat squad or to the Overlord squad, and in either case attempts to safely make its way to a new destination. (I wanted to have it cruise around the edge of the enemy base to keep scouting, but it was too much for now.) Releasing the overlord loses scouting information, but losing the first overlord this early in the game is a severe setback and it was happening too often, so I think it’s the correct trade. If the overlord remains safe in the enemy base, however, it no longer sits still over the enemy resource depot but instead scouts the enemy base in a * pattern: It goes to the depot, then calls MapGrid::getLeastExploredNear() to find another place in the enemy base that it needs to look at, then returns to the depot, etc. That way it regularly revisits the most important spot, but also pokes into the corners of the enemy base so that it sees more.

• Squad overlords, or properly squad detectors since science vessels and observers are handled the same way, are also controlled slightly differently. The flying squad detectors have long had abilities to avoid dangers and seek out cloaked enemies, and they could try to protect themselves from air attackers by seeking friendly units that can shoot air. Now, rounding out their skills, they also try to protect themselves from ground attackers by seeking friendly units that can shoot ground. We’ll see how well it works!

building construction

Critical bug fix: It was possible for the building manager to accept a worker for a construction job while the worker manager believed that the worker was still available for other tasks. Ouchies. The worker was alternately given conflicting commands and achieved nothing. The building it was supposed to construct was hugely delayed or canceled, a game-risking error.

• When choosing a hatchery to morph into a lair, if possible choose a hatchery that is away from enemy units. For example, if there is a scout circling the main, start the lair in the natural where it won’t be seen right away. I wanted this to be a first step in denying and delaying information to the enemy. I wanted to also place other tech buildings out of enemy view when possible and safe (they’re constructed rather than morphed so it takes different code), but I didn’t have time. I did add UnitUtil::IsTechBuildingType() so that Steamhammer can distinguish tech buildings from other buildings (to also eventually be used in prioritizing buildings to destroy in an enemy base).

• Bug fix: When a worker was handed over to production manager or building manager to construct a building, for 1 frame it would be given 2 inconsistent commands, one from worker manager before the reassignment and one from the production manager (to move into position) or building manager (to start construction) after reassignment. I solved it by the simple expedient of running the production manager and building manager before the worker manager, being careful to comment the change so it is not later undone by mistake. The result is that the worker is able to follow its movement or construction command one frame earlier, so the building starts sooner by one Planck time.

• The production manager replaced a worker requisitioned for construction if the worker was locked down, stasised, or maelstrommed before it could be handed off to the building manager. Now that workers often burrow for safety, it also replaces a worker which it finds to be burrowed. The building manager by oversight did not replace a worker which was rendered unable to build (only a worker that was killed). The oversight is fixed; now the building manager also recognizes lockdown and the others. Buildings should construct more reliably in the face of enemy interference.

• The worker manager’s setBuildWorker() no longer takes an unused building type argument. I should have gotten rid of that long ago.

plan recognizer

The plan recognizer work focuses on detecting early shenanigans by the opponent so that Steamhammer can react in time this game, or failing that, choose a safer opening next game.

Recognize an enemy Contain opening plan distinct from the Proxy plan. The details of what counts as Proxy are changed accordingly. The general idea is that a proxy requires an immediate forceful reaction, while a contain should be dealt with more deliberately. This means that the configuration file can include Counter Contain openings which are different from the Counter Proxy openings (see the new openings below). Zerg also reacts somewhat differently in the two cases (see the zerg section).

• The code to recognize a proxy is moved from Bases to OpponentPlan where it belongs, and combined with the code to recognize a contain.

• There was a crashing bug in recognizing a proxy on a map where our starting base had no natural base. Every starting location on every competitive map has a natural, so the bug never occurred. But it’s fixed.

• Do not recognize a gas steal as a proxy. Oops.

• A nearby enemy forge implies that cannons are coming; there is no other reason to build a forge in or near the enemy base. (Well, theoretically it could be part of a wall, but what the wall be for? MadMixP and Steamhammer itself as protoss both do proxy forge into cannons sometimes.) Recognize a proxy forge as a Contain plan. This is not always strictly correct; sometimes the predicted cannons would be better recognized as Proxy. But good enough.

Enemy Fast rush and Worker rush plans are recognized more accurately by using building completion times (see when will that enemy building complete?) and unit travel times (by shortest-distance ground paths—I did mention that Steamhammer has all the parts for pathfinding except actually following paths) to better constrain the true timing of events. I always meant to do this, and now I’ve gotten around to it. The work includes tuning the time limits (“earlier than this is a rush”) based on timing the slowest builds that I want to count as fast rushes, versus the fastest builds that I don’t want to count.

• There was a potential crashing bug in recognizing a rush. I don’t think it ever happened, and now the bug is fixed so it won’t.

Explicitly recognize terran BBS as Fast rush. It was a loophole. Steamhammer might fly its first overlord directly over 2 center barracks... and fail to react, and lose. That won’t happen any more.

Recognize a new Wraith opening plan so that Steamhammer is less often caught off guard by 2-port wraith openings. This gives a chance to react earlier to incoming wraiths and lets you configure Counter Wraith openings. Steamhammer is not reliable at recognizing wraith openings before the wraiths show up, though, because its scouting and plan inference are not good enough. I wanted to improve that, but ran out of time. Steamhammer’s anti-factory hydra-first openings are intended to protect against wraith attack but are not successful in practice because AI-controlled wraiths outmicro the hydras, which don’t have either speed or range yet. A hydralisk needs its range upgrade to equal the weapon range of a wraith.

bases

Always unreserve tiles of a base we failed to take. Formerly, sometimes the base would remain reserved and could never be taken. On the one hand, that was a severe weakness. On the other hand, it created adaptivity in choosing the next base to take; repeatedly failing to take the same base over and over is not a winning plan.

Avoid taking a base where enemy units are thought to be. This is a cheap way to add back some of the adaptivity lost by the previous change. Steamhammer does nevertheless sometimes show perseveration in failing to take a base. The next step, for a future version, is to check the path a worker will take to reach the base, and only accept paths that seem safe.

The “front line” position of each base is smarter. The front line is where static defense is positioned when Steamhammer wants to defend the approaches to the base. (It may also place static defense directly next to the resource depot if it wants to defend the mineral line specifically. It depends on the goal.) The front line is now on the shortest outside ground path toward the base, which I figure is the path an enemy bot is most likely to send its attackers along. Compared to the previous calculation, the new front is much better on some maps (like Benzene and Roadkill) and slightly worse on others (like the top base of Destination, though not the bottom base). It’s a net gain.

A zerg base doesn’t become the “front base” until it completes, because zerg needs creep to build. The front base is where the main approach static defense goes; it is the natural base if the natural is taken. Formerly, Steamhammer might place defenses in the main because there was a hatchery morphing in the natural and the main was where it was able to build—yeesh. For terran and protoss, the natural need only be started.

Don’t try to take an enemy base as a hidden base. If the enemy has not been found yet, and we need to choose an expansion as a hidden base, do not choose any main or natural base (unless that’s all there is), because it might be the enemy’s and that would suck. This is critical if the enemy is following a Contain plan, because then we will try to take a hidden base early without scouting.

• Make a stronger attempt to expand toward the edges, leaving central bases for later. The code proudly flaunts it as a big change, but it is not particularly successful; Steamhammer still likes bases in the open middle on maps like Aztec and Fortress. I probably have to bite the bullet and do the tactical analysis of the ease of approach and the width of the attacking front to figure out how vulnerable a base is.

• Fixed: The global pointer “what is my natural?” and the local pointers “what is the natural of this main base?” might be inconsistent. I don’t know what the effects of that were, but it couldn’t be anything good. As part of correcting it, I simplified and improved the calculation of natural bases. Also, each Base object (each base on the map) now includes a backpointer to its main base if it is the natural of some main (or null if not). It makes some calculations easier.

• Fixed: There was a crashing bug that affected maps on which every base which had minerals was a starting base. That’s very rare, but Crystallis is an example. Though I doubt any bot can play a reasonable game on Crystallis....

squads

Don’t assign base defenders against nearby cannons. This is part of the system to defeat cannon rushes: Combat units should go destroy the enemy base instead, which some of them should be able to do if a zerg hidden base was created as planned. The system doesn’t work perfectly, and sometimes Steamhammer wants to attack the proxy anyway because defenders are still assigned to attack the proxy pylons and any other buildings that may be part of the proxy. But most of the time it works well for a cheap hack.

• The hysteresis in distance for unassigning base defenders is increased. The main visible effect is that an enemy scouting worker has to run farther away before the single zergling assigned to catch it gives up and heads away.

• The Watch squad no longer assigns overlords to watch bases to catch enemy activity. The Overlord squad is responsible for that now; see above.

• I tried adjusting the regroup position (aka retreat point) of Steamhammer units that retreat toward static defense. It didn’t really help.

other infrastructure

• The movement routines in the Micro module check their arguments and drop movement commands for illegal destinations outside the map bounds. After an arduous campaign, I have finally fixed all the diverse callers so that they do not issue those commands in the first place. In long tests, the error checks were never triggered.

InformationManager::getUnitInfo() fetches the UnitInfo for a single unit (recording where and when an enemy was last seen, among other data). I never needed it before; in the past, Steamhammer only wanted to iterate through all unit info records.

• Due to an error in interpreting the configuration file, AbsoluteMaxWorkers always had its default value of 75, ignoring what the config file said. Fixed.

• The code for UnitUtil::GetUncompletedUnitCount() is simplified. Now it simply subtracts the already-computed completed unit count from the already-computed total unit count.

other worker behaviors

When a worker is posted to a location, it remembers not only its macro location as it used to, but its actual map location, and stays there. This is part of the system for taking hidden bases: When you go post worker @ hidden the “hidden” location differs depending on where the enemy base is. When we take a hidden base to counter a Contain plan, we may post the worker before the enemy base is found. If we find the enemy base before starting the hidden hatchery, the map location corresponding to the macro location changes, and at first the drone would waste time and take unnecessary risk moving across the map. Now the worker stays put at the original map location and the hidden base is taken safely and on time.

• When a worker is posted to a location using go post worker @ it first returns any minerals or gas it was carrying. A tiny mining efficiency tweak.

• Steamhammer can mine out blocking mineral patches with non-zero mineral amounts. Not many maps have those, but it was a two-line change that makes more maps playable. The code to mine out the more common zero-amount blocking mineral patches, as seen on Destination and Heartbreak Ridge, has been in there for a while. (There is still no code to break down blocking buildings as on Benzene.)

ranged unit kiting

In my mind this is one change with several parts to the code, but the effects vary depending on the ranged unit. For one thing, air units and ground units kite differently because ground units have to worry about terrain or other units getting in the way. For another, Steamhammer kites what it calls “AlwaysKite” units (not a good name since they don’t in fact always kite) with different code than others. The AlwaysKite unit types are set by Micro::AlwaysKite() and are vultures, wraiths, and mutalisks—fast units with instant acceleration—plus guardians. (By the way, the rate of change of acceleration is called “jerk” so instant acceleration means infinite jerk: those units are infinite jerks.) The AlwaysKite units use “muta dance” kiting code which pays closer attention to timing and latency than the regular kiting code, so that kiting is more precise and takes advantage of the instant acceleration.

• A suite of new routines appeared in the Micro module, for use both in kiting handled inside Micro and by other unit control code as needed. For kiting, the key ones are kiteBack() for kiting regular units, and the more generic fleeEnemy() used for AlwaysKite units.

kiteBack() for regular units considers alternate kiting destinations if the first try doesn’t pan out, according to checks I list below. The effect is that if a unit cannot or should not kite directly backward, it may go diagonally backward or sideways. A unit that is unable to kite away will realize it and keep shooting in place.

• Regular units, air or ground, don’t kite into enemy static defense range. If they’re already in range, they don’t kite deeper into enemy static defense range—the check counts the number of attacks on a prospective kiting destination and rejects it if the prospective count is higher than the current count. It’s relatively rare to fail this check; units are not often backed up against enemy static defense.

• Regular ground units do not kite into terrain.

• Regular ground units do not kite into a tile occupied by any other ground unit, whether a mobile unit or a building. The check is conservative: You might be able to squeeze in there if it fails, but if it succeeds you can definitely go there.

For zerg, the changes primarily affect hydralisks. Hydras used to kite into terrain or into each other as an everyday matter, with the result that they would turn away from the enemy, fail to move because they were blocked, fail to shoot because they were trying to move, and generally be useless and die in vain. To me it was a raging unmissable micro blunder that left hydralisk potential bleeding on the ground. Sideways kiting helps hydras keep moving and spread out so that more of them can fire. Hydras still often get backed up to where they can’t kite, but now they know that they can’t kite and they keep shooting. Hydras do more firing and less dying in battles of every scale, for battles in which kiting happens (Steamhammer units kite only when they expect a benefit). To me it is particularly obvious in small-scale hydra versus zealot fights, which are visibly more efficient.

• The AlwaysKite units don’t do the above checks, but call fleeEnemy() which unconditionally moves away, making sure only that it stays within the map bounds. Slightly complicated unimportant details follow. The muta dance code inherited from UAlbertaBot figures where to kite back to using a function called GetKiteVector() which starts with a point to move away from and calculates the destination by trigonometry. It returns an offset from the kiting unit; add the offset to the kiting unit’s position to get the destination. At some point I apparently mistook the offset for an absolute position and clipped the offset to the map bounds, a teeny-tiny gargantuan boo-boo (the effects on kiting were not severe in practice). More recently, Steamhammer added a function DistanceAndDirection() which, though I didn’t notice it at the time, does the same calculation by the mathematically equivalent method of normalizing the offset vector to length 1 then multiplying it by a scalar. Though it doesn’t make a practical difference in games, the vector math runs much faster than the trig functions, so here is an example of the optimization technique of strength reduction. In working on kiting I noticed the overlap. After undoing the mistaken clipping, I verified by test that the two routines returned identical results to the pixel. Following the motto that strength reduction makes you stronger, I removed GetKiteVector() in favor of fleeEnemy() with the same behavior and less code. By the way, it could be that kiteBack() would be more effective, especially for vultures. It does support air units. I didn’t try it yet.

zerg

Place a sunken to stop a cannon push. If photon cannons are dangerously near one of our bases, place exactly one sunken to prevent them from creeping closer; set it as close as possible outside the range of already completed cannons. This stops most approaching cannon pushes in their tracks. It may be possible for the cannons to circle around outside the sunken’s range and push in regardless, but I’ve only seen that once. The calculation of the cannon’s range is not exact, and on rare occasions the sunken is placed too close, which leads to suicidal placing of the same sunken over and over.

Place a sunken to combat a bunker attempt. If the enemy has built a bunker near a base of ours, try to set a sunken where it can hit the bunker and the bunker cannot hit it. Again, the calculation is not exact and occasionally the sunken is too close (it’s usually good, and I’ve never seen it too far to hit). Also, by the time the sunken is up generally the terran has marines on site, and with good play the marines may kill the drone, or may kill the sunken before it can finish. It won’t just happen; terran has to play well, and zerg should smash clumsy bunker attempts. If the sunken does finish, the bunker play will normally fail and terran will be behind; even if terran kills the natural hatchery, zerg will be comfortably ahead because of the cost of the early barracks plus bunker. (Seriously! I’ve seen it repeatedly versus Halo by Hao Pan.) I concluded that the old school sunken is Steamhammer’s best defense for now, though it’s not the best possible defense. The modern standard way to defeat an early offensive bunker is to pull drones to prevent the bunker from finishing, or prevent marines from getting in. Steamhammer doesn’t have the micro skills yet.

• When placing its one-sunken-per-base to defend against raids by vultures or dark templar, Steamhammer normally places the sunken next to the hatchery to defend the mineral line. In a change, if the base is the natural of some main base, it places the sunken at the front line position instead. That way the sunken provides some protection to both the natural and the main behind it, and if later sunkens are placed then they will also be at the front line and reinforce each other.

Hide a drone on the map versus Contain or Proxy plans by the enemy, and when it is next time to make a hatchery, let it be a hatchery at a hidden base. This is a reaction to a recognized plan: The openings for Counter Contain make a hidden base while the openings for Counter Proxy do not, but the reactions to both call for a hidden base. If there is a scout drone out at the time, then it abandons its scouting mission and hides on the map; otherwise a fresh drone is sent out (which is riskier because it may be caught by, say, containing cannons). Versus Contain, Steamhammer continues its planned opening; versus Proxy it breaks out of the opening unless an early pool is already queued, so that it can react decisively. There remains a weakness versus early bunkers: If Steamhammer scouts the barracks first, it may recognize the plan as a fast rush, in which case it will not update the recognized plan after the bunker starts, and will react differently than intended.

Scourge no longer attack floating buildings. This is a fix for a regression. Wasting gas to set a floating ebay afire is an effective way to suffer.

• If an enemy Wraith plan is recognized, make an evolution chamber right away. Before the Wraith plan was added, Steamhammer waited until it actually saw a wraith. Now it at least has a chance to react in time to 2-port wraiths.

• Unit mix adjustments: If the enemy cannoned us in, favor hydras much more. Vultures more strongly contraindicate zerglings. Versus protoss, favor mutas more; Steamhammer was barely making any after the opening, sometimes building a spire and never using it. Protoss air units more strongly discourage guardians; it was too common to see the guardians countered by corsairs.

• Unit mix in the cleanup phase of the game: If all enemy buildings are unreachable by ground, prefer air units. This could mean the enemy has an island base, or it dropped buildings on a plateau, or its buildings are floating over water. This rule doesn’t outright require air units, because the enemy may still have an army in play.

• Be slightly slower in some cases to take the second gas. It’s a tiny step.

• A regression prevented Spawn Broodlings from being researched, so the skill was never used. Fixed. Tanks or high templar may find themselves abruptly dead.

• In a rare ZvZ where the enemy has lurkers or ultralisks, be quicker with broodling research and prefer a higher number of queens. Queens versus ultralisks = advantage queens. It’s fun to be ready with a correct reaction to a rare situation. Steamhammer has played some successful and entertaining games by being more ready than its opponents for unusual events like hive-tech ZvZ.

• If the enemy is attacking on the ground and you happen to have extra minerals and larvas on hand, then maybe, just maybe, you should make zerglings instead of drones. In fact, I insist on it. You probably didn’t scout the full size of the enemy army. Make zerglings, dammit!

• If we’re in the opening and we have reacted to the enemy’s build by adding more drones than planned, and we’re nevertheless in a situation where there is a mineral shortage and a gas excess, then do not spend one of the extra drones to make an extra extractor. That normal Steamhammer reaction does not make sense in context. This improvement may prevent only a few mistakes over the course of the tournament, but some mistakes are too ridiculous and have to be prevented.

• Steamhammer zerg normally breaks out of its opening if it faces a fast rush that the chosen opening does not already counter. Steamhammer now considers that its 7- and 8-drone dawn hydra rushes counter an enemy fast rush. The change has saved games in test versions.

• If there aren’t “enough” drones, then when adding static defense Steamhammer zerg replaces each drone as it is used up. It’s necessary to prevent emergency defenses from wiping out the economy. I decreased the limit of “enough drones” so that Steamhammer can bring up defenses faster in some midgame situations.

• When looking around a base to see whether it is adequately defended by sunkens, the radius is decreased for considering a sunken as defending the base. It’s a tweak.

• Steamhammer is slightly more cautious about morphing a sunken that will be weak when it is finished. Another tweak.

• The code to place a sunken to defend against vulture or DT raids forgot to check whether we have a spawning pool. Fixed. Other checks in the code would have prevented the error from causing incorrect commands if it ever came up, but it could have caused inefficient play during an emergency.

openings

I made 3 Counter Contain builds to defeat cannon contains and other early containment attempts. They work by starting a hidden base elsewhere on the map, so that units can be produced outside the contain: 6PoolHide 9PoolHide OverpoolHide. Contains still cause Steamhammer to misbehave because it assumes that units can safely walk past (they can’t fight their way past, but walking is different), so the openings don’t work perfectly. But combat units produced outside do usually prefer to find and attack the enemy main first, so it’s a great advance over former behavior.

• The openings I hoped would have a chance against Stardust are 10HatchLing+1, Over10Hatch+1, and Over10HatchHydra. They are all-in builds. The few Steamhammer wins over Stardust so far are due to zergling attacks after Stardust messes up, so I made 2 zergling openings with what I guessed to be good timing. Every Steamhammer win so far has been by a different opening, and neither of these was able to score—they might be as good as anything. The hydra build is one suggested by Jealous in an SSCAIT weekly broadcast. I didn’t really expect it to work and it didn’t, but it was worth a try, and besides, the opening has value for other purposes.

AntiWraith_2Hatch is configured as a Counter Wraith build. It makes an evolution chamber in time to get spores, and goes 2 hatch muta.

AntiFact_Overpool11Hatch is an additional anti-factory mutalisk opening. By opening with overpool it hopes to intimidate the terran into playing too defensively against possible early zerglings. In fact, it makes few lings and aims for 2 hatch muta.

2.5HatchMutaExpo is a variation of the existing 2.5 hatch muta build (2 hatch muta plus a later third hatchery), which adds the third hatchery at an expansion rather than in the main. The original version stuck to 2 bases because it struggled to place the third base on the 2-player SSCAIT maps. That weakness is mostly solved, so it’s time to play the build right.

• Steamhammer doesn’t defeat ZZZKBot as consistently as it should, because Steamhammer is weak at defense. (Microwave is good at defense and wipes the floor with ZZZKBot. “You are my mop!”) Falling back on a quick fix, I tried writing openings. 9PoolHatchSpeedSpire2 as written is too slow to beat the 4 pool. 9PoolHatchSpire is good and should beat all ZZZKBot builds, but Steamhammer still isn’t consistent, only getting about 80% wins in the latest test. A quick fix is not enough, Steamhammer needs the actual skills.

debugging

• Clarified the wording in the building manager’s debug display. The construction status strings were kind of cryptic.

• A meaningless yellow square is no longer drawn in the upper left of the map. It was a leftover code snippet from old debugging. It took me a couple searches through the code to find it.

Next: About Steamhammer’s tournament prep learning files.

Steamhammer is submitted

I submitted Steamhammer to AIIDE 2020, a day ahead of the deadline. I don’t believe in working right up to the limit and risking last-minute bugs, better to turn out a stable version. As it was I did suffer a late bug introduced by an attempted fix, but fortunately it was easy to detect: I knew something was wrong when I noticed 3 spawning pools and 2 spires in the base. It was caused by a tricky race condition, but when I looked back at my change, my familiarity with the code let me see the problem immediately, and I knew how to correct it. I ran long tests after that and found nothing more. The new behaviors have zero known bugs (so I expect to learn something!), though of course they have limitations.

I’m feeling a little paranoid because in double- and triple-checking I discovered a couple mistakes in my submission zip and had to correct them. One was carried over from last year—I had a wrong filename in one line of the README instructions. Luckily for last year, the instructions were clear enough anyway. Actually, triple-checking is an understatement. Some points I verified four times. I ought to feel secure that I got it right.

The version is 3.2.19. Everyone memorize that version number, there will be a quiz. The next step for me is to prepare the change list so I can post it on 1 October. It may take me that long to write it up.

Steamhammer prep for AIIDE

With a couple days left to the deadline, I’m making final preparations for Steamhammer in AIIDE 2020. All the new behaviors are coded and tuned, as best possible. Mostly I’m making final tests and fixing remaining bugs. New code was written to have low risk of bad side effects, has been carefully tested, and seems to have few bugs. I have identified a couple of existing bugs, formerly unseen or unimportant, that are awakened by the changes.

I always wish I could have done more, but I’m happy enough with the improvements. I worked much harder than I have in the past year, when I was distracted by other business. Many long-time weaknesses are finally addressed. Ridicubad midgame play is slashed (and maybe I can do something about the remaining horrors before SSCAIT). Win rates are strongly up against some opponents (though Stardust remains out of reach). Microwave had pulled ahead of Steamhammer lately after months of Steamhammer dominance, but now I see them neck-and-neck rivals. Either might finish ahead in the tournament.

Expect upload to SSCAIT on 1 October, followed shortly by source release. The change list is long. I ran through about 20 test versions.

Steamhammer island plans

Among many other aspirations, I’ve always wanted Steamhammer to be able to take island bases. It’s not quite time yet, but getting closer. Here is my outline plan, with steps in order:

• BWAPI 4.4.0 helps make drop research practical. BWAPI 4.1.2 has a bug that prevents research in a hive.

• Pathfinding. Pathfinding is... on the critical path, according to my plan. The current release version of Steamhammer already has all the parts needed for pathfinding, except the final step of actually following paths.

• Nydus canals—with pathfinding support, because nydus is useless without. By hive tech time when nydus becomes available, nydus is cheap and valuable. If nothing else, Steamhammer would benefit hugely from transferring drones between distant bases without sending them through the center. In fact, if you have a hive and have drones to transfer far away, it’s normally better to hold the drones until you can get a nydus up. They are likely to get there just as soon, and more safely.

• Take island bases after hive, and nydus them up. Transferring units to and from islands by nydus is far simpler than transporting them by overlord. Given pathfinding, the regular base defense squads can defend islands with no extra code. The only drawback is that if the nydus is lost and the hive is destroyed so that the nydus can’t be replaced, then units will be stranded. But then, if the hive is gone we’re probably losing anyway.

It’s also possible to take an island before hive, and nydus it up later. The island will drone itself up slowly and struggle to defend itself before nydus, and drones will have nowhere to run from an attack, but if the enemy has no air units it may be worth it.

Many current bots do not scout islands. I’ve seen that in Ecgberht games; it can build island bases, though it doesn’t mine them efficiently (at least that I’ve seen)—it may lose a game on points with only an island surviving. A bot that’s good at islands might force other bots to adapt.

At some time in the more distant future I’ll add general overlord transport skills, so that Steamhammer can do mass drops, bypass contains, and fight with ground units on island maps.

a few items

I am working furiously on Steamhammer, not leaving myself much time for posting. The version I submit for AIIDE should be substantially stronger than the current release version, with visible changes that close observers will notice.

I doubt it will have much chance versus Stardust, though. After watching games where Stardust lost, I wrote 3 new openings to try to exploit its weaknesses, to at least make a dent. One was the hydra opening that Jealous suggested in a cast. But no, a rubber ball does not make a dent in a concrete wall.

A new bot EggBot appeared on the AIIDE 2020 participant list at some point after I wrote up the participants. I guess it must have been omitted by mistake. It is by Nathan MacNeil of the Memorial University of Newfoundland (Dave Churchill’s institution), who is apparently a graduate student. A grad student should have an interesting project in mind, so I have hopes for EggBot—weak or strong, I hope it will be interesting.

I still want to post about encouraging new bot authors, but you can tell it’s not my actual priority because I’m spending my time on coding and testing instead. Still, it’s an important discussion. The addition of S A B C D E F ranks on the BASIL rankings could be a good step if it encourages new authors to make progress: “I want to move up to D!”

tournaments and tournament preparation

The CoG conference is underway from today through Thursday. It is of course entirely online in this plague year (did somebody let a defiler loose?). I expect the CoG 2020 tournament results to appear during the conference or not long after. The conference program does not announce a time, as far as I can see. You can look back at my expectations if you like.

I am working hard to prepare Steamhammer for AIIDE 2020. I have already uploaded 3 different test versions one after another to the Starcraft AI Ladder, and I have made good progress on the next test version to go up in a day or two. Each version shows some kind of progress in its play, though the win rate does not always go up. The AIIDE update will be much bigger than the update to the current 3.1 release.

I have been watching a huge number of replays and analyzing results with my software. The purple Dan Gant talked in an Undermind podcast about his tournament preparation process: He examines losing games only, identifies the most frequent game-losing weaknesses, and works to fix those. It’s great method, a direct way to improve tournament results in the short term, especially for a bot which can expect to finish near the top, meaning that it shows relatively rare game-losing weaknesses at its level of play. My goal is different, and I follow a different process. I also want to finish well, and make low-risk short-term improvements, but my top goal is to improve play in the long run rather than the short run. I identify ahead of time aspects of play that I think I can and must improve, and I examine both winning and losing games with an eye on those aspects, often looking at specific opponents that bring out those aspects. The weaknesses in winning games must be fixed too; they are by definition not game-losing, but fixing weaknesses improves play and that’s that, and to my eye winning games often show glaring blunders by Steamhammer. Anyway, at Steamhammer’s level of play, fixing a game-losing weakness often leads it to go wrong in a different way a little later and lose anyhow, so I may have to fix a string of weaknesses before I see results. Those are compound weaknesses, as it were, and I run into a lot of them.

I have learned some things by analyzing the ladder results with my software. One of the things I learned is that I could figure out even more if I wrote more software, and if I had Steamhammer record more information that I could correlate with the game results. I may do that soon, and post data.

The Ladder has new participants since I last wrote about it. Besides Stardust, MadMixP is new and StyxZ is reactivated. Just today, CherryPi joined too. That makes 11 active participants, enough for a small but lively scene. I still recommend joining the ladder if you intend to compete in AIIDE 2020, because it is the best way to test that your bot runs correctly in the AIIDE environment, adhering to the strict time limits and so on. Just letting it run for a day is enough to test for basic correctness (the ladder runs games much faster than BASIL), and if you have a problem you want to find out about it early so there’s time to fix it.

Steamhammer update

SSCAIT’s web site is back up, though so far it doesn’t seem to be playing games. (Is this the service being moved to its new home?) I uploaded Steamhammer 3.1 there as soon as I saw. It should pass through to BASIL as usual.

I’m pleased with 3.1’s performance on the Starcraft AI Ladder. It was a small update, and the win rate went up by a small but consistent amount. If that holds on BASIL too (I expect it will), then Steamhammer stands a good chance of overtaking Microwave, which just recently stole the top zerg crown. Steamhammer and Microwave have been swapping top zerg honors for a long time now.

Stardust has joined the Starcraft AI Ladder with a 93% win rate, pushing everybody else’s win percentages down. That’s good. But with few participants and those changing over time, it’s difficult to check progress week to week; you can’t simply compare your win rate this week to your win rate last week. Maybe at the end of the week I’ll calculate elo ratings.

Steamhammer has suffered a regression: Scourge has mysteriously started to target floating buildings again, a mistake that I originally fixed long ago. Somewhere bits have decayed.

Steamhammer 3.2 and up

Steamhammer 3.1 is no longer running on the Starcraft AI Ladder; I already uploaded a version I called 3.2. I decided that the plan is to leave Steamhammer 3.1 on SSCAIT and BASIL until after the AIIDE submission deadline, and upload frequent test versions to the eponymous Ladder (as opposed to the ladders with other names). They’ll be called 3.2, 3.2.1, and so on, so the AIIDE 2020 version will be 3.2.something.

I won’t be going into detail yet, but 3.2 has 3 changes. 2 are the cheese responses, and if they’re successful you won’t often see them because opponents will learn better. The other you won’t see at all: I lifted the limitation which made Steamhammer unable to mine out blocking mineral patches which contain a non-zero amount of minerals. Once I looked at it, I realized it was only 2 lines of code, trivial to write and easy to test. None of the ladder maps (for any of the ladders), and none of the AIIDE 2020 maps, has blocking minerals like that; all their mineral blocks are stacked 0-mineral patches. But there will be another “unknown maps” contest at AIIDE, and maybe one of those maps will.

I tested on Sin Peaks of Baekdu, by the way, which has mineral patches with 40 minerals to block a useful path next to each main. The difference between stacked 0-mineral patches and single small mineral patches is usually not important to the player; you have to return the minerals you mined, which eats frames, but the blocks are normally close and have few minerals so it’s not many trips. But if the opponent wants to mine out the block to attack you, it’s a different story. Stacked o-mineral patches can be mined out in one go by sending one worker for each patch in the stack (mining out all patches in the stack simultaneously), so it can allow early-game cheese. The single mineral patch has to be mined out 8 minerals at a time, so the prospective cheese victim has more opportunity to react.

The sunken defense of outlying bases in Steamhammer 3.1 has the effect of keeping drones alive and allowing it to play its favorite macro game. Not that Steamhammer is feeble at fast rushes, but in the late game once it has all the drones it wants it rarely loses. Cheese defenses also discourage the opponent from trying to win fast, and allow Steamhammer to select macro openings more safely. Against Halo by Hao Pan, Steamhammer has been favoring one-base muta play, which can defeat both Halo’s bunker rush and its 2-port wraith strategy (it’s amazing to watch mutas and scourge pummel the 2-port wraiths—soon cloaked—with less than half of terran’s worker count). In fact, Steamhammer prefers pool-first builds against a surprising number of opponents. My hope is to tighten the early game and get a big economy more often.