3.1 source is out
Steamhammer 3.1 source and binary are available at Steamhammer’s web page.
Steamhammer 3.1 source and binary are available at Steamhammer’s web page.
With the new Steamhammer 3.1 version running only on the Starcraft AI Ladder, I played over a bunch of ladder games to see how it is doing. The ladder runs games at a high rate, so after one day there were already plenty to see. As I expected, so far the overall win rate is not much different, though that might change with more time or a larger variety of opponents. I was amused that the ZvZ games tended to be the longest (due to Microwave’s cautious play style); the ZvT and ZvP games were more aggressive and shorter.
I’m pleased with the new feature to sunken bases which are at risk of vulture raids. Some games versus Halo by Hao Pan looked tighter; Steamhammer could take bases and retain most of their drones in the face of the fast-roaming vultures (it lost drones mostly in transferring between bases, the next worker safety issue I should address). It seemed to make the sunkens at a reasonably efficient timing, including against protoss, early enough to help and not wastefully early. A small step, but a good one.
For AIIDE 2020, submission deadline at the end of September, I’m thinking of uploading test versions to the ladder as I go. I expect to get more work done before then than went into version 3.1. In fact, already today I wrote 2 new reactions to enemy cheeses that cause trouble, and each by itself is more complex than the sunken feature of 3.1. (It will take longer than a day to test them, though.) Steamhammer will become more robust. For AIIDE, I’m still considering whether to concentrate more on basic skills, or more on sneak attacks from my bag of tricks, techniques that bots may be unready for because no other bot has played them yet.
For all who want to participate in AIIDE, I strongly recommend joining the Starcraft AI Ladder. I wrote up the signup process. It runs the same tournament software as the AIIDE tournament, and enforces the same strict time limits. It is the best way to find out whether your bot will run correctly in the tournament. The games become public, and nothing else. If you worry that the games themselves may give away your secrets (other bots might use the ladder as training data), you can work around that too: Deliberately weaken your strategy. You’ll still test correctness and adherence to the time limits, but you don’t test your strength so you don’t give away your true weaknesses to others.
I uploaded Steamhammer 3.1 to the Starcraft AI Ladder. Not to SSCAIT, since it is down. The update is a small one, there’s not much new stuff and no major new features; my rate of work has been low. It should be stronger than version 3.0.2, but not by a wide margin (of course I predicted the same about that version, which made a big gain). Steamhammer’s weakest race terran got the most additions. In a startling break with tradition, I wrote no new openings.
I expect that the next released version will be Steamhammer 3.2, which I will put out after the AIIDE 2020 submission deadline. My to-do list includes a deep bag of tricks that I can select from....
• Take bases in a better order. Reading the code that chooses the next expansion showed me a few gross bugs, which I fixed. I also adjusted values to be a little less wrong. It’s still none too smart; for example, it doesn’t understand that zerg base order versus terran should be much different than versus protoss. The worst remaining problem, though, is caused by a bug in the building manager: When workers repeatedly die before reaching the building site, the building manager may cancel the building without unreserving the tiles, so that the base can never be taken for the rest of the game. That’s bad, but I intentionally left it unfixed for now because some of the bug’s effects are good. If you repeatedly fail at taking a base, then, well, maybe you shouldn’t try to take that base. Steamhammer’s base-taking behavior becomes adaptive. I don’t want to fix the bug until I can provide that adaptivity on purpose rather than by mistake. Failing to expand to the same unsafe base over and over is not a winning plan.
• I added a debug option to the configuration file, DrawExpoScores, which draws Steamhammer’s idea of the value of taking each base. It’s generally a positive number for bases near Steamhammer’s main and a negative number elsewhere on the map (which doesn’t matter, it simply picks the highest value). If the base cannot be taken, it draws the reason instead.
• Ranged units give higher priority to targeting tanks. This was inspired by games in which Steamhammer’s hydralisks saw a factory with a tank on the other side, and decided to shoot at... the factory.
• Bug fix: A worker that had just mined out a mineral block might go idle. When it happened, the worker not only wasted its life doing nothing for the rest of the game (not even watching cat videos), it also blocked the path that it had been given the task of clearing. Now that’s some powerful laziness!
The terran changes are related to repair of buildings and to lifting of buildings.
• Bug fix: It understands that it can’t repair a building which is not completed. I believe the effect of this aboriginal bug in the code is that an SCV is assigned to repair, can’t start because the building is not repairable, and gets reassigned the next frame. I didn’t verify it, but it must slow down mining.
• Mass-repair a bunker or turret. The response time is slow, so it doesn’t work as well as it should. A simplified calculation makes a rough guess at the right number of SCVs to assign (it does get the correct answer in the case of repairing a bunker under attack from dragoons).
• It can repair multiple buildings at once. The original code, inherited from UAlbertaBot and little changed until now, could repair one building at a time. For buildings other than bunkers and turrets, it assigns one SCV each. Only a fixed proportion of the total SCV force is allowed to repair at a given time, so that mining is not impeded too much.
• It repairs buildings other than bunkers and turrets only after they fall to half health. If it’s only a hurt a little, it’s not worth it. Mining is the priority.
• In a build order, the command "go lift [terran building type]" lifts all buildings of that type which are able to lift. For example, "go lift engineering bay" lifts all engineering bays that can lift. If a building is producing a unit or researching, it is not able to lift and ignores the command.
I originally wrote up lifting while working on the scout boss. Since the scout boss is deferred, there is currently no code to tell the lifted building to do anything. It can’t land and it doesn’t move, it just floats in place. Lifting is limited, but it does free room in the base for other buildings.
• The strategy manager automatically lifts any barracks and engineering bays when the opening is complete and the build calls for factory production only. So you should rarely need to use the lift command in a build.
• In build orders in the config file, some upgrades used to require the race name, like "zerg flyer attacks". That still works, but now if you prefer you can leave out the race and write only "flyer attacks". It was a missing case in the parser.
• Build sunkens at outlying bases to provide some defense against vulture raids, sneaky dark templar, and small drops. If Steamhammer suspects that one of those specific things may be coming, it builds a single sunken colony at each base that it expects may be in danger—for drops, that means every base, while for ground raids it skips the sunken at main bases in the hope that a sunken at the natural will be enough. The aim is to add the minimum of static defense. ZvZ is not affected. I expect this to be most effective against terran vulture raids, reducing drone losses and giving the zerg main army time to react.
• Against valkyries or corsairs, get air armor a little earlier. It will help for the rest of the game.
• If we have gas-heavy hive tech, make extractors more freely. I keep telling Steamhammer, “Hey, this is late game already, what’s the holdup? Why haven’t you taken gas at every base?” Somehow I can never accelerate the late-game extractors enough.
Steamhammer 3.1 is almost ready. It needs a small amount of tuning and a larger amount of testing. The new feature I wrote should help with a certain weakness in ZvT and ZvP; it is less than 50 lines of code plus a tidbit or two of infrastructure, hardly a major feature. If no big issues come up in testing, I’ll upload it in a day or two.
Earlier I wrote up a game proxy versus proxy of Steamhammer and Krasi0P, where Krasi0P played its cannon contain strategy. To show Krasi0P’s other choice, here’s a game where Steamhammer played similarly and Krasi0P played its defensive cannon strategy, like so:
In the picture, Steamhammer has calmly morphed its proxy hatchery into a lair and started spawning drones in what it sees as a perfectly normal expansion. Never mind that the lair should be morphed where it won’t be seen immediately, and where it is less likely to be destroyed in passing. It happened to turn out well, since the lair had more HP. In the minimap we can see that zerg has also made a third hatchery at its natural. No hurry, after all protoss made cannons so a nice slow macro game should be in the cards, Steamhammer seems to believe. And in fact Krasi0P is adding another cannon beside its nexus for no apparent reason, and making its cyber core. First tech, then act, is its plan.
When zealots arrived, Steamhammer still had not made an army to handle them, much less a sunken as you would expect at a proxy hatchery. The drones had the sense to run away, and the zealots had the foolishness to chase them instead of focusing down the lair. They chased drones that they could not catch (almost all drones fleeing the proxy reached the zerg natural), and the proxy survived to keep making units.
Spawning drones that will soon have to make a run for it across the width of the map... is not objectively good. But it happened to turn out well, it distracted the enemy from what it should have done. That’s the story of this game, bad moves that worked.
Steamhammer chose lurkers as its first tech. It could not immediately cope with the corsairs, because most of its hydralisks morphed into lurkers. A number of overlords were shot down, and overlords were needed on the scene because dark templar were out for protoss. The lurkers succeeded regardless, though, because Krasi0P never answered them. Protoss made no observers, and the lurkers were in little danger from dark templar because they know not to unburrow when an undetected enemy is around to hit them.
Steamhammer not only narrowly saved its lair, it upgraded it to a hive. Proxy hive, have you seen that before? Once overlord speed finished, Steamhammer’s strong economy and steady upgrades meant that the day of corsairs and dark templar was over; the overlords accompanied an army strong enough to protect them; overlords were relatively safe and protoss with no expansion was outnumbered. Zerg busted the ramp cannons while starting to take additional bases, and the rest was cleanup.
Neither side had the skills to play the situation correctly. Krasi0P’s mistakes were more serious: It failed to kill the lair, it failed to counter lurkers, and it failed to send out a probe to expand to a more distant base. (Look at the mineral and gas counts. Krasi0P’s higher supply is because it has excess probes, enough for 2 bases even though it never expanded.) Steamhammer’s aggressive opening followed up with a macro game plan risked a quick loss, but because of protoss mistakes, it ended up putting zerg far ahead.
Well, I posted this game to have fun showing silly stuff. But I can’t help analyzing it.
Basic proxy skills were one of the major new features added in the current Steamhammer, version 3.0. It was preparation for the future more than a plan to earn cheesy wins: Steamhammer will need more skills before it’s any good at deciding when to proxy, and before it can execute well. And zerg doesn’t have many proxy opportunities in the first place, since it can only build on creep. Zerg can make a proxy hatchery, or versus another zerg (or in rare cases if there is neutral creep on the map) it can try an offensive sunken or offensive spore, that’s all. I was unsurprised when I checked a couple days ago and found that Steamhammer had recorded a total of exactly one proxy opening on BASIL, an ill-advised proxy hatchery in Microwave’s natural that went down for a quick loss.
Today I noticed another proxy attempt, and it’s a funny game: Steamhammer-krasi0P on Roadrunner. For background, #7 Steamhammer’s 60-day record against #11 krasi0P is 23-22, virtually even. So Steamhammer feels a need to keep experimenting to find better openings.
Steamhammer scouted at 5 supply, as soon as its first new drone hatched from the egg, which is necessary on a 4-player map if you want to find the enemy in time to drop a proxy hatch. The scouting drone went the wrong way while the overlord flew straight to the protoss base, but it made no difference; the drone scouted 2 empty bases and deduced the location of the enemy before the overlord came in sight of the nexus.
Krasi0P plays 2 related but different strategies, it either cannons up the exit of the enemy natural, or it cannons the entrance to its own base (and follows up about the same in either case). The 2 strategies are nearly identical from krasi0P’s point of view, but call for contrasting reactions from the opponent, “ha ha, it’s easy for me but hard for you!” In this game, krasi0P chose the forward cannons, so both sides are building in the enemy natural. It’s the Starcraft equivalent of Spy vs Spy; which will win this time? The picture shows Steamhammer’s spawning pool just starting as the cannons warp in; there is no hope of breaking the containment early.
Well, it was a funny start, but the rest is disappointing. The cannons were strong, but a hatchery is a production building and it can make units that go kill you. Krasi0P didn’t have any better defensive idea than to pull probes and lose them all. Once the protoss base was destroyed, the result was foreordained, even though Steamhammer becomes accident-prone when it has units on both sides of a contain: It blunderfully tries to join them into a single army. But all it had to do was kill cannons that could never be replaced, and it eventually did.
(By the way, are the pictures a good size? I have a bigger screen now and the images are not the same size as in past posts. You can click through to get the full size pictures.)
Well, so much for “back to normal.” My energy has improved somewhat but remains low. Let me try again.
I’m pleased with how well Steamhammer has held up without updates. It remains #1 zerg on BASIL, in the top 10 overall and above 2700 elo except for occasional wobbles. Other zergs have improved at ZvZ so that ZvZ is no longer Steamhammer’s top matchup—I let it coast too long on an edge it has held for years. Instead, improving win rates versus terran has made ZvT the best matchup. In the last 60 days, Steamhammer is 18% versus #3 Krasi0, better than even against the tricky #4 Halo by Hao Pan (Steamhammer is tricky too), and about even versus #5 adias, all good rates facing higher-ranked opponents. ZvP skills trail far behind and need the most work.
My plan for Steamhammer remains to release a version 3.1 with minor improvements soon-ish. My rate of work has been low. So far I have restored several small side features from the rolled-back scout boss version and made one new tweak; each step was a trivial amount of effort. I want to restore a couple more side features and write one new feature from scratch, and then I’ll call it done. I could do it in a day if I worked hard, but I think it will take longer....
I enjoyed Jealous as commentator last time. He contrasted well with the usual casters: Strong game knowledge, less familiarity with the bots so that their play looked fresh and surprising, and a slow and thorough style of examining the game events. Casters with varying approaches and knowledge make the casts more fun.
Commenting Broodwar games is a difficult skill! Even learning to consistently notice important events in the minimap takes practice and concentration.
After more than a year of coping with unhappy realities, at times slowly and at times intensively, I’m finally returning to normal. After passing through final blasts of stress and (as it seemed to me) sky-spanning arches of paperwork, only niggling details are left. I’m gradually recovering my energy.
I have only just restored a usable development environment—not that it was hard, I am still energy-limited. Before, I was working on an ambitious update to scouting and overlord safety, which involved refactoring, and in many cases entirely rewriting, all code related to scouting, detectors, and overlord movement. I guess that I left it about 25% complete. It’s an important improvement, but also somewhat monolithic, and for now I don’t have the brain cycles to work on it. I rolled it back, I’ll return to it later.
Instead, Steamhammer 3.1 will come out soon-ish and have a small number of improvements that are easy to write and easy to test. I will fix the expansion order, for example (that will improve games on Heartbreak Ridge especially).
Today is the last day to register for the annual CoG tournament (known as CIG until last year). Steamhammer will not be participating.
Steamhammer’s average game is kind of so-so, but its best games are good. Today it played an exciting macro game Steamhammer-adias on Jade. The game showed the strengths of Steamhammer’s queen play and burrowed zerglings, though adias shut the defilers down hard.
For background, Steamhammer’s 30 day record versus adias on BASIL is 17-10, so it wins more than it loses. But nearly all of its wins are with its cheesy hydra rush opening, in games like this one on Benzene: adias survives the rush, but it doesn’t know how to react and its build order breaks down so that it gets outmacroed and run over. Steamhammer is exploiting a bug.
The Jade game is different. Steamhammer opened with one of its anti-factory openings, the one that follows up with hydralisks. Adias set up to do its usual early game 2-vulture runby, but for some reason one of the vultures stayed behind and only 1 made it into the zerg main. It killed 2 drones before hydralisks nabbed it, not enough to set Steamhammer back severely.
A little later, after neatly clearing the spider mines in front of its base, Steamhammer went to attack with the hydras. Adias was in no danger, but it did lose a few goliaths unnecessarily due to clumsy maneuvering. That may have been why terran chose to take a third base, rather than build up and attack on 2 bases.
The picture shows terran trying to take its third base. The blood on the ground is from Steamhammer’s burrowed zergling. The zergling successfully delayed the expansion, but not for long because adias knew what to do: It brought tanks and scanned. Steamhammer also reacted correctly. In the minimap, the small orange splotch near the terran natural is a hydralisk attack which drew the goliaths out of position. Mutalisks went to the terran third and delayed it further. There are only 6 mutas, but they killed those 3 tanks and a number of followup terran units and delayed the third for longer than they should have. I think this was the key battle that set adias back far enough that Steamhammer could play a long game.
Adias did finally bring enough units to take its third safely. Terran with 3 bases is very strong, but Steamhammer now has 6 bases and is ahead in workers. By keeping terran busy with a handful of units, zerg was able to drone heavily.
The picture shows Steamhammer’s queen parasiting the first science vessel. The little orange dot halfway between them is the parasite projectile. Terran did not have irradiate yet. The queen kept busy parasiting vessels for the rest of the game. Adias did not react to the parasites, which handed Steamhammer another crucial advantage: Zerg maintained vision of the terran main army via the parasites, and almost always knew its location, size, and composition.
Adias is no pushover and it has its own strengths. Here a vulture raid has cleared the drones from one of Steamhammer’s bases. Steamhammer went from well ahead to about even in workers. Adias pulled these raids repeatedly. But unlike terran, a zerg with a strong economy can replace lost drones in short order. The raids did ensure that terran could firmly secure its third.
OK, now terran has irradiate. Steamhammer has code to separate an irradiated mutalisk, and it worked when I wrote it, but bits decayed and now it does not work. It’s a devastating weakness. 6 mutalisks and a few scourge died to this one irradiate, and the surviving muta had a sliver of health.
But irradiate a hydra and it burrows to spare its comrades. This came up later in the game.
Here is terran’s big attack, the intended killing blow. The armies of both sides are disorganized. Steamhammer has just cleaned up another vulture raid at lower right (by the time the vultures were dead it had already restored its drone count) and is rushing back, while adias (perhaps hurrying to take advantage while zerg is out of position) has allowed its units to stretch into a narrow column. The line of tanks and goliaths continues north of this wide picture.
Well, zerg is more mobile. Steamhammer got its forces together before adias could sort its units into a ball, and rolled up the terran column with hydra-ultra. The picture shows adias dropping Steamhammer’s natural while this happens. Shortly after this, vultures raided the 4 o’clock base too. The terran army has been forced back, but the worker count went into terran’s favor, and adias still has 2 bases mining.
The scourge on the tail of the dropship did finally catch it after it reached the terran main. Almost safe! I think Steamhammer’s scourge control has a bug that causes it to chase some enemies too slowly.
Oops, the terran army retreated to the natural, not to the third base. A small flight of 7 mutalisks, after erasing the dropped units, arrowed to the undefended third base and started to erase it too. Well, after defending adias still had enough SCVs, partly because its natural was running low, but Steamhammer had replaced its drone losses and was pulling ahead. Steamhammer suddenly switched to mutalisks as its primary unit, and was able to produce them faster than adias could produce goliaths to defend. In the picture terran and zerg are equal in supply, but adias could not hold against the mutas. Terran had the wrong unit mix.
The mutalisks depopulated the terran third, and then there was nothing adias could do. Another devastating irradiate finally forced the mutalisks back (most of the survivors were barely alive), but by then adias had only 14 SCVs and a smaller army size. Steamhammer soon maxed and ultraling finished it. For the cherry on top, the queen infested the main command center.
From Steamhammer’s point of view, the game was all about information. Even though adias knew how to counter it, the burrowed zergling saw what was happening before it died and made it possible for Steamhammer to delay the terran third. Then the queen’s parasites ensured that Steamhammer always knew the terran unit mix. Steamhammer used the information to make sudden switches in its own unit mix to take advantage of temporary opportunities.
This was a great game to show off the weaknesses of both sides. Adias repeatedly ran into trouble because it could not keep its units in good formation. Steamhammer needed to frequently replace dead drones, and suffered in the air from irradiate.
In the next game, on Circuit Breaker, Steamhammer repeated the opening, but the game went differently. Adias did its 2-vulture runby before Steamhammer was ready, killed a bunch of drones, and pulled far ahead to win easily. I made a version of an anti-factory opening timed to stop the 2 vultures, but this was not it.
I’ve mentioned it briefly before, but here’s a longer post. It is past time to start writing serious machine learning methods into Steamhammer. I’ve been writing code for it behind the scenes, though none is in Steamhammer yet, even in the development version. I selected a combination of techniques that will learn fast, will run fast, and I hope will be accurate enough. Right now I need to fix a numerical precision problem (I’ve always hated numerical analysis), but soon it should be ready to start testing on non-toy problems. It won’t be in the next Steamhammer 3.1, but perhaps a version or two after that, if all goes well.
The first application will be a “will I win this game?” evaluation function. The idea of evaluation functions is very general: You can evaluate anything, “how good is this build order?” “am I likely to win this fight?” “which tactical maneuver is better, A or B?”—anything you want to measure or compare, really. The use of evaluators is also very general. Whenever you want to make a choice, if you have the right evaluator and you can provide it the right inputs, you can compare the choices and pick the one that looks best. That is what search is, and search is one of the most basic ideas in AI.
The “am I winning?” evaluator will take several hundred numbers as inputs, unit counts and things like that. You can see my 2018 analysis of LastOrder for some of the possibilities. The output will be an evaluation of how likely Steamhammer is to win from the game position, I think a probability or something that can be converted to a probability. My initial estimate is that it should run in under 5 milliseconds. It doesn’t need to be run often, so even if that’s optimistic it will be fast enough. If it works as well as I hope, it will be possible to specialize the evaluator for each opponent. If that succeeds, there will be a pre-learned evaluator for unfamiliar opponents, and learning data in the opponent model will update it to understand that player. I’m seriously expecting the learning to be fast enough for that to help, though we’ll see.
The first use of the evaluator will be to select openings. Right now Steamhammer keeps tabs on whether a given opening won or lost. The bot does not know, at least until it plays a lot of games, whether it won because the opening gave it a huge strategic advantage, or whether it was behind after the opening but managed to scrape a win anyway. The evaluator will tell it, and it will select better openings. For example, against a much stronger opponent Steamhammer rarely wins and falls back on trying builds at random, hoping to hit one that works. Most of the random choices are poor, but it is losing every game anyway so it can’t tell. The evaluator will tell it which tries are more nearly successful; it will try those more often and have better chances. That is only an example; I expect the evaluator to help against most opponents.
A later use of the evaluator will be to construct new builds. I have plans in mind. There is already code in Steamhammer—it’s not finished or working, but the nub of the idea is there—to simulate build orders. When that is in place, Steamhammer will be able to evaluate builds that it has never played in a real game and get an idea of whether they will work. “I got run over fast. If I substitute 12 pool for 12 hatch, am I ready in time?” If that succeeds, Steamhammer will be able to customize builds to counter specific opponents. The potential is great, and this evaluator is a key step on the way.
Starcraft gives the players many many choices. It’s not possible to search any large proportion of them. In the search/knowledge tradeoff, I think that means that knowledge is preferred: You want to search few choices (at least compared to how many there are), but select and evaluate the choices with a lot of knowledge. That’s why I think that knowledge-rich machine learning methods are the right way.
Steamhammer versus BananaBrain on Moon Glaive was a fun back-and-forth game. Well, it was Randomhammer as zerg, that’s Steamhammer.
Steamhammer opened with a fast hatchery before pool, preparing zergling aggression. BananaBrain was also aggressive; it hid 2 gateways on the left of the map where they were unlikely to be scouted early. The gateways were more or less midway by ground between the 2 bases where zerg might be.
The zerglings outfought the zealots, then made a beeline for the protoss base, where they wrecked the economy. Protoss was left with 1 probe mining and 1 more in production.
But protoss had still been producing army during the attack, though the units were too far away to defend the main. It’s the drawback of a proxy opening: Close to the enemy means far from home. Steamhammer did not see the units and concluded that it was safe, so it started a third base (see 8 o’clock in the minimap), added a hydralisk den, and morphed a lair in its natural. A good human player would have predicted the protoss army size and been ready for it, but bots to date are weak at inference. Steamhammer could not save the lair in its natural and threw away units trying, then pulled together a defense in its main barely in time. BananaBrain ran by the sunkens to attack drones, one of its great skills, and it was zerg’s turn to fall behind in economy. Notice how much the protoss probe count has recovered. The zerg drone count fell to 5 shortly after the picture.
Three drones escaped the carnage and ran across the map to the hidden zerg third, which protoss did not yet know about (though a human player would have guessed its general location from the direction of arriving units). After a short distraction when a small zerg squad again attacked the protoss main, BananaBrain put heavy pressure on the defended zerg main. Both sides were racing to rebuild workers and trying to afford tech.
It was around here when BananaBrain repeatedly tried to expand, and Steamhammer’s patrolling Recon squad repeatedly denied it with only a few units. Protoss chose to keep attacking rather than defend an expansion. BananaBrain has added tech and sent out corsairs, and zerg protected its overlords with a spore colony in the main. Steamhammer’s mineral bank of 900 is a sign that it is short of hatcheries—it knows that, and wants to add hatcheries.
Needing more hatcheries, Steamhammer also tried to expand, in a rather strange pattern where the first hatchery at a new base was offset and the second one placed at the base location. The natural was denied, then a new base at 10 o’clock was about to be killed by zealots—when a scouting observer finally ran down the left of the map and discovered the hidden base, now bustling with drones. The protoss army suddenly had a more alluring target, and ran there to raze it.
But Steamhammer had mined its third base for most of the game, and BananaBrain had never been able to expand. The protoss main was dry, and the zerg 10 o’clock now had a half dozen drones at work, and it shows in the production tab. Steamhammer scourged the sky of corsairs, defeated the zealots with hydra-ling and a few mutalisks, and tore down the proxy gates before finally tackling the protoss main.
Whew, no big fights because of the damaged economies, but an exhausting struggle. Either side could have won easily at various points with smarter play at that moment.
I have given Steamhammer a primitive ability to lift terran buildings. A terran opening can include a command like "go lift engineering bay" and every ebay that can lift, will. If it’s busy researching, it can’t lift. The StrategyManager code that manages terran production will lift every barracks and ebay if the plan calls for all factory production, so the command doesn’t have much practical use for those writing openings. Still, the lifted buildings will leave more space available in the main base, so fewer factories should end up in the middle of the map.
I thought the work would be trivial, but I had to make more changes to the parser than I expected. Now aMacroActis able to parse and remember a command with aUnitTypeargument, in case I ever add any more commands like that.
Floating buildings are controlled by the new Scout Boss, which will find something useful for them to do. That’s why I added lifting now. I am also looking ahead: Lifting an infested command center is a zerg skill, and I’d like to be able to do that when appropriate. Steamhammer infests command centers on a regular basis, much more often than I’ve seen any other player do, bot or human.
You’ll need to write code if you want to lift off a specific building: Just this ebay that I built forward for scouting, not the one at home. A simple command has no way to specify. Still, I would like the production system to be able to tie production to specific units: Morph these hydras to lurkers, not the others; make this creep colony into a spore and that one into a sunken. I’ve seen only one game where it tried to make a spore (in main) and sunken (at natural) at the same time and got them switched, but it seems like something I had better get right.
Landing is not as easy as lifting off, because you have to decide where to land, and it depends on what you’re aiming for. Someday I’ll implement lifting off an endangered building and landing it again when the area is safe. It may involve ordering your own units out of the landing zone. That will likely be the first use case for landing. I think other cases will wait until there is an operations planner: Opening and closing “gates” in a wall, relocating a command center, floating in a proxy factory, reacting to enemy tricks like blocking the machine shop with a pylon....
Does Steamhammer’s updated gas steal skill help it win games? I ran an analysis on Starcraft AI Ladder games to find out. Each of these tables represents data from 100 games against that opponent.
“Gas steal decision” means Steamhammer decided to try to steal gas. It gives the number of games it made the decision and the time when it decided, along with the win rate and the enemy gas timing in games where it decided to steal gas. “Gas steal success” counts games where it succeeded in making the extractor on the enemy geyser. That’s more important than making the decision. “None or failed” means games other than successes, and “gas steal killed” is the time the extractor was destroyed, given that it was made in the first place. The “enemy gas” column is the median game time when the enemy was first observed to use gas (they made a building or unit which costs gas); the purpose of stealing gas is to delay this time. When it is “-”, that means the enemy was never observed to use gas before the game ended.
| gas steal | # | median | early | late | wins | enemy gas |
|---|---|---|---|---|---|---|
| gas steal decision | 18 | 2:24 | 2:01 | 2:58 | 22% | 5:32 |
| gas steal success | 13 | 2:33 | 2:10 | 3:08 | 23% | 6:38 |
| none or failed | 87 | - | - | - | 21% | 4:49 |
| gas steal killed | 13 | 6:01 | 2:51 | 12:31 |
| gas steal | # | median | early | late | wins | enemy gas |
|---|---|---|---|---|---|---|
| gas steal decision | 15 | 2:35 | 1:47 | 3:40 | 33% | 4:06 |
| gas steal success | 6 | 2:43 | 2:13 | 3:09 | 0% | 5:59 |
| none or failed | 94 | - | - | - | 34% | 4:09 |
| gas steal killed | 6 | 3:12 | 2:46 | 3:38 |
| gas steal | # | median | early | late | wins | enemy gas |
|---|---|---|---|---|---|---|
| gas steal decision | 6 | 2:32 | 2:01 | 3:25 | 50% | 3:37 |
| gas steal success | 1 | 2:04 | 2:04 | 2:04 | 100% | - |
| none or failed | 99 | - | - | - | 64% | 4:15 |
| gas steal killed | 1 | 2:26 | 2:26 | 2:26 |
| gas steal | # | median | early | late | wins | enemy gas |
|---|---|---|---|---|---|---|
| gas steal decision | 15 | 2:13 | 1:53 | 5:06 | 73% | 5:58 |
| gas steal success | 12 | 2:25 | 2:01 | 5:08 | 67% | 6:06 |
| none or failed | 88 | - | - | - | 78% | 4:57 |
| gas steal killed | 12 | 3:53 | 2:35 | 6:04 |
| gas steal | # | median | early | late | wins | enemy gas |
|---|---|---|---|---|---|---|
| gas steal decision | 10 | 2:21 | 2:06 | 2:51 | 90% | 5:17 |
| gas steal success | 6 | 2:22 | 2:09 | 2:36 | 83% | 5:30 |
| none or failed | 94 | - | - | - | 90% | 4:55 |
| gas steal killed | 6 | 3:06 | 2:48 | 3:16 |
| gas steal | # | median | early | late | wins | enemy gas |
|---|---|---|---|---|---|---|
| gas steal decision | 11 | 2:11 | 2:00 | 2:51 | 73% | 2:48 |
| gas steal success | 1 | 2:16 | 2:16 | 2:16 | 0% | - |
| none or failed | 99 | - | - | - | 61% | 2:52 |
| gas steal killed | 1 | 7:25 | 7:25 | 7:25 |
Conclusion: The important rows to compare for each opponent are “gas steal success” versus “none or failed”. The numbers say that a successful gas steal does delay the enemy’s gas use. That is why Steamhammer tries it so often—it takes that as a sign that the trick is working. But by and large, stealing gas doesn’t lead to a higher win rate. These opponents can cope with having their gas stolen, at least as Steamhammer does it.
Maybe I should tone down the vespene theft. I have the impression that most opponents which are discombobulated by the gas steal are ones that Steamhammer will defeat anyway.
I thought I’d take the opportunity to update the script that analyzes Steamhammer’s learning data files to handle the new game record format.
Since yesterday, on the Starcraft AI Ladder both Microwave and Halo by Hao Pan have been updated. Halo in particular is performing better. Here’s the new crosstable, just for background, showing the new results since the ladder was reset yesterday.
| # | bot | overall | bana | halo | stea | micr | ecgb | purp | zzzk |
|---|---|---|---|---|---|---|---|---|---|
| 1 | bananabrain | 82.41% | 67% | 78% | 72% | 100% | 100% | 78% | |
| 2 | halo | 71.56% | 33% | 72% | 67% | 84% | 97% | 76% | |
| 3 | steamhammer | 56.94% | 22% | 28% | 67% | 81% | 89% | 56% | |
| 4 | microwave | 56.48% | 28% | 33% | 33% | 72% | 100% | 72% | |
| 5 | ecgberht | 36.41% | 0% | 16% | 19% | 28% | 75% | 81% | |
| 6 | purplewave | 17.59% | 0% | 3% | 11% | 0% | 25% | 67% | |
| 7 | zzzkbot | 28.57% | 22% | 24% | 44% | 28% | 19% | 33% |
And here is the analysis of what Steamhammer learned against each opponent so far. This is only a small part of the information that can be extracted from the game records; many more tables and charts are possible.
| opening | games | wins |
|---|---|---|
| 11Gas10PoolMuta | 4 | 25% |
| 11HatchTurtleHydra | 1 | 0% |
| 4PoolHard | 1 | 0% |
| 9PoolHatchSpeedAllIn | 1 | 0% |
| AntiZeal_12Hatch | 4 | 25% |
| Over10HatchBust | 10 | 50% |
| OverhatchExpoMuta | 1 | 0% |
| OverhatchLateGas | 1 | 0% |
| Sparkle 2HatchMuta | 13 | 31% |
| ZvZ_Overgas11Pool | 4 | 25% |
| 10 openings | 40 | 30% |
| plan | predicted | recognized | accuracy | |||||
|---|---|---|---|---|---|---|---|---|
| count | games | wins | count | games | wins | good | ? | |
| Heavy rush | 3 | 8% | 33% | 4 | 10% | 25% | 33% | 0% |
| Naked expand | 1 | 2% | 0% | 5 | 12% | 80% | 0% | 0% |
| Proxy | 1 | 2% | 100% | 1 | 2% | 0% | 0% | 0% |
| Safe expand | 30 | 75% | 27% | 12 | 30% | 17% | 27% | 37% |
| Turtle | 5 | 12% | 40% | 4 | 10% | 50% | 0% | 60% |
| Unknown | 0% | 0% | 14 | 35% | 21% | 0% | 0% | |
| timing | # | median | early | late |
|---|---|---|---|---|
| my combat unit | 37 | 3:06 | 1:47 | 3:11 |
| my gas | 35 | 2:35 | 1:33 | 4:22 |
| enemy scout | 40 | 1:58 | 1:25 | 3:02 |
| enemy combat unit | 39 | 4:09 | 2:19 | 5:46 |
| enemy gas | 30 | 4:53 | 2:57 | 10:13 |
| enemy air unit | 30 | 5:27 | 2:58 | 11:35 |
| enemy cloaked unit | 20 | 6:47 | 3:29 | 12:54 |
| game duration | 40 | 10:12 | 4:46 | 29:56 |
| opening | games | wins |
|---|---|---|
| 2HatchLingAllInSpire | 2 | 0% |
| 7-7HydraLingRush | 1 | 0% |
| 9PoolExpo | 9 | 33% |
| 9PoolSpeed | 1 | 0% |
| 9PoolSunkHatch | 12 | 42% |
| 9PoolSunkSpeed | 1 | 0% |
| AntiFact_13Pool | 5 | 20% |
| AntiFactory2 | 4 | 25% |
| Over10PoolLing | 1 | 0% |
| 9 openings | 36 | 28% |
| plan | predicted | recognized | accuracy | |||||
|---|---|---|---|---|---|---|---|---|
| count | games | wins | count | games | wins | good | ? | |
| Factory | 7 | 19% | 29% | 5 | 14% | 60% | 43% | 0% |
| Fast rush | 10 | 28% | 60% | 9 | 25% | 33% | 10% | 40% |
| Proxy | 18 | 50% | 11% | 17 | 47% | 6% | 56% | 6% |
| Unknown | 1 | 3% | 0% | 5 | 14% | 60% | 0% | 0% |
| timing | # | median | early | late |
|---|---|---|---|---|
| my combat unit | 36 | 2:22 | 2:13 | 3:31 |
| my gas | 34 | 4:02 | 1:34 | 5:03 |
| enemy scout | 36 | 2:39 | 1:17 | 8:23 |
| enemy combat unit | 36 | 2:29 | 1:55 | 4:27 |
| enemy gas | 32 | 5:47 | 3:00 | 6:42 |
| enemy air unit | 16 | 12:20 | 5:34 | 16:35 |
| enemy cloaked unit | 22 | 9:37 | 5:34 | 17:11 |
| game duration | 36 | 12:31 | 5:16 | 31:21 |
| opening | games | wins |
|---|---|---|
| 9Hatch8Pool | 1 | 0% |
| 9PoolHatchSpeedAllInB | 1 | 0% |
| 9PoolSunkSpeed | 2 | 0% |
| Over10PoolLing | 1 | 0% |
| OverpoolSunk | 13 | 77% |
| ZvZ_Overpool9Gas | 18 | 78% |
| 6 openings | 36 | 67% |
| plan | predicted | recognized | accuracy | |||||
|---|---|---|---|---|---|---|---|---|
| count | games | wins | count | games | wins | good | ? | |
| Fast rush | 4 | 11% | 25% | 1 | 3% | 0% | 0% | 75% |
| Heavy rush | 19 | 53% | 74% | 6 | 17% | 100% | 16% | 68% |
| Naked expand | 10 | 28% | 80% | 3 | 8% | 33% | 0% | 70% |
| Turtle | 1 | 3% | 100% | 2 | 6% | 100% | 0% | 0% |
| Unknown | 2 | 6% | 0% | 24 | 67% | 62% | 0% | 50% |
| timing | # | median | early | late |
|---|---|---|---|---|
| my combat unit | 36 | 2:25 | 2:17 | 3:05 |
| my gas | 36 | 2:05 | 1:54 | 3:19 |
| enemy scout | 36 | 2:33 | 1:27 | 4:26 |
| enemy combat unit | 36 | 2:37 | 1:54 | 3:18 |
| enemy gas | 27 | 4:32 | 2:48 | 11:16 |
| enemy air unit | 21 | 6:49 | 3:46 | 11:17 |
| enemy cloaked unit | 0 | - | - | - |
| game duration | 36 | 12:07 | 3:21 | 25:44 |
| opening | games | wins |
|---|---|---|
| 2HatchLingAllInSpire | 1 | 0% |
| 2HatchLurkerAllIn | 1 | 0% |
| 4PoolHard | 2 | 50% |
| 9HatchExpo9Pool9Gas | 7 | 71% |
| 9PoolSpeed | 19 | 95% |
| 9PoolSunkHatch | 1 | 0% |
| AntiFact_2Hatch | 5 | 100% |
| 7 openings | 36 | 81% |
| plan | predicted | recognized | accuracy | |||||
|---|---|---|---|---|---|---|---|---|
| count | games | wins | count | games | wins | good | ? | |
| Factory | 9 | 25% | 67% | 7 | 19% | 43% | 22% | 56% |
| Heavy rush | 23 | 64% | 87% | 12 | 33% | 92% | 39% | 35% |
| Proxy | 0% | 0% | 1 | 3% | 100% | 0% | 0% | |
| Unknown | 3 | 8% | 100% | 15 | 42% | 93% | 0% | 67% |
| Worker rush | 1 | 3% | 0% | 1 | 3% | 0% | 0% | 0% |
| timing | # | median | early | late |
|---|---|---|---|---|
| my combat unit | 36 | 2:17 | 1:47 | 3:53 |
| my gas | 34 | 1:50 | 1:45 | 4:05 |
| enemy scout | 32 | 1:34 | 0:33 | 4:01 |
| enemy combat unit | 35 | 2:58 | 2:22 | 5:39 |
| enemy gas | 20 | 4:33 | 3:08 | 10:19 |
| enemy air unit | 15 | 5:42 | 4:06 | 15:09 |
| enemy cloaked unit | 9 | 5:53 | 5:30 | 11:34 |
| game duration | 36 | 5:42 | 3:59 | 18:52 |
| opening | games | wins |
|---|---|---|
| 11HatchTurtleHydra | 8 | 88% |
| 11HatchTurtleMuta | 3 | 67% |
| 12Hatch_4HatchLing | 2 | 100% |
| AntiZeal_12Hatch | 4 | 75% |
| Over10Hatch | 6 | 100% |
| Over10Hatch2SunkHard | 3 | 100% |
| Over10HatchSlowLings | 4 | 100% |
| OverpoolSpeed | 3 | 100% |
| OverpoolTurtle | 3 | 67% |
| 9 openings | 36 | 89% |
| plan | predicted | recognized | accuracy | |||||
|---|---|---|---|---|---|---|---|---|
| count | games | wins | count | games | wins | good | ? | |
| Fast rush | 0% | 0% | 1 | 3% | 100% | 0% | 0% | |
| Heavy rush | 34 | 94% | 88% | 18 | 50% | 89% | 50% | 38% |
| Proxy | 0% | 0% | 2 | 6% | 0% | 0% | 0% | |
| Safe expand | 0% | 0% | 1 | 3% | 100% | 0% | 0% | |
| Unknown | 2 | 6% | 100% | 14 | 39% | 100% | 0% | 50% |
| timing | # | median | early | late |
|---|---|---|---|---|
| my combat unit | 30 | 3:05 | 2:23 | 3:35 |
| my gas | 25 | 4:06 | 2:03 | 5:53 |
| enemy scout | 31 | 2:09 | 1:34 | 3:10 |
| enemy combat unit | 31 | 2:33 | 2:15 | 5:35 |
| enemy gas | 25 | 4:46 | 3:58 | 5:45 |
| enemy air unit | 5 | 4:19 | 3:58 | 5:33 |
| enemy cloaked unit | 8 | 4:36 | 3:59 | 4:51 |
| game duration | 36 | 5:57 | 0:01 | 8:09 |
| opening | games | wins |
|---|---|---|
| 6PoolSpeed | 1 | 0% |
| 9PoolSunkHatch | 2 | 50% |
| 9PoolSunkSpeed | 17 | 71% |
| OverpoolSunk | 17 | 71% |
| ZvZ_Overpool9Gas | 19 | 58% |
| 5 openings | 56 | 64% |
| plan | predicted | recognized | accuracy | |||||
|---|---|---|---|---|---|---|---|---|
| count | games | wins | count | games | wins | good | ? | |
| Fast rush | 49 | 88% | 63% | 14 | 25% | 86% | 22% | 69% |
| Heavy rush | 1 | 2% | 0% | 2 | 4% | 50% | 0% | 0% |
| Turtle | 6 | 11% | 83% | 6 | 11% | 67% | 50% | 0% |
| Unknown | 0% | 0% | 34 | 61% | 56% | 0% | 0% | |
| timing | # | median | early | late |
|---|---|---|---|---|
| my combat unit | 36 | 2:25 | 2:19 | 2:29 |
| my gas | 36 | 2:37 | 1:55 | 3:23 |
| enemy scout | 56 | 2:31 | 0:37 | 6:49 |
| enemy combat unit | 56 | 2:43 | 1:45 | 3:42 |
| enemy gas | 24 | 3:02 | 2:42 | 4:23 |
| enemy air unit | 29 | 4:37 | 3:51 | 8:07 |
| enemy cloaked unit | 0 | - | - | - |
| game duration | 56 | 7:51 | 3:11 | 12:24 |
| total | ZvT | ZvP | ZvZ | |||||
|---|---|---|---|---|---|---|---|---|
| opening | games | wins | games | wins | games | wins | games | wins |
| 11Gas10PoolMuta | 4 | 25% | 4 | 25% | ||||
| 11HatchTurtleHydra | 9 | 78% | 9 | 78% | ||||
| 11HatchTurtleMuta | 3 | 67% | 3 | 67% | ||||
| 12Hatch_4HatchLing | 2 | 100% | 2 | 100% | ||||
| 2HatchLingAllInSpire | 3 | 0% | 3 | 0% | ||||
| 2HatchLurkerAllIn | 1 | 0% | 1 | 0% | ||||
| 4PoolHard | 3 | 33% | 2 | 50% | 1 | 0% | ||
| 6PoolSpeed | 1 | 0% | 1 | 0% | ||||
| 7-7HydraLingRush | 1 | 0% | 1 | 0% | ||||
| 9Hatch8Pool | 1 | 0% | 1 | 0% | ||||
| 9HatchExpo9Pool9Gas | 7 | 71% | 7 | 71% | ||||
| 9PoolExpo | 9 | 33% | 9 | 33% | ||||
| 9PoolHatchSpeedAllIn | 1 | 0% | 1 | 0% | ||||
| 9PoolHatchSpeedAllInB | 1 | 0% | 1 | 0% | ||||
| 9PoolSpeed | 20 | 90% | 20 | 90% | ||||
| 9PoolSunkHatch | 15 | 40% | 13 | 38% | 2 | 50% | ||
| 9PoolSunkSpeed | 20 | 60% | 1 | 0% | 19 | 63% | ||
| AntiFact_13Pool | 5 | 20% | 5 | 20% | ||||
| AntiFact_2Hatch | 5 | 100% | 5 | 100% | ||||
| AntiFactory2 | 4 | 25% | 4 | 25% | ||||
| AntiZeal_12Hatch | 8 | 50% | 8 | 50% | ||||
| Over10Hatch | 6 | 100% | 6 | 100% | ||||
| Over10Hatch2SunkHard | 3 | 100% | 3 | 100% | ||||
| Over10HatchBust | 10 | 50% | 10 | 50% | ||||
| Over10HatchSlowLings | 4 | 100% | 4 | 100% | ||||
| Over10PoolLing | 2 | 0% | 1 | 0% | 1 | 0% | ||
| OverhatchExpoMuta | 1 | 0% | 1 | 0% | ||||
| OverhatchLateGas | 1 | 0% | 1 | 0% | ||||
| OverpoolSpeed | 3 | 100% | 3 | 100% | ||||
| OverpoolSunk | 30 | 73% | 30 | 73% | ||||
| OverpoolTurtle | 3 | 67% | 3 | 67% | ||||
| Sparkle 2HatchMuta | 13 | 31% | 13 | 31% | ||||
| ZvZ_Overgas11Pool | 4 | 25% | 4 | 25% | ||||
| ZvZ_Overpool9Gas | 37 | 68% | 37 | 68% | ||||
| total | 240 | 60% | 72 | 54% | 76 | 58% | 92 | 65% |
| openings played | 34 | 13 | 17 | 8 | ||||
These two games were played a few days ago, after Krasio was updated. Krasio apparently forgets its learned data on update, and against some opponents takes a few games to remember how to win again.
In Steamhammer-Krasio on Moon Glaive, Steamhammer started aggressively with overpool (overlord on 9 drones then spawning pool), and the early zerglings prompted Krasio to play defensively with a bunker at its ramp. But sneaky sneaky Steamhammer made few lings and instead added a second hatchery and teched to lurkers. Despite some clumsy zerg play, the lurkers delayed terran from expanding until around 11 minutes into the game. In the picture, lurkers are about to deny Krasio’s attempt to take its natural.
Krasio did at last successfully double-expand, but by then zerg was ahead and was soon able to destroy the terran third.
The next terran expansion was too far away to defend, and the rest of the game was zerg all the way.
Microwave-Krasio on Icarus, Microwave opened with a hatchery on 12 and went for mutalisks. The early mutas made more losses than gains, but notice the strong zerg economy. Microwave did not fall behind in supply for the whole game—a sign that Krasio was doing something wrong strategically, since the terran unit control was clearly superior.
In the middle game Microwave switched to ground units, overrunning Krasio’s third base in the lower left. For the late game it suddenly switched back into mutalisks and amassed a sky-darkening cloud. Mutas erased Krasio’s second attempt at a third base, in the bottom right, and then it was too late for terran.
Despite the different unit mixes and play styles, the games are strategically similar. In both, Krasio did not play its best opening and fell behind early. The zergs were able to roll up outlying bases with relative ease because terran did not have the mobility to defend them, and then were so far ahead that they could win by brute force.
Krasio wins when it starts well, of course, and it usually starts well once it has a little experience. The top zergs have gained enough skill to be a threat, though. Both have adequate macro and know how to choose a poorly defended expansion to attack, skills that many bots lack. In the last 7 days, BASIL gives Steamhammer 4-4 versus Krasio, and Microwave 2-5.
When you can’t defend your own expansions, you need to keep your opponent off-balance instead. It’s an advanced skill, and even Krasio does not have it. Against the lurkers, terran could have tried vultures, or drops, or perhaps wraiths—harassment that lurkers will be poor at responding to. Against the mutalisks, terran had enough valkyries to be safe, but seemed to deploy only 1 or 2 at a time in any given fight. Also, since terran was behind, the goliaths were not the best unit choice because they slowed down army movements. Without them, a larger marine and medic army would have been able to maneuver rapidly in defense, or cross the map to threaten zerg bases. I think bots are starting to play well enough that this kind of strategy knowledge will help.
This Steamhammer version is showing clear superiority over the previous one. I expected a small improvement that was hard to be sure of, but got an improvement that’s easy to see. Nevertheless, there is one new misbehavior: It takes bases in a poor order on some maps. On Heartbreak Ridge it takes the center base far too early, among other expansion order mistakes. Using the resource tracking info threw the base scoring out of whack, and my attempts to whack it back into whack were not enough. I have to hit it harder.
A funny picture:
Krasio is taking its third base as it should, and mining out the blocking minerals at a good timing so that it can transfer SCVs along the back path. Steamhammer has 2 drones in view. The drone on the right also wants to take the base, and is just noticing the command center in its way; it will give up and return home. The drone on the left knows, “We’re about to take this base, so I’d better clear this path that’s near it.” The SCV and drone are cooperating to mine out the stacked minerals, entirely to Krasio’s benefit.
Steamhammer stands at an advantage in this position, but ended up losing, most importantly because it took bases in the wrong order. Terran pushed out, and by the time zerg gained the strength to break the attack—which it did—the center base had already fallen. Many bots expand unsafely to that center base.