archive by month
Skip to content

Steamhammer 3.0’s new gas steal

Steamhammer’s existing gas steal skill works by UCB, like the opening selection of many bots. It has a bias toward not stealing gas, but the basic behavior is that it will steal gas if that wins more games than not stealing, or if it hasn’t tried a gas steal in a while and it’s time to give it another spin. It pays no attention to what the opponent is doing, so it will try silly things like stealing gas while under zergling attack from a 4 pool. The silly decisions hurt.

Steamhammer 3.0 will have a completely recoded gas steal skill using the skill kit, and it will be much fancier. In fact it got too complicated; today I finished rewriting it to simplify the rules. I’ll upload 3.0 as soon as it passes tests.

The skill records three values for each game: The frame a gas steal was decided on (0 if never), the frame when the refinery building was started, and the lifetime of the refinery (when did the opponent clear the gas steal?). Also newly recorded in the game record is the frame when the enemy was first observed to have spent gas on a unit or building.

All this information, plus a few other items like the recognized enemy strategy, goes into the gas steal decision. The outline is that various checks are made first to see whether stealing gas makes sense (“no, this enemy doesn’t take gas for a long time anyway”). If so, attempt a gas steal randomly with a certain probability until we’ve accumulated 5 games of experience with it. Once the data is in hand, adjust the probability up or down depending on the amount of evidence, with fudge factors to try to take certain strategic points into account (“versus 2 barracks? are you sure about this?”).

It’s still crude compared to the analysis I’d like to do. The ideal would be to figure out the effect of stealing gas on the enemy’s strategy and play, infer the best time to attempt it, and send a worker then to threaten it. But it should avoid many of the blunders that the current method makes.

Next: The Cadenzie-Locutus match.

KangarooBot, KasoBot, NuiBot, DTD Bot

I promised to write up the remaining newcomer bots. Despite my best efforts, I do occasionally keep my promises. Including Slater, which is the most succesful so far, we have 5 new bots that seem to be from 3 different sources. I’m surprised there are so many in such a short time. Did something happen out in the wide world?

Kangaroo Bot

Random KangarooBot from Australia—sorry, from Straya—has an attitude, and the attitude is “gosh darn it, no lazin’ around, the executive plan here calls for makin’ up more silly stuff, we have to put our backs into it.” Even in the code (github) I see variables like String currentBitch; (which can take on the value “Myself” among others) and String newDumbName = ““; (which can take on values like ShootyMcShootSiegeBot and McPurpleBraintus).

Kangaroo is developed from If Bot by the same author, which has a long history as a single .java file.

KangarooBot uses the ASS combat simulator and has a lot of tech skills. As a random player, it knows several terran builds, a few protoss builds, and one build per matchup as zerg. So far so good. The builds are all a little wonky, and the bot has a strong aversion to saturating its minerals with workers. So it often gets stomped (SSCAIT win rate 12%). But, you know, winning is not the main goal here.

KasoBot, NuiBot, DTD Bot

These are by fresh masters students at the Slovak University of Technology. They are newly created bots, so they’re simple for now. But as grad student projects, they aim to use cool tech, and if they succeed then in the future we may all learn lessons from them.

Terran KasoBot says “Currently using randomly selected strategy - automatically extracted from replay dataset (no manual build orders).” Downloading the binary from SSCAIT, I see a BO directory with JSON files of 12 build orders each for TvT, TvP, and TvZ. A build order looks like this:

{"items": [{"name": "Terran_Academy", "id": 112, "type": 2, "supply": 200, "frame": 10915}, {"name": "Terran_Armory", "id": 123, "type": 2, "supply": 200, "frame": 11431}, {"name": "Terran_Barracks", "id": 111, "type": 2, "supply": 22, "frame": 2161}, {"name": "Terran_Bunker", "id": 125, "type": 2, "supply": 200, "frame": 10529}, ...

... and so on for about 5K of text. The build order files are all roughly the same size in bytes. Presumably the randomly chosen build order file feeds to a build order interpreter that figures out how to execute the build order using some of the info in the file. In any case, since the BO items are not sorted by frame number, the files are hard to interpret by eye.

It’s a cool capability for brand-new code, though we don’t know where the replays came from, or how the data was extracted from them, or how the build order execution works. KasoBot’s play so far is weak; it is ranked last of all active bots on BASIL with a win rate of 5%. But it started off with something interesting, and I expect it will only grow more interesting as it progresses.

Zerg NuiBot’s description says nothing much. As far as I have seen, it plays a variety of pool-first builds from 5 pool to 12 pool and it attempts mass zergling attacks and techs to hydralisks. As a new bot, it often makes poor combat and macro decisions, and it has a bug that sometimes causes its drones to stop mining for no apparent reason. And that’s about all I know.

Protoss DTD Bot does not take any actions, even to send its probes mining, and wins only if the opponent plays a crash rush (that is to say, if the opponent crashes early). I hope the author is getting tech help! The description says the aim is to include a decision module using Long Short-Term Memory (LSTM).

ASL 9 games today

Today’s ASL 9 games (video) in the pro world were particularly exciting. If nothing else, I recommend the Stork-Larva game on Inner Coven. A number of the other games were also hard-fought.

I didn’t have time to watch, but I have 2 brain hemispheres, right? So I can do 2 things at once, right?

LetaBot in AIST S3

AIST S3 completed. Round up the usual suspects, you can see the results for yourself. There are replays for all the games, but no video so far. The replays are labeled “Round 1” through “Round 14”; you can read the round numbers (I would have called them match numbers) from the bracket diagram. I like seeing all the results at once, but if you prefer to follow the tournament without spoilers, you could download the replays at the top of the page, scroll down no farther than the picture of the initial bracket to match up replays with the tournament structure, and watch the replays by round number.

I was especially interested to see LetaBot by Martin Rooijackers. LetaBot, it seems to me, is strategically strong but suffers from many bugs. Its standard game plan is a classic terran strategy, defend while building up a large army, then bury the opponent in an avalanche of units. LetaBot knows a variety of specific defenses against different cheeses, and has reactions to enemy moves that threaten its game plan, so I think its potential is high. This version is updated to BWAPI 4.4.0, so possibly it has more updates besides. Martin Rooijackers long ago promised a stronger version with bug fixes.

Versus Dragon: I especially wanted to see this match because of the players’ opposite game plans. Dragon plays an early attack and harassment style. In game 1 of the best of 3, at about 2:35 into the game, Dragon sent its first 2 marines and 5 SCVs to breathe some fire. LetaBot luckily scouted in the right direction and timing to spot the force as it left Dragon’s base, and LetaBot had a bunker on its ramp in plenty of time. Fireproof. Dragon sent the SCVs home right away, but inexplicably continued to produce marines that it posted outside LetaBot’s natural. LetaBot appeared to read the situation and react; it made vultures and goliaths—a strong force when the enemy has fallen behind early—batted aside the marines, and continued straight on to Dragon’s base. Dragon had been preparing medics and tanks behind the scene for its next wave of aggression, leaving itself open to LetaBot’s timing, though LetaBot was well ahead even without that opening. Luck plus skill, 1-0.

In the second game, LetaBot crashed on startup. 1-1

In the third game, Dragon tried the same plan again. LetaBot did not get the lucky scout, but cross positions favored defense. Dragon seemed indecisive, sending SCVs forward and back before attacking with 7. LetaBot floated its barracks after 1 marine, Dragon’s SCVs defeated the marine and moved into LetaBot’s base, some blocking while one built a bunker for the following marines. LetaBot pulled SCVs to defend, and with more it easily won the worker fight, but the bunker completed. LetaBot pulled SCVs out as far as the center of the map to keep marines away from the bunker, but eventually retreated and let 2 marines enter. But the timing was OK, another SCV pull past the loaded bunker kept further marines away while a tank came out and kicked over the bunker; not perfect defense but more than good enough. Fire resistant. Dragon’s SCV attack left it far behind LetaBot’s cheaper SCV defense; LetaBot seemed to understand and quickly won with a tank-goliath attack. LetaBot advances 2-1 on its strong defensive and counter-attacking reactions.

Versus Locutus in the next round: LetaBot crashed 2 games in a row.

Versus BananaBrain in the loser’s bracket: LetaBot crashed 2 games in a row.

So... there might be bug fixes, but we didn’t get to see because there were bugs. :-(

what about the Torch Up tournament?

What ever happened with the Torch Up: FOSDEM’20 Brood War AI Tournament? All the pages saying to be ready by 25 January are still up, and I found a list of 11 participants, but I can’t find any sign of results, including at the FOSDEM 2020 conference which happened at the start of February.

It seemed like an interesting competition with some different decisions than other tournaments. The map pool, in a post that is mysteriously dated 9 March, includes Gold Rush, which has difficult features (Steamhammer struggles on that map, though it can still beat the built-in AI). Some of the optional challenge maps are extremely demanding—are these for a future iteration?

Did the tournament happen? Did it complete? Were the results perhaps announced to raised beers and general carousing so that nobody remembers them any more?

when will that enemy building complete?

Today I pretended to have enough time to play around, fired up my development vm for the first time in days, and took an hour out to solve a niggling issue: How do you correctly predict when an enemy building will finish? My first try gave inaccurate predictions.

If it’s your own building, call building->getRemainingBuildTime(), done. If it’s an enemy building, that doesn’t work. You can see the building’s hit points and predict its completion time from that, but it’s a little tricky. Today I learned the 2 tricks.

One: A building just starting construction doesn’t start at 0 hp and work up, it starts at 10% of its final hp. Over the course of construction, it progresses smoothly from 10% to 100%. Liquipedia on buildings explained it to me. Two: After the hp reach 100%, there is extra latency before the building is actually complete. I didn’t read OpenBW, but a few quick experiments let me measure the latency fairly closely. I got 2 frames for a terran building, 72 or 73 frames for a protoss building for the warping-in animation, and 9 frames for a zerg building. Knowing that, with one glance you can predict the completion of an enemy building to within a few frames (usually to +/- 1 frame in my tests).

    // Predict the completion of a building under construction from its current HP.
    // isBeingConstructed() is false for a terran building with no SCV building it.
    // It's also false for non-buildings, so we don't need to check that separately.
    // A morphed zerg building cannot be predicted this way, so skip those.
    if (unit->isBeingConstructed() && !UnitUtil::IsMorphedBuildingType(type))
    {
        // Interpolate the HP to predict the completion time.
        // This only works for buildings. The prediction is usually accurate to within a few frames.
        // Known cases where the prediction is wrong:
        // * The building was damaged.
        // * The prediction is made during the extra latency period (see below).

        // A building begins with 10% of its final HP.
        double finalHP = double(type.maxHitPoints());
        double hpRatio = (unit->getHitPoints() - 0.1 * finalHP) / (0.9 * finalHP);

        // Buildings have extra latency for their completion animations.
        int extra;
        if (type.getRace() == BWAPI::Races::Terran)
        {
            extra = 2;
        }
        else if (type.getRace() == BWAPI::Races::Protoss)
        {
            extra = 72;
        }
        else // zerg
        {
            extra = 9;
        }

        return extra + BWAPI::Broodwar->getFrameCount() + int((1.0 - hpRatio) * type.buildTime());
    }

Here unit is the building and type is equal to unit->getType().

As the code comments point out, there are ways for it to go wrong. It doesn’t work on a terran building if the constructing SCV has wandered off to play pinochle. It doesn’t work on a zerg morphed building, like a sunken colony morphed from a creep colony or a lair morphed from a hatchery, only on a zerg building made from a drone. If you shoot at the building and hurt it, you’ll get a wrong answer. If the HP have already reached 100% and the building is in its extra latency period, then there’s not enough information to know. I think all those issues can be corrected for if you make the effort, but I didn’t today.

Did I miss anything else? My short time was not enough for many tests.

Using the building completion times for enemy static defense will help the combat simulator avoid mistakes. And the times of tech buildings will help decipher the enemy build order.

Slater’s progress

I’m pleased with how Slater is coming along. The 2 March update fixed combat problems so that its units fight much more effectively. As I hoped, fixing the biggest weaknesses let it jump up from the bottom ranks.

Slater is still low-ranked, but as it climbs it adds to its roster of upsets.Locutus-Slater on Destination is a deserved win for Slater. Slater denied scouting, leading Locutus to choose a passive build that exposed a weak side to Slater’s strong side. As the chess saying goes, it is not enough to be a good player, you must also play well.

I think it is intentional that Slater likes to hold its army back a little from the front, even when an attack would be safe. A containment strategy puts less immediate pressure on the enemy, but not less pressure overall. If Slater learns to expand beyond 2 bases, the plan can become very strong.

an advantage for playing random on BASIL

And another new bot, the strange random KangarooBot whose builds are... unconventional. Read the github, it’s funny. But that’s not what this post is about.

Here are graphs of Steamhammer’s win rates by matchup followed by Randomhammer’s for the same matchups. Randomhammer is Steamhammer, I upload the same file for both. Any differences in play are due to the learning data—or to the opponent.

Steamhammer win rates Randomhammer win rates

The software has helpfully given the graphs different scales, so here’s the key data in a table.

matchupSteamRandom
ZvZ73%80%
ZvT73%75%
ZvP60%64%

On BASIL, when you play random, the server chooses your race and so both players know it from the beginning. The idea is to negate any advantage from playing random. And yet Randomhammer performs better than Steamhammer in every zerg matchup. Why is that?

Maybe the issue is that other bots do not learn by matchup, but pool all their learning data for each opponent. (Steamhammer learns each matchup independently.) It’s a reasonable thing to do for a traditional random opponent, in which the game chooses the opponent’s race and you don’t know it at first. It amounts to pretending that you don’t know the opponent’s race for learning purposes, so the opponent appears more unpredictable than it should.

Any other theories?

PurpleWave and PurpleDestiny show the same effect for protoss, by the way. MadMix is not as simple. But Randomhammer is the only bot that I’m certain has no configuration differences when playing random.

irradiate trivia question

If you irradiate a unit and the unit then enters a bunker or a transport such as a dropship, then the irradiation continues to function: The unit takes irradiate damage, and the damage splashes to other units in the bunker or transport. (It’s a way to save ground units from splashing their friends with radiation: Pick them up in an empty transport.)

If you irradiate a worker and the worker enters a refinery building, the worker takes no damage while inside. At least that’s what Liquipedia says. Apparently it gets a radiation rest break.

What about a queen infesting a command center? Does it continue to take irradiate damage while inside the command center? Can it die inside without finishing the infestation? Can it successfully infest the command center and not reappear because it died?

It should go without saying that this is critical knowledge that affects the course of every zerg game. It should be on page 1 of all player guides.

new openings in Steamhammer 3.0

Part of my regular change list for each new version is a list of openings I’ve added, so here’s another preview. The list is long this time, but easy to write up. Only a few of these openings are configured for regular play, but all will show up now and again.

Steamhammer’s new proxy skills enable a huge range of cheese builds. I wrote 2 or 3 for each race, sort of as samples.

terran

• In base proxy openings ProxyBBS and ProxyFactory. Ecgberht occasionally pulls out a similar proxy factory, which has scored wins over Steamhammer. These builds annihilate unready opponents but show execution weaknesses if the enemy is able to defend at all. BunkerNatural makes barracks in the center and bunker at the enemy natural, and scouts at a timing so that it just barely works reliably on a 4-player map.

10-10-10Vultures gets vultures earlier than the standard factory timing. I wrote this to test zerg reactions to fast vultures. Might as well keep it.

protoss

Proxy2Gate in a corner of the enemy base, which I haven’t seen another bot try, and CannonRushNatural with dragoon followup, also new to bot play.

zerg

Burrow versions of existing openings, zergling openings with different timings. It is part of my followup on the burrow skill. As burrow gains more uses in the future, these openings should show up more often. 6PoolBurrow 6PoolSpeedBurrow 8Hatch7PoolBurrow 8Hatch7PoolBurrowB 9PoolBurrowB 9PoolSunkBurrow OverpoolBurrow Overpool_3HatchBurrow 9Hatch8PoolBurrow 10HatchBurrow Over10HatchBurrow 3HatchLingBurrow 5HatchPoolLingBurrow.

Proxy openings: Proxy8HatchNatural makes a quick hatchery in the enemy natural and sunkens it up. AntiTyr and AntiTyrLurker are the same idea, but timed much later to counter the Tyr protoss build where it makes cannons in its base and builds up for a timing attack. AntiTyr serenely swallows the attack and wins. Steamhammer still needs a couple more skills before it can do Fried Liverpool.

AntiFactory2 is a slightly faster version of Steamhammer’s longstanding anti-factory opening, with hydralisks first. The original opening was timed to stop a 3-vulture runby, but lately a couple of terrans have been winning with a 2-vulture runby which is earlier and sneaks in before the defenses are ready. AntiFactory2 closes the gap. I configured it as a top answer to factory openings, so it should be fairly frequent.

11Pool is slightly faster than 12 pool for ZvZ, filling a small gap.

10HatchLing and 10HatchLing2 are specialized versions of 10 hatchery 9 pool which go all-in on zerglings.

• Experimental openings: Phlegethon I timed and showed to be inferior. The alternative 2x10Hatch (10 hatchery, 10 hatchery, 9 spawning pool with repeated use of the extractor trick) I have not timed, so in my ignorance I allowed myself to write variants 2x10HatchSlow 2x10HatchAllIn and 2x10HatchBurrow. The less I know, the more fun stuff I get, there’s a lesson!

Over10Hatch11Pool starts with the same extractor trick-overlord-hatchery sequence as a number of common Steamhammer builds, but inserts a couple extra drones before the spawning pool to build up the economy.

• Going the opposite direction, 3 hatcheries before pool but cutting drones to get the hatcheries faster than standard, are 12-11Hatch, 12-12Hatch, and 12-13Hatch. I was pleased with these and added 12-11HatchLing as a zergling all-in version.

2HatchLurkerPure is a variant 2 hatch lurker build which includes minimal zerglings, making drones instead, so that there’s a little more economy. I figure that if opponents lose because they are unprepared with detection, then the zerglings may not help much.

QueenRush and GuardianRush are not really useful except for testing (the only reason I wrote the queen rush in the first place). But then, I used to think the same about the hive rush build, until it scored wins over BananaBrain. At least they’ll be entertaining if they ever show up. The queen rush makes a half dozen queens with broodling nice and early in the game.

AIST S3 pairings

The AIST S3 pairings are out. Normally that would not be worth a post, it’s only first-round pairings. But it immediately struck me that there are 3 mirror matchups out of 4 pairings. It’s the maximum possible; there are 3 terrans and 3 protoss, so not all can be paired with the same race. If that happened to me I would have to step away from the computer, I would be tempted to rerun the pairings to get something “more random”—there’s an irrational reaction!

PurpleWave BananaBrain
McRave zerg Microwave
WillyT Locutus
Dragon LetaBot

How unlikely is it? Doing the combinatorics, I get 8! / (24 * 4!) = 105 possible pairings, of which 9 have the maximum-mirror property—3 ways to choose the protoss player, 3 ways to choose the terran, and after that choice everything else is fixed. That’s about 8.6%, not all that rare. It seemed more surprising than it should have.

Starting with mostly mirrors doesn’t affect the tournament much. We should have slightly fewer than average mirrors in the next round in both the winner’s and loser’s bracket; it will even out over the tournament.

I judge that BananaBrain, McRave, and WillyT have little chance to upset their stronger opponents. I’m excited to see skilled defender LetaBot play against the dangerous harasser Dragon. Is this LetaBot version much improved?