archive by month
Skip to content

Steamhammer status update

Steamhammer 1.1 is in the works. It is currently short 1 major feature, 2 smaller features, and 7 critical bug fixes that I know of, so it is still a ways off. When it does come out, the headline feature will be the ability to transition from one unit mix to another in the middle game. Currently, all transitions are written into the opening book, obviously a severe limitation. The work involves completely rewriting the macro code, and I’m only part way through.

I keep changing my mind about the order of improvements. Here is an outline of what I’m thinking today, so that when I do something completely different, nobody will be surprised.

The basic order of middle game skills should be mutalisk skills, then lurker skills, then drop and runby skills (which are related in a way). For the benefit of people who fork Steamhammer, I want to make sure that all races work and that the bot can play random—it’s theoretically possible today, but I haven’t tested it so expect some bugs. It’s also a priority to upgrade base defense in general and worker defense in particular. In long macro games Steamhammer 1.0 does stuff which is bananasuperbeyond boneheaded, which I’ll have to ameliorate a little at a time. Scouting has got to be worked on and must tie into tactical decisions better. Upgrades need to be more aggressive, and the first hive units should be ultralisks. I really really want to make a start on opponent modeling soon. And I have many other plans that I’ve written down but not put into priority order.

Anyway, here are today’s plans for the headline features of the next few versions. I’m expecting many extra features and fixes in 1.1 and few extras in 1.2 (and beyond that I don’t want to predict).

  • 1.1 - transitions
  • 1.2 - test and fully support random play, like UAlbertaBot
  • 1.3 - mutalisk reign of terror

After starting work on 1.1, I’ve already changed my mind twice about what to do when, and I may rethink again without warning. I shouldn’t try to plan further ahead.

Now I need to put my head back down and return to work.

2016 and 2017

Now that the new year—wait wait wait, how did it get to be February already? Well, I’ll go ahead and ignore the mistake in the calendar. No need to file a bug report, I’m sure they’re on it.

2016 brought big progress in BWAPI bots. Killerbot by Marian Devecka finished #1 in SSCAIT 2015 with a 96% win rate in the round robin, seeming nearly unbeatable. But even after late updates, it landed #6 in the SSCAIT 2016 round robin with 85% win rate. The 5 bots that finished above it had all seen updates repeatedly during the year.

Iron brought hyperaggression and amazing micro. Krasi0 fixed crashes and weaknesses and became more aggressive. Sudden sensation Bereaver put together a variety of skills in a balanced package to reach the top ranks. ZerGreenBot showed us the first skilled overlord hunting and the first skilled reaver drops, both of which were then picked up by Bereaver and Tscmoo protoss. Zia gave a taste of zerg variety with opening learning. Even ZZZKBot by Chris Coxe, less heavily updated than the others, proved that it is still possible to beat many opponents with prepared strategies. Overall, the meta shifted somewhat away from rush strategies toward macro play, though rush defenses need to be strengthened further before the shift will be complete.

In 2017 I see progress speeding up further. The community is larger and more active. I see people in the chat talking about their plans for new skills. Openbw is preparing new tools. Bots are playing an ever-wider range of strategies. The level of play is higher, and bot authors are adapting to it in a virtuous cycle of improvement. 2016’s top Krasi0 and Iron are updated, and so is Tyr by Simon Prins. Many of the fresh bots popping up during the post-SSCAIT surge are starting out stronger than new bots did last year (except for Bereaver, of course). I think both AILien and my own Steamhammer are at risk of becoming top bots and having to work to stay there, and the new from-scratch bots like McRave and ZurZurZur are improving rapidly and may catch up.

Even today’s entrant “Newbie Zergrush” is causing trouble for one opponent after another with its simple nonstandard opening of 8 hatch 7 pool (at least against protoss and terran; it played differently in its one game vs zerg so far). That rush gets zerglings over a minute later than 4 pool, but with 2 hatcheries the numbers grow fast and it seems that many bots were caught sleepy-eyed. XIMP did not add cannons or send defenders in time, and Krasi0 was surprised by the timing too. Steamhammer, by the way, knows a similar opening of 9 hatch 9 pool 9 gas, which gets the first lings 2 seconds later (seriously!) and also researches speed and boots up a stronger economy with greater chances to transition later. Steamhammer only plays it versus zerg, though. Now I’m thinking I should have enabled it versus protoss and terran too.

In 2017 I predict multiple bots with new skills of taking island expansions and carrying out doom drops. For Steamhammer I also plan deeper map analysis so it can do things like backdoor attacks when the map allows it. The tactics and strategy in bot play will grow more complex, and everybody will be scrambling to keep up.

SSCAIT semifinals and third place playoff, part 2

Today is the second and more interesting part of the SSCAIT 2016 round of 4. Krasi0 fought XIMP, with the winner to move on to the final. The loser went to a 3rd/4th place playoff match against Iron.

Krasi0 vs XIMP

Game 1 was on Empire of the Sun. XIMP is the carrier bot. Terran Krasi0 saw what was coming and chose to attack with tanks and early goliaths before the carriers had all their interceptors. The tanks were somewhat inefficient in sieging down the cannons (most bots are), but they were fast enough. XIMP was in trouble regardless, but losing too many probes sealed it.

Game 2 was on Heartbreak Ridge, a 2-player map. It has many cliffs which favor carriers, but it also has low-ground bases and a short ground distance between the mains, which favors mech attacks. Krasi0 attacked with the same timing as the previous game. Krasi0 again killed the natural, but terran reinforcements chose a path through the center which took them next to the protoss base, distracting XIMP into playing correctly against the reinforcements instead of the main terran force. Krasi0 could have sent fresh units the other way around the center of the map, where carriers could not have engaged them until they arrived. Then the mech army would have stayed compact.

But as it happened, the diversion toward reinforcements and Krasi0’s difficulty in attacking the protoss main through the very narrow entrance meant that the carriers were able to build up interceptor numbers. XIMP defeated the goliaths and started chasing the terrans away. Krasi0 sent goliaths piecemeal toward the front and lost them a few at a time.

While one carrier group fought terran units around the center, another group departed on XIMP’s trademark edge crawl to survey the bases around the map and attack from the rear, a slow but dangerous plan. Both players were in some trouble. XIMP had only its main left and no long future unless it could take and hold another base, while Krasi0 had 2 bases but not enough anti-air to stop the carriers. What would happen?

XIMP’s front carriers played poorly and lost numbers. They could have returned through the center to cover while XIMP retook its natural, or they could have joined the attack on the main where cluttered buildings made goliaths awkward, or they could have circled the terran natural and attacked it from above the cliff, but they insisted on attacking from the front without the advantage of a cliff. With that decision, Krasi0 had the lead. Terran should have sent its ground army, minus air defense, to the protoss base, which would either cause a base race or bring the carriers back home to defend. Instead Krasi0 left tanks and vultures idling around the center of the map. Krasi0 did not use its lead.

Neither side was making the most incisive moves, and the outcome was unforeseeable. Fun game!

Krasi0 got a third base up. XIMP had no money but destroyed the terran main, slowly. Krasi0 did not try to float its factories, but rebuilt from scratch instead. Finally Krasi0 built up enough stuff to start hitting carriers, and that was enough.

Both players fought like lions. After mistakes all around, the victory was narrow. Krasi0 won and went to the finals.

Lesson: You never know what little thing will make the difference. A small improvement by XIMP (try to attack from above cliffs, or destroy bases more efficiently) or a minor weakness in Krasi0 (build the 3rd too late, be unable to recover from losing all tech) could have given us a different result.

Iron vs XIMP

Iron is far more aggressive than Krasi0. Iron attacked with infantry and tanks, sieged down the cannons, held off carriers with marines and turrets, finally added valkyries almost as an insult, and won easily. The second game went about the same way. A group of carriers escaped and caused damage, but only until the undefended protoss base died.

It’s not easy to beat XIMP, or more bots would do it, but Iron made it look easy.

the big BOSS bug with zerg

UAlbertaBot includes BOSS, the Build Order Search System, which accepts goals like “I want 12 zerglings and the speed upgrade” and calculates how to achieve them as quickly as possible, including creating the spawning pool and extractor if necessary, adding supply, building the ideal number of workers, and the exact spending sequence for everything. It does make approximations, but the build orders it produces should be close to optimal for the goal you give. UAlbertaBot by default uses BOSS to oversee its production as soon as it gets out of its opening build order.

Unfortunately BOSS also has limitations and bugs. If you give it a complex goal, it can’t run in real time (though you can still use it to create opening builds offline). And for zerg, BOSS has the bug that it will sometimes throw in an extra building that is not implied by your goal, usually an extractor, hydralisk den, or lair. I only wanted zerglings, why are you giving me a hydra den?

Blog reader Micky Holdorf looked into that bug and found the cause. Thanks for the report!

BOSS wants to search efficiently, so given your goal, it calculates the prerequisites so that it doesn’t waste time searching actions that don’t contribute to the goal. It calls this the goalMax, the most of each thing that you might want in order to achieve the goal. For terran and protoss, BOSS recursively calculates all the prerequisites and carefully counts each. Here is the code for zerg, from DFBB_BuildOrderSmartSearch::setPrerequisiteGoalMax():

    else if (getRace() == Races::Zerg)
    {
        _goal.setGoalMax(ActionTypes::GetActionType("Zerg_Spawning_Pool"), 1);
        _goal.setGoalMax(ActionTypes::GetActionType("Zerg_Extractor"), 1);
        _goal.setGoalMax(ActionTypes::GetActionType("Zerg_Lair"), 1);
        _goal.setGoalMax(ActionTypes::GetActionType("Zerg_Spire"), 1);
        _goal.setGoalMax(ActionTypes::GetActionType("Zerg_Hydralisk_Den"), 1);
    }

That’s not a calculation, that’s a stand-in! This part of the code was never written in the first place. I wonder if there was a bug in the recursive calculation for zerg, and Dave Churchill put in a stub until it could be dealt with?

Anyway, the correct fix is to write that code. One workaround is to delete the setGoalMax calls for zerg and always pass in goals that include their own prerequisites; you have to remember that you might need a spawning pool, or notice that you’ve lost yours and explicitly put it in. Micky Holdorf found another workaround with the same effect, which tells BOSS not to worry about prerequisites at all. In DFBB_BuildOrderStackSearch::generateLegalActions() change the line

            if (!goal.getGoal(actionType) && !goal.getGoalMax(actionType))

to this, which tells it that only goals and not prerequisites are legal actions:

            if (!goal.getGoal(actionType))

I don’t have any plans to write a fix for Steamhammer. If somebody sends me one I’ll certainly consider it! But Steamhammer is moving away from BOSS, because BOSS answers the opening question “how do I get this stuff as fast as possible?” and not the middlegame question “how do I spend my resources efficiently?”

SSCAIT semifinals and finals, part 1

This post is about the boring stuff that happened in the SSCAIT semifinals and finals. I’m saving the most interesting games for a later post. It’s all part of my natural laziness—er, I mean, cruelty.

The round of 4, aka semifinals, was played as best-of-3. The winners moved on to the final, which was best of 5.

round of 4: LetaBot vs Iron

LetaBot played its SCV rush. Iron’s author Igor Dimitrijevic reported (in a comment) that Iron easily beats Stone’s SCV rush. But LetaBot’s rush is more aggressive than Stone’s, and LetaBot won 2-1.

Game 2 was the only interesting one. Iron did not adapt its build to the emergency and started a second factory instead of building a vulture from the first and winning. When Iron lost all SCVs, it still did not cancel the unfinished second factory and win. Instead, LetaBot was cleaning up Iron’s base and killed the second factory, releasing its cost so that Iron could build vultures from the first factory, which it did, and won.

Lesson: Apparently not enough opponents have put early pressure on Iron. It hasn’t needed to adapt in that time frame before!

round of 4: XIMP vs Krasi0

This match deserves more time, so I’ll write about it... hmm... the day after tomorrow.

finals: LetaBot vs Krasi0

SCV rush again, to the disappointment of many, and a LetaBot victory. The games are not much worth commenting on. I did notice that when Krasi0 ran short of SCVs it recalled the scouting SCV from LetaBot’s base, a cute emergency response that I promptly added to Steamhammer.

Now SCV rushbot Stone has been reactivated as I had wished. I expect that all actively-updated top bots will be able to cope with SCV rushes before the next SSCAIT. Iron and Krasi0 already have been.