archive by month
Skip to content

Steamhammer in SSCAIT 2021

Games for SSCAIT 2021 will be starting any time now. Meanwhile, I have been working on an unrelated project which is well over half complete.

Steamhammer has participated in SSCAIT every year since 2016. This year makes six. Steamhammer finished at #11 in 2018, #11 in 2019, #11 in 2020. This year will be the first time Steamhammer has played without any special preparation or last-minute fixes. I expect it to finish at... #11, maybe a little better. If I had worked on it in the runup, it would have had a good chance to finish in the top half, because I’m at a point where big improvements are possible. I didn’t, but Steamhammer is still in good shape to finish as well as it has in past years.

Anyway, the proof is in the pudding. Let’s go!

AIIDE 2021 - what Steamhammer learned

The submitted Steamhammer was mistakenly configured to retain 100 game records per opponent. I had thought it was set for 200, and didn’t double-check. So of the 157 games against each opponent, of which 150 counted in the tournament, I have records for only the final 100. That’s 93 tournament games plus the 7 extra at the end.

My prepared data was successful. For all opponents which I prepared for, the prepared openings were among the highest scoring (including the zero score versus Stardust). It’s notable that Steamhammer’s gas steal was not successful against any opponent, perhaps another sign of an elite tournament. It was either infeasible or abandoned as a failure against every opponent except DaQin, and did no good then.

Steamhammer’s game records are rich with data. To show a little bit more of it, I added a new feature in the opening table. There are new “wins” and “losses” columns showing the median time that winning and losing games with that opening lasted. The median is a better measure than the mean, because we can expect the distribution of game times to be right-tailed: Games are limited to between zero minutes and one hour, but we expect a hump nearer to zero and a long tail of slower games. That inflates the mean and makes it misleading. For the tournament, I turned off surrendering, so Steamhammer played its losses out to the end.


#1 stardust

openinggameswinswinslossesfirstlast
10Hatch10%-8:484848
10HatchHydra10%-8:414545
11HatchTurtleHydra30%-10:331456
11HatchTurtleMuta30%-10:401067
11Pool10%-8:487474
12Gas11PoolMuta10%-6:536060
12Hatch_4HatchLing10%-14:082525
2HatchLurkerAllIn10%-9:126565
2x10Hatch10%-8:309595
2x10HatchBurrow10%-9:215555
3HatchHydraExpo40%-8:032386
3HatchLateHydras10%-7:4399
3HatchLing10%-7:545151
3HatchLingBurrow10%-8:317171
3HatchLingExpo20%-8:43637
4HatchBeforeLair10%-7:394747
4PoolSoft10%-8:266868
6Pool20%-9:127592
6PoolHide10%-8:351717
6PoolSpeed60%-8:27385
7DroneGas10%-7:518080
7Pool10Hatch10%-8:168383
7Pool12Hatch10%-8:365050
7Pool6GasLurker B10%-9:384444
7PoolHard10%-14:074141
7PoolHarder10%-8:237676
7PoolMid10%-8:038989
7PoolSoft10%-13:094242
8Hatch7PoolBurrow10%-9:476464
8Hatch7PoolBurrowB10%-8:2355
8Scout10%-8:148787
9HatchExpo9Pool9Gas20%-8:291694
9Pool8Hatch10%-8:179898
9Pool9Hatch10%-10:297070
9PoolBurrow10%-9:348484
9PoolBurrowB10%-8:0744
9PoolHatchSpeed7Drone20%-7:583173
9PoolHatchSpeed7DroneB20%-8:01024
9PoolHatchSpeedAllInB10%-8:412222
9PoolLair10%-7:369999
9PoolLurker10%-9:412727
9PoolSpeed20%-9:03826
9PoolSpire10%-9:033232
9PoolSunkSpeed10%-7:417979
AntiFact_13Pool10%-8:175454
AntiFact_2Hatch30%-7:396993
AntiFactoryHydra10%-7:086363
AntiZeal_12Hatch30%-10:203377
HiveRush10%-6:503030
Over10Hatch20%-10:071534
Over10Hatch1Sunk10%-8:359696
Over10Hatch2Sunk30%-10:33188
Over10Hatch2SunkHard10%-9:154646
Over10HatchBust20%-8:211849
Over10HatchSlowLings20%-8:236178
OverhatchExpoLing10%-8:301313
OverhatchLing10%-10:255858
Overpool14Hatch10%-7:3977
Overpool2HatchLurker20%-9:064382
OverpoolLurker10%-8:487272
OverpoolTurtle 010%-8:3222
Overpool_3HatchLing10%-10:292020
PurpleSwarmBuild10%-8:086666
ZvP_2HatchMuta20%-7:553897
ZvP_Overpool3Hatch10%-8:162929
ZvT_13Pool20%-9:185791
ZvT_7Pool10%-8:308181
ZvZ_12Pool10%-7:015353
ZvZ_Overpool11Gas10%-7:503535
ZvZ_Overpool9Gas10%-7:471919
70 openings1000% - 8:30
planpredictedrecognizedaccuracy
countgameswinscountgameswinsgood?
Heavy rush100100%0%4040%0%40%58%
Naked expand--22%0%0%0%
Unknown--5858%0%0%0%
timing#medianearlylate
my combat unit1002:541:474:11
my gas993:171:347:33
enemy scout1001:571:187:53
enemy combat unit1002:412:214:37
enemy gas1004:203:376:37
enemy air unit99:428:3011:09
enemy cloaked unit89:439:1411:09
game duration1008:306:5018:12
gas steal#medianearlylatewinsenemy gas
gas steal decision102:121:582:210%4:22
gas steal success62:152:032:310%4:32
none or failed94---0%4:17
gas steal killed62:472:422:58


Steamhammer lost every game, but there is still valuable info here. If you’re losing all games, the game duration is a plausible proxy for how much trouble you caused the opponent. Especially so if you tried a rush opening and ended up in a long game—either the rush did some damage, or the opponent overreacted and was slowed down. Here, a couple of 7 pool builds were among the longest games. Steamhammer probably should have repeated them.

Notice the 4 pool and the hive rush. Steamhammer tried the whole range. Steamhammer recognized Stardust’s build in 2 games as nexus without cannons, a reaction that Stardust did not have last year. Otherwise, results are similar to last year’s.


#2 bananabrain

openinggameswinswinslossesfirstlast
11Gas10PoolMuta10%-6:043333
11Gas10PoolMutaB10%-6:215656
11HatchTurtleLurker1553%15:329:437198
11Pool10%-14:481010
12-11HatchStem10%-16:347878
2x10HatchSlow70%-8:30495
3HatchHydra10%-12:204242
3HatchLingBurrow10%-14:001919
4PoolSoft10%-7:557474
6Scout10%-8:486666
9Hatch8Pool10%-6:126969
9PoolBurrow812%16:2912:534382
9PoolHatchSpeed7DroneB10%-10:2611
9PoolHatchSpeedAllIn520%9:496:515868
9PoolHatchSpeedSpire80%-7:21399
9PoolHatchSpeedSpire210%-7:021515
9PoolSpeed10%-11:011414
9PoolSpeedAllIn10%-13:021616
9PoolSunkHatch10%-11:502828
AntiFact_Overpool11Hatch10%-13:189393
AntiZeal_12Hatch10%-7:482626
Over10Hatch1Sunk10%-15:104747
Over10Hatch2Sunk10%-14:382727
Over10Hatch2SunkHard10%-16:033636
Over10HatchHydra10%-10:353838
Overgas+110%-13:188585
OverhatchExpoLing1118%7:3414:512483
OverpoolLurker10%-6:156161
OverpoolTurtle617%15:0115:591796
ZvP_3HatchPoolHydra157%18:188:27270
ZvT_3HatchMuta10%-15:2700
ZvZ_12HatchMain10%-15:2366
ZvZ_12Pool10%-6:393131
33 openings10014% 15:24 10:42
planpredictedrecognizedaccuracy
countgameswinscountgameswinsgood?
Fast rush22%0%1111%0%0%50%
Heavy rush9797%14%6363%13%63%22%
Safe expand11%0%33%67%0%0%
Turtle--11%0%0%0%
Unknown--2222%18%0%0%
timing#medianearlylate
my combat unit1003:031:474:38
my gas932:571:337:14
enemy scout1002:101:155:03
enemy combat unit1002:402:185:47
enemy gas946:053:169:12
enemy air unit916:073:1711:33
enemy cloaked unit579:266:0614:59
game duration10011:456:0421:43
gas steal#medianearlylatewinsenemy gas
gas steal decision102:301:513:3310%5:42
gas steal success32:101:552:110%4:22
none or failed97---14%6:07
gas steal killed32:502:482:51


In the 150 tournament games, Steamhammer scored 25 wins versus BananaBrain. Of those, 15 were due to BananaBrain suffering a frame timeout. Ouch. The game scores say that BananaBrain was ahead in 11 of the 15 games when it timed out. So the win percentages and times need to be interpreted carefully. The wins overall were longer games than the losses, possibly because BananaBrain was more likely to time out in a longer game with a larger game state to model and more units to control.

11HatchTurtleLurker scored over 50% in 15 games! Is it particularly good at prompting BananaBrain to time out? If I’d known about it ahead of time, I could have added it to my preparation and perhaps scored higher.

The build 2x10HatchSlow is shown as tried 7 times with no wins. I know from watching games that the opening scored wins earlier in the tournament, before the final 100 games; that is why it was tried so often later on. The build is very similar to Broken Horn’s 10 hatch-9 hatch-pool, but (I think) slightly more efficient. Apparently BananaBrain learned to avoid lines that lose to the mass of slow zerglings.

Successfully stealing its gas caused BananaBrain to take its gas sooner. I haven’t seen that before. In any case, it was only 3 games; Steamhammer found the gas steal unprofitable.


#3 dragon

openinggameswinswinslossesfirstlast
2HatchLurkerAllIn10%-30:514141
3HatchHydra10%-10:163333
5HatchPool2471%13:2328:23694
7-7HydraLingRush10%-16:574545
9PoolFastLurker933%9:1627:47192
9PoolHatchSpeed425%3:3116:321758
9PoolSunkSpeed20%-26:541438
AntiFact_13Pool1765%18:0516:345096
AntiZeal_12Hatch10%-38:541212
ZvP_4HatchPoolHydra862%5:5715:586599
ZvT_3HatchMutaExpo3278%15:5024:55098
11 openings10062% 15:36 25:13
planpredictedrecognizedaccuracy
countgameswinscountgameswinsgood?
Factory4141%56%1717%47%24%41%
Naked expand--44%50%0%0%
Safe expand2323%74%1515%80%9%48%
Turtle--11%0%0%0%
Unknown--3131%68%0%0%
Worker rush3636%61%3232%59%75%8%
timing#medianearlylate
my combat unit983:122:137:53
my gas803:491:3412:10
enemy scout982:110:5312:07
enemy combat unit822:482:218:38
enemy gas816:042:4410:40
enemy air unit749:394:3117:18
enemy cloaked unit6210:515:5019:39
game duration10016:283:3160:00
gas steal#medianearlylatewinsenemy gas
gas steal decision172:091:562:5853%6:31
gas steal success92:162:072:3044%7:04
none or failed91---64%6:03
gas steal killed94:053:085:05


The most successful openings were 5HatchPool (5 hatcheries before pool, a supremely greedy build to exploit bots that never attack early) and ZvT_3HatchMutaExpo, the two openings I selected as preparation. For bots carried over from the previous year, good preparation is easier.

Dragon has a chaotic play style. Steamhammer’s wildest game of the tournament may be Steamhammer-Dragon on Longinus (replay file). Dragon played a V strategy: Vultures, valkyries, and vessels.


#5 mcrave

openinggameswinswinslossesfirstlast
11Gas10PoolMuta10%-10:078989
12Gas11PoolLurker10%-9:054040
2HatchHydra10%-6:324545
2HatchMutaPure10%-4:026161
4PoolHard30%-8:521443
9Pool8GasLurker10%-11:258888
9PoolHatchSpeedAllIn1662%6:0310:25096
9PoolLair10%-4:586868
Over10Hatch11Pool1844%10:457:54281
OverhatchLateGas10%-16:085353
ZvZ_12HatchExpo10%-8:182323
ZvZ_12HatchMain1030%11:058:26790
ZvZ_OverpoolTurtle4578%9:2711:10499
13 openings10056% 9:19 9:46
planpredictedrecognizedaccuracy
countgameswinscountgameswinsgood?
Heavy rush2323%48%55%60%4%74%
Turtle7777%58%1111%0%8%87%
Unknown--8484%63%0%0%
timing#medianearlylate
my combat unit992:261:493:19
my gas942:091:435:02
enemy scout992:570:415:25
enemy combat unit1002:321:494:26
enemy gas983:472:526:12
enemy air unit945:054:017:07
enemy cloaked unit0---
game duration1009:274:0224:09
gas steal#medianearlylatewinsenemy gas
gas steal decision72:131:582:5557%2:58
gas steal success0-----
none or failed100---56%3:47
gas steal killed0---


Again two of my prepared builds, 9PoolHatchSpeedAllIn and ZvZ_OverpoolTurtle, were the top choices. Both are tough for most zerg bots to handle. My other prepared build, ZvZ_Overgas9Pool, does not appear in these 100 games. Apparently it flopped and was abandoned early. Rushy builds ended up winning faster than they lost, and more macro builds were the reverse, as you might expect. The timing table shows that McRave went spire nearly every game (overlords do not count as “air units” there), and not slowly. That’s normal for ZvZ, of course, but it shows that McRave did not favor builds to overrun the opponent with zerglings.


#6 willyt

openinggameswinswinslossesfirstlast
12Hatch_4HatchLing10%-14:087373
2.5HatchMutaExpo450%19:4214:047694
9HatchExpo9Pool9Gas10%-17:395656
9PoolHatchSpeedAllIn1338%4:538:51097
9PoolHatchSpeedSpire210%-9:337070
9PoolLair10%-16:433030
9PoolLurker1580%12:1520:15398
9PoolSpeed1346%6:2612:49190
9PoolSpeedAllIn1267%5:509:321299
ZvT_13Pool2564%19:3520:09481
ZvT_2HatchMuta10%-22:102929
ZvT_3HatchMuta1354%17:3518:492278
12 openings10056% 13:56 14:57
planpredictedrecognizedaccuracy
countgameswinscountgameswinsgood?
Factory11%100%11%100%0%0%
Fast rush88%38%33%67%0%75%
Heavy rush55%80%22%0%0%60%
Naked expand4747%57%1616%100%17%64%
Safe expand3939%54%1313%46%10%67%
Unknown--6565%48%0%0%
timing#medianearlylate
my combat unit1002:182:135:58
my gas1002:141:456:22
enemy scout1002:141:427:17
enemy combat unit1002:582:066:14
enemy gas855:163:167:59
enemy air unit4414:598:3923:14
enemy cloaked unit3115:227:1920:23
game duration10014:304:4160:00
gas steal#medianearlylatewinsenemy gas
gas steal decision102:061:563:0910%5:34
gas steal success82:142:063:150%5:42
none or failed92---61%5:15
gas steal killed83:593:034:20


WillyT has become much stronger over the past year. It is better at handling Steamhammer’s lurker builds—except for the especially early 9 pool lurker build, which apparently catches it unready. Steamhammer’s improvements in lurker play were important to keep up with progress. I think Steamhammer’s diverse mix of openings was essential to counter WillyT, which has its own diverse mix and will figure out how to counter anything that is too predictable.

Steamhammer’s closest game of the tournament was Steamhammer-WillyT on Empire of the Sun (replay file). Steamhammer decisively stopped WillyT from taking the nearby north island base, but allowed it to hold the distant south island despite scouting it the instant it started. Notice WillyT’s interesting but somewhat uncoordinated dropship play throughout the game.


#7 microwave

openinggameswinswinslossesfirstlast
5HatchPool10%-5:231818
8Hatch7Pool580%10:159:322059
973HydraBust540%13:285:165491
9HatchMain9Pool9Gas10%-4:325656
9PoolHatchBurrow10%-5:264646
9PoolHatchSpeedAllIn2080%6:4812:00099
9PoolHatchSpeedSpire2483%11:056:06493
9PoolSpeedSpire10%-11:098181
ZvZ_12HatchMain2085%11:2017:506596
ZvZ_12PoolMain1173%9:355:06897
ZvZ_Overpool9Gas1164%13:2717:08242
11 openings10074% 11:14 8:31
planpredictedrecognizedaccuracy
countgameswinscountgameswinsgood?
Fast rush1717%71%1414%93%6%59%
Heavy rush4949%71%2525%76%27%31%
Naked expand2626%81%1616%62%12%35%
Turtle88%75%99%89%12%25%
Unknown--3636%67%0%0%
timing#medianearlylate
my combat unit982:252:133:15
my gas972:311:477:09
enemy scout982:301:224:43
enemy combat unit1002:321:053:31
enemy gas664:352:2517:32
enemy air unit527:513:4317:33
enemy cloaked unit0---
game duration10010:574:2725:22
gas steal#medianearlylatewinsenemy gas
gas steal decision82:111:532:4175%4:33
gas steal success22:292:142:43100%4:34
none or failed98---73%4:35
gas steal killed22:402:212:58


Microwave had too many weaknesses. Of the 4 openings with 80% plus win rates, 3 were from preparation and one was Steamhammer’s discovery during the tournament. It’s interesting that the 12 hatch build ZvZ_12HatchMain was faster to win than to lose. I think that means it won with zerglings from its extra larvas.

The plan table shows that Microwave followed its own broad range of plans. In the timing table, see the wide and matching variation in Microwave’s gas timing and air unit timing. Did Microwave never get zergling speed in long games?


#8 daqin

openinggameswinswinslossesfirstlast
11Gas10PoolMuta10%-11:292424
2HatchLingAllInSpire812%9:3712:165292
2HatchLurkerPure10%-15:314545
2x10HatchSlow10%-9:525555
3HatchHydra20%-17:147293
3HatchHydraBust520%18:0712:092291
3HatchHydraExpo10%-11:0466
3HatchLing1233%7:0611:29373
3HatchLingExpo1217%34:0211:353697
4HatchBeforeGas20%-12:31221
4HatchBeforeLair20%-11:476799
5HatchBeforeGas10%-11:116868
5PoolHard2Player10%-9:4144
9HatchExpo9Pool9Gas1030%8:1212:257595
9Pool9Hatch10%-12:243232
AntiZeal_12Hatch10%-11:404141
Over10Hatch11Pool10%-14:043131
Over10Hatch2Sunk10%-15:217070
Over10PoolHydra10%-9:437474
OverhatchExpoLing3040%6:3410:26098
OverhatchLateGas10%-12:309696
OverhatchMuta10%-14:162929
ZvP_3BaseSpire+Den20%-14:06525
ZvP_3HatchPoolHydra20%-13:175078
24 openings10023% 7:02 11:40
planpredictedrecognizedaccuracy
countgameswinscountgameswinsgood?
Heavy rush44%50%1010%0%25%0%
Naked expand33%0%1111%100%0%0%
Safe expand5858%24%4141%10%40%3%
Turtle3535%20%3434%24%40%6%
Unknown--44%0%0%0%
timing#medianearlylate
my combat unit1003:071:533:54
my gas1002:471:476:26
enemy scout1001:311:109:29
enemy combat unit1004:334:066:41
enemy gas945:285:066:52
enemy air unit1216:509:1020:14
enemy cloaked unit2412:396:3517:59
game duration10011:185:4260:00
gas steal#medianearlylatewinsenemy gas
gas steal decision302:081:552:3623%5:35
gas steal success242:172:062:2525%5:36
none or failed76---22%5:23
gas steal killed242:472:353:06


After this upset, I think I’ll take DaQin as a test opponent and finally figure out the skills to defeat it. DaQin is a Locutus fork, so beating it probably means doing better against other protoss bots.

The timing table shows that DaQin was remarkably late with air units. That includes both corsairs and observers—DaQin was late with both of them. In fact, I don’t remember whether it makes corsairs at all. Mutalisks might be a good choice to win.


#9 freshmeat

openinggameswinswinslossesfirstlast
11Gas10PoolMuta1267%7:065:50294
8PoolHard633%8:209:091445
9Hatch8Pool10%-6:489292
9PoolHatchSpeedAllInB3784%5:565:55599
9PoolSunkHatch862%5:069:46474
9PoolSunkSpeed825%8:017:04052
Overpool14Hatch10%-6:198686
OverpoolSunk1771%9:189:45397
ZvT_13Pool333%7:335:439093
ZvZ_12PoolMain743%7:075:351187
10 openings10064% 6:21 6:53
planpredictedrecognizedaccuracy
countgameswinscountgameswinsgood?
Fast rush1313%38%1414%71%31%31%
Heavy rush5757%65%3030%67%25%32%
Naked expand--22%100%0%0%
Turtle3030%73%2525%52%10%20%
Unknown--2828%64%0%0%
Worker rush--11%100%0%0%
timing#medianearlylate
my combat unit1002:172:093:27
my gas982:531:467:53
enemy scout792:311:267:29
enemy combat unit1002:341:055:17
enemy gas394:012:559:29
enemy air unit294:434:015:51
enemy cloaked unit0---
game duration1006:304:1716:24
gas steal#medianearlylatewinsenemy gas
gas steal decision112:151:552:5745%3:31
gas steal success62:182:013:0133%-
none or failed94---66%4:01
gas steal killed63:042:314:06


When I was preparing opponent-specific data, Steamhammer had an overwhelming score against FreshMeat on BASIL. This result is good but not overwhelming; FreshMeat improved a lot in a short time. I had recognized that FreshMeat had made great strides, but there was not enough recent data to show what was working in the most recent games. So I made no preparation at all. These tables show an example of how Steamhammer figures out an opponent from scratch. I think it did OK.


#10 ualbertabot

openinggameswinswinslossesfirstlast
Over10HatchSlowLings10%-8:169999
OverhatchExpoMuta1759%5:216:262195
OverpoolTurtle8294%6:1711:51098
3 openings10087% 6:00 8:16
planpredictedrecognizedaccuracy
countgameswinscountgameswinsgood?
Factory1010%100%1313%100%10%0%
Fast rush3333%82%2727%85%36%18%
Heavy rush4949%90%3131%81%31%20%
Naked expand88%75%1212%100%0%12%
Unknown--1717%82%0%0%
timing#medianearlylate
my combat unit1002:262:153:13
my gas992:582:396:33
enemy scout882:081:219:58
enemy combat unit892:331:474:30
enemy gas823:442:3714:24
enemy air unit1414:2011:5015:59
enemy cloaked unit1014:212:3716:46
game duration1006:314:3521:33
gas steal#medianearlylatewinsenemy gas
gas steal decision82:321:482:5488%7:00
gas steal success42:292:102:4475%13:15
none or failed96---88%3:37
gas steal killed43:022:513:06


Comparing this year to last year, Steamhammer actually did a little worse against UAlbertaBot. The skills I improved over the last year didn’t include skills to defeat UAlbertaBot’s pressure builds, or to adapt better to its random race.


overall

totalZvTZvPZvZZvR
openinggameswinsgameswinsgameswinsgameswinsgameswins
10Hatch10% 10%
10HatchHydra10% 10%
11Gas10PoolMuta1553% 20% 1362%
11Gas10PoolMutaB10% 10%
11HatchTurtleHydra30% 30%
11HatchTurtleLurker1553% 1553%
11HatchTurtleMuta30% 30%
11Pool20% 20%
12-11HatchStem10% 10%
12Gas11PoolLurker10% 10%
12Gas11PoolMuta10% 10%
12Hatch_4HatchLing20% 10% 10%
2.5HatchMutaExpo450% 450%
2HatchHydra10% 10%
2HatchLingAllInSpire812% 812%
2HatchLurkerAllIn20% 10% 10%
2HatchLurkerPure10% 10%
2HatchMutaPure10% 10%
2x10Hatch10% 10%
2x10HatchBurrow10% 10%
2x10HatchSlow80% 80%
3HatchHydra40% 10% 30%
3HatchHydraBust520% 520%
3HatchHydraExpo50% 50%
3HatchLateHydras10% 10%
3HatchLing1331% 1331%
3HatchLingBurrow20% 20%
3HatchLingExpo1414% 1414%
4HatchBeforeGas20% 20%
4HatchBeforeLair30% 30%
4PoolHard30% 30%
4PoolSoft20% 20%
5HatchBeforeGas10% 10%
5HatchPool2568% 2471% 10%
5PoolHard2Player10% 10%
6Pool20% 20%
6PoolHide10% 10%
6PoolSpeed60% 60%
6Scout10% 10%
7-7HydraLingRush10% 10%
7DroneGas10% 10%
7Pool10Hatch10% 10%
7Pool12Hatch10% 10%
7Pool6GasLurker B10% 10%
7PoolHard10% 10%
7PoolHarder10% 10%
7PoolMid10% 10%
7PoolSoft10% 10%
8Hatch7Pool580% 580%
8Hatch7PoolBurrow10% 10%
8Hatch7PoolBurrowB10% 10%
8PoolHard633% 633%
8Scout10% 10%
973HydraBust540% 540%
9Hatch8Pool20% 10% 10%
9HatchExpo9Pool9Gas1323% 10% 1225%
9HatchMain9Pool9Gas10% 10%
9Pool8GasLurker10% 10%
9Pool8Hatch10% 10%
9Pool9Hatch20% 20%
9PoolBurrow911% 911%
9PoolBurrowB10% 10%
9PoolFastLurker933% 933%
9PoolHatchBurrow10% 10%
9PoolHatchSpeed425% 425%
9PoolHatchSpeed7Drone20% 20%
9PoolHatchSpeed7DroneB30% 30%
9PoolHatchSpeedAllIn5459% 1338% 520% 3672%
9PoolHatchSpeedAllInB3882% 10% 3784%
9PoolHatchSpeedSpire3262% 80% 2483%
9PoolHatchSpeedSpire220% 10% 10%
9PoolLair30% 10% 10% 10%
9PoolLurker1675% 1580% 10%
9PoolSpeed1638% 1346% 30%
9PoolSpeedAllIn1362% 1267% 10%
9PoolSpeedSpire10% 10%
9PoolSpire10% 10%
9PoolSunkHatch956% 10% 862%
9PoolSunkSpeed1118% 20% 10% 825%
AntiFact_13Pool1861% 1765% 10%
AntiFact_2Hatch30% 30%
AntiFact_Overpool11Hatch10% 10%
AntiFactoryHydra10% 10%
AntiZeal_12Hatch60% 10% 50%
HiveRush10% 10%
Over10Hatch20% 20%
Over10Hatch11Pool1942% 10% 1844%
Over10Hatch1Sunk20% 20%
Over10Hatch2Sunk50% 50%
Over10Hatch2SunkHard20% 20%
Over10HatchBust20% 20%
Over10HatchHydra10% 10%
Over10HatchSlowLings30% 20% 10%
Over10PoolHydra10% 10%
Overgas+110% 10%
OverhatchExpoLing4233% 4233%
OverhatchExpoMuta1759% 1759%
OverhatchLateGas20% 10% 10%
OverhatchLing10% 10%
OverhatchMuta10% 10%
Overpool14Hatch20% 10% 10%
Overpool2HatchLurker20% 20%
OverpoolLurker20% 20%
OverpoolSunk1771% 1771%
OverpoolTurtle8889% 617% 8294%
OverpoolTurtle 010% 10%
Overpool_3HatchLing10% 10%
PurpleSwarmBuild10% 10%
ZvP_2HatchMuta20% 20%
ZvP_3BaseSpire+Den20% 20%
ZvP_3HatchPoolHydra176% 176%
ZvP_4HatchPoolHydra862% 862%
ZvP_Overpool3Hatch10% 10%
ZvT_13Pool3057% 2564% 20% 333%
ZvT_2HatchMuta10% 10%
ZvT_3HatchMuta1450% 1354% 10%
ZvT_3HatchMutaExpo3278% 3278%
ZvT_7Pool10% 10%
ZvZ_12HatchExpo10% 10%
ZvZ_12HatchMain3165% 10% 3067%
ZvZ_12Pool20% 20%
ZvZ_12PoolMain1861% 1861%
ZvZ_Overpool11Gas10% 10%
ZvZ_Overpool9Gas1258% 10% 1164%
ZvZ_OverpoolTurtle4578% 4578%
total90048%20059%30012%30065%10087%
openings played12523101303

Steamhammer showoff games

I picked five winning games to show off Steamhammer’s fearsome might, such as it is. I’m happy with the improvements in the tournament version, and if there’s more to do, then when it’s done I can be happy about that too.

Steamhammer used to defeat Locutus only when Locutus messed up severely, such as by trapping its own dragoons in its natural so that zerg didn’t have to face the whole army. And it still can’t touch Stardust. I was surprised to see a couple games where Steamhammer beat Locutus by straight up outfighting the dragoons. See Steamhammer-Locutus on Fighting Spirit where zerg won impressively with All The Macro, and Steamhammer-Locutus on Jade where zerg was unable to keep a third base up for long, but still wrested a win. Some of the credit is due to the smarter upgrade choices versus protoss, though the burrowed zergling preventing expansion was key, and Locutus did supply block itself. Here’s a picture from the second game. It may look as though zerg has 3 bases beyond its main and natural, but 1 is already destroyed (you’re seeing burrowed drones on the minimap) and the other 2 will be.

confused combat

Steamhammer has also been taking games from Halo by Hao Pan. That’s not new, but I like the promise it shows. Some wins are with a one-base mutalisk build: Steamhammer-Hao Pan on Fighting Spirit. I was intrigued by Steamhammer-Hao Pan on Roadrunner where Halo was winning after a vulture-wraith build and putting on continual pressure, while Steamhammer struggled with awesome determination for longer than seemed possible. The new static defense code provides for stubborn defense. Instead of winning, Halo suffered some kind of production bug, fell behind on macro, and slowly lost. I suppose it is the result of Hao Pan concentrating on Fresh Meat, but Halo is still higher ranked than Steamhammer. This is why you don’t resign too early in bot versus bot!

Steamhammer-MadMixP on Medusa shows off cannon-related skills of both bots. MadMix cannoned behind the zerg minerals, a great skill which I haven’t seen from any other bot. Steamhammer could not fight so many cannons, but it showed its own rare skill: It mined only the mineral patches that were outside cannon range. It’s not a new skill, but I’m proud of it. Unfortunately the drones that were not allowed to mine dangerous minerals idled around the base “waiting for them to open up” instead of being transferred elsewhere, but one step at a time! Steamhammer knocked down the undefended protoss main, expanded there itself, and clumsily but inevitably defeated the cannons for the win.

cannons and response

I recommend making no more than about 4 cannons, then adding gateways at the proxy instead. Zealots have the power to, you know, move around and hit stuff that’s outside immediate reach. The only extra smarts the zealots need is the ability to retreat toward the cannons when outmatched and fight within cannon range.

Steamhammer’s timers

UAlbertaBot comes with a system of timers: It divides the bot’s work into aspects, and for each frame times how much time was spent on each aspect. Steamhammer inherited it. Overkill also inherited it, and if you’ve seen Overkill play on the SSCAIT stream then you’ve seen its timer display in a big black box smack in the middle of the screen. On a standard Broodwar screen, much smaller, the box is in the lower right.

The display only shows the times for one frame. I found it less useful than it could be; you have to be watching closely to see any spikes in specific aspects. So yesterday I extended it to remember the high water mark for each aspect, the longest time it has taken during the game. If there are time usage spikes, I can quickly get an initial idea of where they are.

black box with bar graph and two columns of numbers

At the time of the picture, Steamhammer’s supply was 187. Some of the aspects of play named down the left are the same as UAlbertaBot’s; others are new or changed. The bars represent time in milliseconds for the previous frame, the same as the first column of numbers. The second column of numbers is the peak time in milliseconds. (I decided that drawing the peaks on the bar graph would compress the real-time display too much.) Worker management, production, building construction, and combat are the most expensive aspects. Search means BOSS search, which does not happen for zerg, so the 0.4ms peak probably means that the OS dropped in that much delay at some point. The Tasks are a couple of jobs that the bot already did that I converted into tasks, nothing new yet.

If I run into slowdowns in the future, maybe I’ll extend it more and keep a histogram for each aspect to see how often it is slow.

The code that does the timing is straightforward and exactly like UAlbertaBot. Here’s the code to time the Info line of the display.

    _timerManager.startTimer(TimerManager::InformationManager);
    Bases::Instance().update();
    InformationManager::Instance().update();
    _timerManager.stopTimer(TimerManager::InformationManager);

what’s next for Steamhammer: the decision

I have decided what tactical skills to work on. My list included skills for specific units: Mutalisks, the most important; lurkers, which I’m most interested in for now; scourge, which Steamhammer spends heavy gas on and doesn’t always use well, defiler skills because Steamhammer often reaches late game. But those are only single unit types. And unit coordination skills, like storm dodging, scarab dodging, mine clearing and mine dragging, making the best use of the dark swarm that is on the map—all needed, all narrow and specific. And tactical analysis, my initial favorite. I have an algorithm in mind, which calls for a fast combat evaluator. MaasCraft’s tactical search also uses a fast combat evaluator. My idea is different, and I’m not satisfied with MaasCraft’s evaluator. Thinking through what’s needed, I concluded that the first draft would be easy to write, but would produce poor results. I think it’s likely that it needs a sophisticated combat evaluator to work well—I have an AI algorithm in mind for that too, but I fear I can’t finish it in time for SSCAIT in December.

To make the most progress before SSCAIT, I decided to work on the next level of pathfinding skills. Steamhammer currently calculates terrain paths without regard to where the enemy may be. On an empty map, ground units reach their destinations without getting stuck on terrain. When a unit is trying to reach its destination safely despite the enemy, a scouting unit or a drone transferring to another base, the unit reacts to dangers by leaving its path and running away from the enemy. It is not able to figure out a way around (though it may blunder into one), and it is not able to tell when its path is completely blocked and it should give up. So overlords scout less safely and less efficiently than they could, and worse, drones trying to transfer may end up burrowed all over the map, wasting supply and risking their lives to achieve nothing.

Steamhammer needs true safe pathfinding. It has to recalculate safe paths when the enemy is sighted. That opens the door to a lot of more specific skills.

• Don’t send drones to a place you know they can’t reach. This alone would save many games.
• Don’t even spawn extra drones inside a tight contain. They won’t get out.
• Better scouting, from maneuvering the early scouting worker to moving overlords and the Recon squad.
• Calculate least-danger paths for harassment. You can take hits as long as you escape.
• Similarly for drops.
• Reach safe spots to attack walls or other stuff from outside enemy range.
• Enemy vision is a kind of danger too. Find sneaky paths.
• Path through nydus canals. Nydus canals are part of my plan to support islands.

I don’t know how many of these I’ll get to by SSCAIT. There is a lot to it: Ground units and air units have different needs, safe paths and least-danger paths are different, sneaky paths are different. Safe drone transfers are the biggest weakness and have top priority. Part of the solution is to spread hatcheries out more, rather than putting all macro hatcheries in the main.

The first part of the job was to create a task manager to run background tasks. It’s simple, I wrote it yesterday. The idea is that pathfinding tasks will update safe pathfinding data structures behind the scenes, so that the calculation load is spread out and the data is reasonably up-to-date. Over time, I expect to add a lot of other kinds of tasks. Steamhammer runs fast, and for now there is little risk of overstepping the frame time limit. (Even in the late game when maxed, most frames take a handful of milliseconds, and spikes above 20ms are rare.) But I have thought up plenty of complicated tasks, and it seems likely to become an issue someday. I want the infrastructure to be ready, so that I can implement a principled solution instead of refactoring a lot of code when the day arrives.

Steamhammer 3.5.11 change list

According to tradition, a new Steamhammer version drops in elo on BASIL at first. It takes around 2 months for changes to settle into the learning data before the elo reaches a new equilibrium. The new AIIDE tournament version has broken tradition and started out with an elo rise instead. It’s an early sign that I may have a successful version.

Last night I uploaded the “bug fix” version 3.5.11 to SSCAIT and SCHNAIL. It has 9 small changes over the tournament version of Steamhammer, a lot more than I planned. Only 3 changes are proper bug fixes. All of them are meant to prevent bad behavior or use resources more efficiently, so they fix play bugs if not code bugs. For debug flags, this time I turned on drawing of not only the clusters but also the combat sim info (drawn alongside the cluster info and in combat areas) and the static defense plan. It makes for a busy display.

operations

Estimate when one of our bases is doomed to be destroyed, so that we can stop spending resources on it. Any code that wants to know can call base->isDoomed(). For this first pass, I made it conservative; it checks a few conditions and does a quick comparison of defenders to attackers to see if the fight is very lopsided. If it says the base is doomed, then it is under attack and there truly is little chance that it can be saved (though you never know, maybe the opponent will do something else). The feature has many uses that I’m sure I’ll get to, but for now only one is implemented (keep reading).

static defense

Don’t add more sunkens or spores at a doomed base. They’ll die too and accomplish nothing. The weakness was glaring; now it should be only staring.

• Limit front-line sunkens versus terran to 6 at most, 5 at other bases. (Against bots, rather than humans, Steamhammer makes at most 1 sunken at other bases, to prevent casual raids. Almost all bots concentrate on attacking the main with its front line.)

• The plan/execute loop runs more often, to reduce the delay in adding defenses when in a hurry.

• The controller could mistakenly order multiple copies of a prerequisite building, like a forge for cannons or an evolution chamber for spore colonies. Fixed.

• There was one last place where a building was posted directly to the building manager instead of queued for production: The prerequisite building. Fixed. It caused no known bug, but queueing the building likely avoids rare problems.

zerg

Fixed a production freeze that was possible when the enemy went mass air. This was an interesting one, because it was a completely different mechanism than any other production freeze I’ve seen. In the unit mix calculation, if the best unit for the mix was devourers and we already had as many devourers as we should, then the code rejected the choice it had committed to. The unit mix fell back on the default, drones as the only unit to make. By the time this happens, it is late in the game and Steamhammer already has as many drones as it wants. So it replaces lost or used drones, makes urgent units like scourge, keeps up with its upgrades... and produces no other units. The fix was to reject devourers up front in that case, so that the calculation finds a different best unit.

• If we have excess minerals and gas, make a lair and/or research burrow solely to use up some of the excess. It happens occasionally, and if the game continues we’ll want both eventually.

• If air carapace has reached +3 and we still have many mutalisks and/or guardians, start getting air attack upgrades too. Might as well, I figured. I uncommented a snippet of code that I wrote years ago, back when Steamhammer’s air upgrades never went beyond +2.

the prototypical series on SCHNAIL

SCHNAIL players who try out Steamhammer often play a series of games one after another, and if they liked it they come back another day for more. I’ve watched enough of these series that I have a sense of the patterns they follow. Everybody’s different, of course, and Steamhammer’s play has random elements too. But often enough, a series with a terran or protoss opponent who is well-matched with Steamhammer more or less follows a prototypical sequence of four steps.

1. Get busted. Steamhammer is tuned against bots, where early aggression is successful, so it often starts out with a bust. Apparently many humans at this level are not quite prepared. Against terran it breaks in with zerglings or lurkers, against protoss with lings, hydras, or mutas. (Terrans are ready for mutalisks.)

2. Tighten up defenses. Players at this level figure out how to stop an incoming Steamhammer rush within a few games. That’s typically good for two or three wins before Steamhammer tries something else.

3. Get overrun by macro. Players at this level also tend to be too passive. Maybe macro and scouting and whatnot uses up their bandwidth, or maybe they’re used to being fine if they stay at home for a while. If the player goes active and begins attacks too late into the middle game, Steamhammer has already started to outmacro them and, even if it loses bases along the way, will finally win with hive tech.

4. Learn to attack actively. And players at this level don’t take long to understand how to react to zerg macro: Don’t let the zerg macro, but attack expansions aggressively. The new static defense code makes more sunkens at exposed outer bases against humans (not against bots), which helps them survive. But Steamhammer is not strong at defense, and players are fairly successful at taking the bases down anyway. After figuring this out, the human player will win games indefinitely, sometimes all games. If the two are closely matched, the games may be long and difficult.

Alternately, a terran may make one big timing attack into the zerg natural, and break through. Steamhammer can usually deter this plan versus protoss.

It seems to me that if you start out struggling to beat Steamhammer, and without using any special anti-bot tricks learn to defeat it, then you must have improved your play. Tight defense and active play are good. The same skills you polished to beat the bot will help you against other opponents.

Of course, many series don’t go this way at all. A player of different strength may get all losses or all wins. Several days ago one player played a long series of cannon rushes on the 2-player map Destination, first trying to push cannons from the side of the zerg base, then in later games switching to cannon the natural. The rush, after adding proxy gateways, often eventually destroyed the zerg main, despite being slowed by defenses, and units from the proxy gates were then able to move out and destroy more bases. But protoss was never able to stop zerg from expanding, and ended up losing every game, usually after defensive cannons in the protoss base suddenly fell. Steamhammer made many missteps, but I was pleased with the defense against cannon pushes. This was likely a player trying out the strategy for fun.

what’s next for Steamhammer?

Steamhammer 3.5.10, the AIIDE 2021 tournament version, is uploaded to SSCAIT and SCHNAIL. I chose to turn on DrawClusters this time as the debug flag to entertain watchers, because it now draws enemy unit clusters as well as friendly ones. I’ll post the source before long.

Next up will be Steamhammer 3.5.11, a bug fix release. It seems that I often issue bug fixes shortly after tournament versions, because there are a few things I wish I had gotten done in time. I don’t intend to take long with it. It will include the production freeze fix that I mentioned in the change list, and likely a few other quick items.

After that, it is time to re-evaluate my priorities again. Earlier, I had planned work on opening timing, and started some of it. Then I had to wait for data to accumulate before I could dig in deep, and my motivation flagged. Now the data has accumulated, but the skills I wanted to gain from opening timing no longer seem like the most urgent for Steamhammer: It is losing games for different reasons than back then. When I made the analysis that led to the opening timing decision, Steamhammer was losing due to poor opening choices and strategic mistakes. Now it seems to me that its losses are more often due to tactical weaknesses. The old problems are not fixed, but neither are they foremost; the scene has passed them by and exposed different problems. Maybe my changed analysis comes from watching SCHNAIL games? That’s probably one reason.

I want to improve tactical play somehow. I wrote down a number of medium-size projects that promise progress and that I could reasonably complete in time for the annual SSCAIT tournament in December. Some are work on tactical control of units that need help, and some are more general skills.

They’re all important, and I haven’t decided. At the moment I’m leaning toward doing the tactical analysis that I’ve often mentioned. The tactical analysis would provide an information framework for squad tactics and other decisions, so it’s logical to do first. With new priorities, the version after the bug fixes of 3.5.11 will be 3.6.

Besides one multi-month project, I need to put some level of effort into solving a few critical tactical weaknesses. Number one is indecision between advancing and retreating, the constant back-and-forth of the front units. It causes losses that add up quickly, and it happens virtually every game. Number two is defense when closely contained outside the sunken line, which is outright broken—units take fire without shooting back. Against humans, much more than bots, a key ZvP weakness is lack of storm dodging. Bots storm poorly. Storm dodging is a solved problem, so I hope the implementation won’t be hard.

Steamhammer 3.5.10 change list

Steamhammer 3.5.10 is the AIIDE 2021 tournament version. The current version on SSCAIT and BASIL is 3.5.2. The change list covers everything in between. I’ll upload the new version shortly, and source before long.

I wanted to improve lurker play to the point of having working lurker contain skills, but it was too ambitious for the time available. Even so, the improvements to lurker play should be easy to see. I soon decided it would be more effective to work on smaller fixes. There are always many short to-dos that each make a difference... because they accumulate faster than I can retire them.

tournament preparation

• Special preparation against 9 prospective AIIDE 2021 opponents—the ones it might make a difference against, plus Stardust where Steamhammer is at risk of scoring zero. I followed the same preparation plan as last year: For each opponent, choose a small number of builds that have historically won, or that seem to have good chances, and enter them into history as fictional single winning games. Let learning do the rest.

It amounts to giving hints “try this a few times before giving it up.” Steamhammer has a better chance of finding good builds early, and is not weighed down with masses of outdated learning data if the opponent brings surprises.

information

• Remember whether the enemy has used psionic storm this game. I wanted to feed the information into lurker spacing decisions, but ended up not implementing lurker spacing, so the feature is unused for now. There are other potential uses.

static defense

Changes to static defense include tuning to make the right amount in different situations—zerg static defense is expensive, and needs to be worth it. I think the tuning is improved versus terran, fairly good versus protoss, and still weak versus zerg.

• Fixed a crash due to division by zero. The bug fix does not affect strength, because the crash only happened when Steamhammer had no bases left. Yes, it was dividing by the number of bases. How easy it is to forget that you may already be dead! For my part, I forget that nearly every day.

Morph forgotten creep colonies into sunkens or spores, if and when they happen to be needed. The building manager sometimes slips up and forgets to morph a creep colony that was intended to become static defense. If defense is not needed, it will remain a creep for the time being. When the static defense planner decides that it is needed, it may turn into either a sunken or a spore. At some point I’ll implement tactical analysis and Steamhammer will have an idea of when the enemy might attack in strength. Then it will be able to leave all colonies until they are needed.

Try to place spore colonies in the mineral line, rather than somewhere vaguely near the hatchery. This helps ZvZ the most.

• Make one sunken colony less per base, compared to before.

• If the enemy has many tanks with siege mode, sharply limit the number of sunkens. They become a waste of minerals.

• Make more spores versus mass wraiths and mass scouts.

buildings

Anti-cannon sunken reaction failed due to errors in building placement introduced in a recent version. Fixed.

• Other attempted improvements to anti-cannon sunken placement.

• Added configuration option Config::Skills::UseSunkenRangeBug so that I can turn the feature off when it’s not allowed. It’s part of building placement; see BuildingPlacer::getAntiCannonSunkenPosition(). It’s off for AIIDE, where use of the bug is not allowed. It’s on for SCHNAIL, since it’s allowed in human games.

Steamhammer might try to build a macro hatchery directly on top of the main hatchery in the opening. The hatchery failed to build and the drone assigned to build it was left idle for a time, a serious breakdown. Fixed.

• In rare cases, a building might be placed invalidly so that it could not be built. Fixed.

squad orders

• Each squad keeps track of the last time its order was changed to a different target. It also remembers the most recent frame that any cluster of the squad attacked, and the most recent frame of a retreat. (“Attack” usually means that the combat sim said “go attack”, not that any unit fired a shot.)

• The above info is used by the air squad in deciding whether to keep attacking its current target, or seek an undefended target of opportunity. If the last attack was a long time ago and the last retreat was just now, then the mutas are sitting around and should try another target. They look for the closest undefended thing and try that instead. Unfortunately, the closest undefended target is often as inaccessible as the original target—it can be attacked in theory, but Steamhammer doesn’t have the smarts to do it in practice. So far, the feature is not worth the effort I put into it. I think it will become worth it when I implement more pathing and harassing skills.

• In defense, defeat enemy proxy pylons when nothing more dangerous threatens. There was always code to do this, but it was broken in a subtle way. The method for assigning units to squads is too complicated; I’ve got to find a better idea.

• In defense, count an enemy proxy creep colony as 2 units, not 1. When pulling drones to defeat the proxy before it can finish morphing into a sunken, Steamhammer will pull 4 drones and win the fight instead of 2 drones and lose. (3 drones would be ideal, if no other unit interferes.)

recon squad

The Recon squad has been a valuable feature ever since I implemented it. But lately Steamhammer has become strong enough that Recon’s weaknesses are hurting. For example, classically the Recon squad only pays attention to units that it can see, ignoring the remembered positions of enemy units, because its purpose is to see what’s going on. But suppose the squad consists of 1 zergling and it wants to scout an area defended by a sieged tank. The ling approaches to see, gets splatted by the tank. Another ling is assigned, approaches, splatted, etc., until the target times out. The process is, as people say nowadays, unsustainable.

I made 3 changes. None is critical in itself, but together they make the Recon squad safer and more effective and count as an important improvement.

• Combat sim attends to all enemy units, as for other squads, not only visible enemy units.

• When the squad is restored after it has become empty (for any reason, not only losing all units to the enemy), reset its target to somewhere else.

• Don’t assign the squad a target that is already in view. If the Watch squad or an overlord can see the target, the Recon squad doesn’t need to. As always, if no targets need scouting, disband the squad.

irradiated squad

I improved the behavior of irradiated units, but it still doesn’t work as intended. I’m convinced that bugs are hidden somewhere in the infrastructure code, not in the top-level decision code.

• The code was already clean, but I simplified it a little more.

• An irradiated unit keeps farther away from its friends than before. This is the most important change, even though the old distance was already outside the irradiation splash range.

• Flying units seek in a wider radius to find enemy units to splash radiation onto. Mutas are fast and may get there in time to do a little splashing.

• A slight change to burrow decisions.

scouting

• Release the scout worker early in a few special cases: If there is an overlord nearby to continue the scouting work; if the scout runs into a completed enemy bunker or photon cannon. There are details to the conditions; for example, if no enemy unit type has been seen yet beyond those the enemy had at the start of the game, then the scout stays on the job. Steamhammer usually scouts early, and returning the scout is economically good. An enemy bunker or cannon (if not a proxy) means on the one hand that the scout cannot advance, and on the other that the enemy has no intention of attacking right away, so Steamhammer can return the scout now and wait for zerglings to arrive to keep watch.

squad tactics

Don’t retreat forward if the enemy is near at all. The feature was meant to fix the case where one cluster of units is attacking the enemy, while a smaller cluster farther away was afraid to approach because it could not win on its own. But if an enemy was between the two clusters, which could happen despite a triangle-inequality test to try to prevent it, the cluster retreating forward would walk through the enemy and get shredded. Instead, a Regroup cluster close to an Attack cluster is itself changed to Attack in a second pass through the cluster status decisions before they are executed. The failure cases are non-horrible, and the change fixes one of Steamhammer’s biggest tactical weaknesses. At some point I’ll rewrite it so that clusters fighting the same enemies are treated together, not separately, but that’s for the future.

Enemy unit clustering is turned on, so that known enemy units are grouped into clusters just as Steamhammer’s units are. The config option Config::Debug::DrawClusters draws the enemy clusters in red circles to contrast with Steamhammer’s clusters in white circles. The enemy clusters are used in various decisions at the cluster and unit level.

An unhandled case led to poor lurker retreat decisions. I rewrote the code to simplify it and fix the bug.

When retreated all the way to the retreat point, lurkers burrow and tanks siege. Formerly, both remained ready to move, which meant that they were unready if the enemy advanced. It may not sound important, but it’s a big improvement. Indecision between advancing and retreating is common, which causes the familiar burrow/unburrow frenzy, but it’s a net gain by a wide margin.

• When retreating, count a sieged tank or a burrowed lurker as immobile defense, an option to retreat toward. Formerly, Steamhammer only looked for static defense.

• When seeking a cluster ahead to join this cluster with, use the squad’s order distance instead of the air distance. The order distance is the ground distance for ground clusters or the air distance for air clusters. This fixes some poor decisions made by ground units near terrain features.

• The code to retreat behind static defense was rewritten to be correct for a change. The actual behavior doesn’t change much, though.

• Be a little quicker to declare overlord danger at a base, so that new overlords are not spawned there to die uselessly.

combat sim

• The configuration option Config::Debug::DrawCombatSimInfo now draws information for each cluster, rather than for the most recent cluster simulated. It shows both the raw and the smoothed attack/regroup results, so you can see how the raw results flip-flop more. Combat sim is that much more debuggable—still not very.

A bug could leave the combat sim in an out-of-date state. Fixed. The bug (mentioned earlier in Steamhammer is progressing) is responsible for most or all of the 50-100 elo strength loss on BASIL in version 3.5.2. It’s what caused units to sit back instead of, say, attacking an undefended base.

• The radius to look for enemy units to include in the combat sim is altered to match what the Squad code does. I think this is a no-op; the enemy units that end up included are those in range to fire into the combat radius, which is different. But it looks tidy.

micro

Cancel a dying egg, cocoon, or unfinished building 1 second before it is predicted to die, not 5 seconds as previously. Lurker eggs were being canceled almost the moment they came under attack, which was bad. The gain of canceling items later outweighs the loss of a few units that come under sudden massive attack and die before they can be canceled.

• In figuring out which direction to kite a hydralisk, Steamhammer knows not to kite back into its own ground units—they are in the way. But it did not check whether the units were burrowed. Hydras had trouble kiting when near burrowed lurkers, because escape paths appeared to be blocked. Fixed.

terran

• Slightly improve the stim calculation, so that marines overstim a little less. It’s a change made in passing while I was working on other stuff, under the rule “if you see it now, fix it now.” (If it were possible to follow this rule all the time, there would be no such thing as technical debt.)

zerg

Macro: Steamhammer did not always make enough macro hatcheries due to a bug. That hurt a lot. Fixed.

• Macro: Make no macro hatchery unless there are at least 3 drones per base. Yeesh. It sounds basic, but the drone count never entered into Steamhammer’s calculation of whether it needed a macro hatch. This is a lenient limit that prevents rare egregious blunders (which I have seen happen). I expect I’ll tighten it in the future, one way or another.

• Macro: I noticed that Steamhammer sometimes became briefly supply blocked in the early middle game. I tweaked an overlord timing parameter by 1 point of supply, which fixed it.

• Macro: Fixed a potential production freeze related to air upgrades. This is a rare freeze; I'm not sure it has ever happened. When I fixed it, I thought it was a less-rare freeze that can happen when the enemy goes mass air. Then I discovered I was wrong. I have fixed the more important freeze, but not in time to get it into this version.

• Queue sunkens ordered by the strategy boss (as well as those ordered by the static defense boss, a change made in version 3.5.2), rather than posting them directly to the building manager. I never saw the old code cause a problem, but it’s likely that the change fixes rare misbehaviors.

• Queens: Be more flexible about parasiting high-priority targets instead of waiting for a good ensnare or broodling. If there is no tank in sight and the queen suddenly notices an enemy dropship, it should know what to do. A parasited dropship cannot surprise you.

• Queens: Get ensnare much less often versus terran, and a little less often versus protoss. I find the improvement in terran play to be visible.

• Defilers: A defiler that is about to die wants to cast a last spell. It’s done in part by a hit point test. Formerly, if the HP were too low but the enemy was gone, the defiler might (say) swarm itself, then consume, then swarm again nearby because the HP were still low, etc. There was often little or no gain, and the consumed zerglings did not appreciate it. Now the defiler only casts its low-HP Hail Mary spell if the enemy is around to shoot at it. (Being irradiated, stormed, or plagued also brings a Hail Mary.)

Lurkers: Avoid burrowing in tank or cannon range unless friends are along to help. This reduces the tendency of lurkers to rush in where angels fear to tread, though they’re still pretty foolish.

• Lurkers: Undetected lurkers look around harder for dangerous enemies nearby before unburrowing.

• Unit mix: Discourage guardians more overall. Discourage ultralisks and encourage hydralisks versus battlecruisers more. Favor hydras a little more versus wraiths. I think guardians may finally be tuned almost acceptably for Steamhammer’s current poor skill with them.

• Unit mix: When seeing 2 or more starports and no other air units, assume wraiths are likely and nudge the unit mix toward countering them. Steamhammer doesn’t make many predictions, but this one seemed important.

• Unit mix: Dark archons discourage queen production, though they don’t always eliminate it.

• I found that some urgent defensive reactions were happening too slowly. Therefore, first, call makeUrgentReaction() twice as often. Second, when making an anti-cannon sunken, it is allowed to start the creep colony before the spawning pool finishes. (Starting the creep before the prerequisite finishes for the final morph to a sunken or spore was already supported in other cases.)

Upgrades: Better code for ground upgrades. Historically, in long games Steamhammer went for ultra-ling in all matchups, and I wrote rigid upgrade code to match. It got carapace and then melee attack upgrade, and that’s all, correct preparation for the ultra-ling unit mix, with an exception added later for ZvZ to get melee attack first. Today Steamhammer varies its unit mix more sensitively depending on the situation, and may stick with or switch to hydralisks in the late game if they’re called for. I rewrote the code to be simpler and more flexible. In the planning phase, code puts any or all of melee attack, missile attack, and carapace into priority order depending on the matchup and game situation. In the execution phase, code assigns the top priorities to available evolution chambers.

In ZvT, Steamhammer gets missile attack if it is making hydras to fight goliaths or battlecruisers, because the terran is likely to stick with them. In ZvP, Steamhammer likes hydras and usually gets missile attack first and carapace next, though it depends. In ZvZ, with less variety, upgrades are about the same as before, except that there are extra rules if hive tech is reached. To my eye, play is clearly improved, especially in ZvP. Though the behavior is a lot more complicated, the total code size is small and about the same as the old rigid code.

• Upgrades: Fixed a minor bug where Steamhammer thought it could upgrade in an uncompleted evolution chamber. The worst case result was that the bot might slightly underspend its money on this production round.

openings

Overgas+1 build added to use more of that fast gas. Only one new opening! Is it a record low?

Tomorrow: What’s next for Steamhammer?

Steamhammer is ready for AIIDE 2021

Steamhammer is all set for AIIDE. I’m still making checks and running tests to be extra-duper-sure, but I’m convinced that this is the strongest and least-buggy Steamhammer ever. It hasn’t been uploaded anywhere, so nobody will be 100% ready for it... though I guess Stardust will be 99% ready. I plan to submit it today, a day ahead of time.

I’ll post the change list in a day or so, and the code after the submission deadline is safely past.

close proxy game

Here’s a short and surprising game from SCHNAIL, Steamhammer vs leftchange (T) on Heartbreak Ridge. Terran played an unusual and sneaky proxy. Steamhammer scouted it thanks to the anti-proxy overlord, and its first reaction was almost good; it did things right except for misplacing the sunken because sunken placement is optimized for stupid bot opponents. Steamhammer countered the empty enemy main, and soon neither player was able to mine. But there was a clear winner!

Today’s ASL 12 matches had another surprising and close proxy game with much better play, Soma vs JyJ on Polypoid. It starts at about 34:00 in this round of 16 group A vod with commentary by Nyoken and Scan. (I watched it “excluding restricted content” and didn’t miss anything that I noticed.)

Steamhammer is frozen for AIIDE

Steamhammer is feature-frozen for AIIDE 2021, so that I don’t risk breaking my good version. Well, maybe not entirely frozen, but reduced to a low temperature (keyword simulated annealing). I will fix bugs and prepare for specific opponents, and I’ll probably also make small feature tweaks if they are safe.

My change list right now has 54 items on it, 14 of them marked as important changes that significantly improve play. With that many, obviously none of them is a big project—there hasn’t been time! But major weaknesses are fixed or reduced, affecting the whole range of strategy, tactics, and micro; all levels have important improvements. I’m pleased and optimistic. (Of course I was optimistic before AIST S4, and then Steamhammer lost 0-4, so....)

For one new feature, I ran a test that involved adding a spore colony at every base. At supply 7 (very early, before the spawning pool), Steamhammer started an evolution chamber and made a spore in the main, and then added a spore at every new base for the rest of the game. The opponent didn’t matter for the test, so I ran it against the protoss built-in AI. I was tickled that, even with the giant handicap, Steamhammer won several games in a row with apparent ease.

the sunken range bug and AIIDE 2021

In Steamhammer 3.5.1 (see the “zerg” section) I added a defense against cannon rushes which exploits the sunken range bug. The bug makes it possible, under specific conditions, for a sunken colony to target an enemy which is outside the sunken’s range. Exploiting the bug is allowed in human tournaments. In fact, it’s a standard defense against cannon rushes, one that players know and use. An example is ASL 11 Semifinal A, Mini vs Queen, game 1—see about 32 minutes into the vod for a complicated sequence where Mini eventually abandons the cannon rush knowing that it has been countered, and notice that casters Nyoken and Scan have little trouble understanding what happened and why.

At the time I wrote “Use of this bug seems to be universally legal,” but today I checked the AIIDE rules more closely. The rules include a list of allowed bugs to exploit, and add “All other bugs/exploits are forbidden.” The sunken range bug is not on the list.

I sent e-mail to Dave Churchill explaining the situation and its complexities. He’s busy and I don’t know if he’ll have time to look into it. Basically, I’m expecting to disable the behavior in Steamhammer for the tournament. I’m adding a configuration setting Config::Skills::UseSunkenRangeBug so I can turn it on and off.

Most likely no AIIDE 2021 protoss will cannon rush at all, so in a way the point is academic. But who knows?

what should the rules say?

It’s complicated!

The range bug is a game behavior, and it can happen unintentionally in real games, just because events happen to trigger its conditions. It’s fairly rare, but I expect all who play regularly have seen it (whether they recognized it or not). Bots should not be penalized for game behavior that they did not intend, and have no reason to even notice.

Steamhammer deliberately attempts to exploit the bug to beat cannon rushes. I have to interpret that as a violation of the AIIDE rules as they are written.

If you’re actively trying to enforce the rule, how would you do it? First, you’d have to examine the games, presumably with replay analysis software since there are too many to watch in person. Then you’d have to decide whether at least one instance of the bug was a deliberate exploit. That likely involves reading the code to be sure. Tournament organizers are not going to go to so much trouble, so probably the only practical enforcement would be for other authors or observers to point out possible infractions after the fact.

Then there’s the point that exploiting the bug is legal in human play, so presumably it should be legal in bot play. But that has a hidden assumption behind it: Humans can’t or don’t exploit the bug in any way that seems unfair, therefore bots won’t either. It might be true, but how sure are you? Bots with perfect timing and simultaneous view of all information might be able to exploit the bug in a way that feels unfair. Then the rules would be unfair.

Maybe it’s right to allow exploiting the range bug unless and until some bot implements an unfair exploitation.

Even if it may be a good idea to change the rules, it’s no good to change them close to the submission deadline. The rules for this year should stay put. Next year’s rules may be open to debate.

Update: I have mail from Dave Churchill. After some flip-flopping, the final ruling is “INTENTIONAL use of this bug via any specific code that invokes it is not allowed.” That follows the original rules.

popular opponent Steamhammer

When I uploaded Steamhammer 3.5.1 to SCHNAIL, with new weaknesses, the bot lost 200 elo or more and also lost its popularity as a SCHNAIL practice opponent. I guess it’s not as much fun to play an opponent that sometimes plays fine and other times arrays all drones in front of the natural to make sunkens and then has no money to morph them. The bugs are fixed now. Elo is still lagging—elo changes slowly because there are not many ranked games—but Steamhammer’s popularity for practice returned suddenly. The players are getting information from somewhere.

In unrelated news, the name “Leta” is pronounced by some “Leeta”, by some “Layta”, and by some “Lehta” (which I guess is the correct one). In today’s ASL 12 round of 24 group E cast, Nyoken pronounced it all three ways in the space of a minute! Did anybody else notice?

Steamhammer is progressing

I estimate that the Steamhammer version active on SSCAIT and BASIL, 3.5.2, is about 50-100 elo weaker than the previous active version, 3.5. The improvements are outweighed by new issues, the most important of which came from an “optimization” of combat simulation which sometimes fed it stale data. Oops. Advice to all persons: Do not make mistakes, they can hurt.

I fixed that yesterday. The only remaining new weakness (that I can see) is a tendency to sometimes overdo it on the sunkens. I trimmed that back with limits based on additional information. It is less severe than the earlier weakness of forgetting the sunkens or leaving them until too late, and there are other improvements besides. I have the strongest Steamhammer yet.

I have time for more improvements. Early signs for Steamhammer in AIIDE 2021 look good, provided I can follow my own advice to all persons.