archive by month
Skip to content

map analysis plans

One of my goals for Steamhammer is to remove the dependency on BWTA, a large, slow and troublesome library. Its startup time to analyze a new map for the first time is ridiculous, and I want full power to analyze map blocks. I could go to BWEM, and I may yet change my mind and do that. But I’m not 100% satisfied; I might have to modify the library to simplify hypothetical reasoning and add features like pathfinding for units which are pushed through minerals. Another idea is to start with UAlbertaBot’s existing distance maps. It calculates ground distances at build tile resolution (32 x 32 pixel tiles) rather than the walk tile resolution of the map (8 x 8 pixel tiles), but this doesn’t cause any obvious problems and is easy to change if necessary. UAlbertaBot doesn’t actually rely on many BWTA features.

I was leaning toward the native distance map solution already. It calls for writing more code, but not that much, and the final solution would end up simpler and better tailored. Now Dave Churchill has made exactly that change to UAlbertaBot. It smooths my path since I can borrow code, and I plan to follow.

Dave Churchill removed BWTA big-bang style from UAlbertaBot, dropping the dependency and replacing its major uses in one step. I think the largest piece was to add a BaseLocation class—not a large piece at all. My implementation strategy will be the opposite. I’ll replace uses of BWTA item by item, testing as I go, and when I’m satisfied I’ll drop BWTA. The development process should be gradual and stable.

As a first step I taught Steamhammer to pay attention to map blocks in calculating ground distance maps. It doesn’t notice when blocks are removed, or route units around blocks, it only calculates distances more accurately based on the map’s initial state. Even this small step improves play, since Steamhammer decides on expansion locations partly based on ground distance. Since I reflexively clean up any code that I touch, I also fixed a bug in checking whether a tile is walkable and reduced the unnecessarily large size of the data structures. Distance maps are better, faster, and cheaper—there should be less memory traffic in calculating a map, and lookups will be more compact in cache.

tricky bugs

Bugs can be deeply interconnected in obscure ways. Sometimes one appears after changes that seem to have no relation.

If you watch the latest Steamhammer, you’ll sometimes see idle drones in its base, sitting on the creep doing nothing. It happens especially when the bot has been holding off heavy pressure for a long time, as if its APM were not enough to keep up with managing its base. And I haven’t seen the bug in older versions.

It’s actually a primordial UAlbertaBot design flaw that happens to manifest now because of changes in Steamhammer that have nothing to do with drones. When ProductionManager sees that a building is coming up next, it checks whether it can save time by moving a worker to the building location immediately, so that construction can start as soon as resources are available. If you then insert something into the production queue ahead of the building—which parent UAlbertaBot will do when it realizes a sudden need for detection—then the building will come up again in the queue and the bot may send another drone, leaving the previous one idle. There is no tracking except the order of items in the production queue, which is unstable. The newest Steamhammer triggers it more often because its urgent reactions, the things it does when under heavy pressure, more often insert stuff into the queue ahead of buildings. Then of course the bug causes mining to slow down, so that the pressure breaks through, and the reactions end up backfiring.

By the way, ProductionManager ought to also check when tech for the building will be available. If you watch Steamhammer build its spire, sometimes you’ll see the building drone waiting in place, twiddling its zergy thumbs instead of working, well before the lair is finished. ProductionManager only checked the resources, so it thought the spire could start earlier and sent the drone too soon. I’ll fix it eventually, but it probably doesn’t lose more than 24 minerals.

I have seen the same bug in Arrakhammer. Microwave solves the bug by catching idle drones and putting them back to work. One older Steamhammer version did the same. Unfortunately, a drone that was about to start a building may be put back to work instead, causing a construction delay—that’s why I undid the change in Steamhammer.

Another solution would be to return drones when the queue is messed with. Steamhammer sometimes decides that an upcoming production item is useless and should be dropped; if it drops a building from the queue, which it sometimes does, that could cause the same bug. Messing with the queue behind the scenes needs to notify ProductionManager.

A more thorough fix would be to delegate all the work to BuildingManager. It’s awkward for drone pre-positioning to be in ProductionManager while the rest is in BuildingManager; better to keep the related parts together. If buildings are sent to BuildingManager before they can be constructed and BuildingManager is responsible for positioning workers, then the existing BuildingManager state (with the addition of an “in preparation” label for buildings that can’t be started yet) can keep track of which worker has been assigned to each building and avoid some construction delays that happen now when workers move around unnecessarily before starting the building. It’s more complicated, because messing with the queue then needs to notify BuildingManager. So I might go with the simpler solution.

Getting all the errors out of the infrastructure is hard. I have fixed about 10 bugs for the next version, but there are other basic infrastructure bugs that are as bad as this one, and I have fixed zero of them. They’re tricky. Meanwhile, the zerg emergency reactions also indirectly cause other errors in the strategy boss, sometimes preventing necessary tech switches....

experience with the updated SparCraft version

I’ve been playing with the new version of SparCraft by Dave Churchill. I made 2 Steamhammer versions which are identical except for the SparCraft version, so I can test for differences in various scenarios.

My conclusions so far:

1. The new version was not too much trouble to integrate. Throw out the old SparCraft folder, drop in the new one, tweak one Visual Studio setting since I’m using an older version, and rewrite a small amount of initialization code and calling code. There is a new SparCraft configuration file that has to go into bwapi-data/AI/. It’s not much work at all for swapping out a major component. I also removed a small amount of debugging code from SparCraft, but that wasn’t necessary.

2. Dave Churchill dubbed it “semi-stable”, and it’s true. It mostly works, but throws fairly often. I modified the try-catch in Squad to catch all exceptions, and return -1 “we lose” when SparCraft throws. Then the squads retreat, which simplifies the situation so that the errors don’t usually persist. It works well enough. Another idea would be to remember the results of the last successful run and reuse them. I didn’t try that.

3. It still doesn’t support bunkers, reavers, or carriers. That’s quite a limitation. The “let’s pretend this bunker is 5 marines” trick (or something like it) is still needed.

4. Results for battles among ground units seem about as good as before. Tests under controlled conditions would surely find differences, but I’m interested in real games first. For games which stay on the ground, the difference is smaller than I can see by eye and smaller than I can measure from game outcomes, at least so far.

5. Results for battles with air units are improved. Steamhammer with old SparCraft likes to suicide mutalisks. Steamhammer with new SparCraft will still do it, but less happily. It understands turrets and spore colonies better than before. It seems to have an advantage in straight air-to-air battles too, though that’s based on only a small number of test games.

6. Since air units have lost some of their overconfidence and retreat more often, the weakness of their retreating behavior shows more. Steamhammer has always had a tendency to string out its mutalisks due to poor retreating (and other causes), even when it should pull them into a tight knot. The new SparCraft makes it worse. The first couple mutalisks see a bunker and pull back “until reinforcements arrive,” and the reinforcements wait at home “until the outlook improves.” Fixing one weakness makes the next one starker! And it is an open question whether the cautious mutalisks will be as successful as overconfident mutalisks in harassment; they may pull back too early when they can’t win outright.

I haven’t measured the run time yet, which will be a crucial test. I hope the new version will turn out to be faster. Some day soon I will probably put up a test version on SSCAIT to see how it performs in the wide world. If I don’t hit any surprises, I may switch to the new SparCraft even if the remaining bugs don’t get fixed.

another Randomhammer upset

Randomhammer earned another upset, this time with protoss against Iron. The game is not too interesting, just a dark templar rush that Iron wasn’t ready for. Iron could have held by landing its barracks to close the wall until mines and turrets were done, but didn’t. Even so, it shows that Steamhammer can defeat any opponent with any race—at least occasionally when it gets lucky.

two upsets

Two surprise upsets today caught my interest.

new from MadMix

The game MadMix by Oyvind Johannessen vs McRave surprised me.

McRave fell out of the top ranks a while back, but has lately been climbing back up. I’m guessing that some new subsystem was switched in a while back, and it has taken this long to work the bugs out. After a long drought and a bunch of tries, the new version of McRave notched its first recent win versus Steamhammer today (and another shortly after). I expect McRave will keep rising and return to the top 5 before long.

MadMix is brand new, but already has a big update. The initial version made most units for all races, but never researched upgrades or tech. Today’s version researches most upgrades and at least some tech, so the mix is even madder!

In MadMix versus McRave, random MadMix rolled zerg and started off with fast lurkers. McRave is much higher ranked and has a better build order, better tactics, and better micro. McRave had a vastly superior force in the early game, but for some reason chose not to engage—mistake #1. When the lurkers came out, McRave had no detection and was contained despite MadMix’s poor combat skills.

MadMix slowly expanded to many bases while McRave was contained. McRave made a robo facility but never added an observatory, so it had no detection—mistake #2. I’m sure it’s an oversight or bug and will be fixed before long. McRave still could have made a nexus at its natural, added cannons for detection, and maintained a chance to win, but instead when the protoss main mined out, McRave resorted to long distance mining—mistake #3. Even so, McRave’s macro was stronger and the protoss army remained dominant. In smaller attacks, MadMix retreated support units and unburrowed lurkers each time targets moved out of range, so the forward lurkers tended not to live long. For a lurker, staying underground and restricting your enemy’s mobility can be more important than having a target.

McRave was strangely passive this game, moving its army mostly in response to immediate threats. With zerg on many bases and protoss long distance mining, the writing was on the wall. Eventually MadMix started mass attacks and broke through to win. The picture is from shortly after MadMix’s army first became the larger one (notice the worker counts). In the upper left you can see lurkers holding an isolated protoss force at bay; for some reason, MadMix made better use of its lurkers during the breakthrough attack.

MadMix upgrades tab

The upgrades tab shows that MadMix did a ton of upgrades this game, even overlord sight range. You can see scourge, and offscreen is a devourer, even though McRave never made an air unit. The zerg unit mix is genuinely mad. It did not make queens, which may mean that it realizes it needs to know how to use the spells first.

Maybe another update soon will see MadMix using most tech, too. In any case, MadMix is already ranked higher than Travis Shelton, the other random bot with a wide choice of units.

Randomhammer gets a win over Krasi0

Randomhammer scored an upset win over Krasi0 with a vulture drop. I knew the drops would pull some good wins.

Randomhammer (this time) sent its dropship the short way around the edge of the map to Krasi0’s base. Randomhammer’s vulture micro was disappointingly poor, but even so the drop was moderately successful; it killed few SCVs, but stopped mining for a surprisingly long time as Krasi0 cautiously backed away.You can see in the production tab that Randomhammer is expanding and adding units while Krasi0 is producing nothing.

Randomhammer’s drop

Krasi0 may have seen the building starport just before its scout was chased away by marines. In any case, it made goliaths with a few tanks mixed in, a good counter to the air units and vultures which were the only units it had seen indications of. But Randomhammer immediately switched to tanks (it’s a hardcoded tech switch—Steamhammer’s terran and protoss strategy is ultra-simple), and expanded not once, but twice.

Krasi0 delayed its expansion and did not have enough gas to make many tanks alongside the other tech it wanted. With 3 geysers, Randomhammer had greater tank numbers and was able to push through and win despite Krasi0’s superior tactics and unit control. Knowing how to position tanks on high ground is great, but if you have 2 tanks versus 6, it’s not great enough.

Randomhammer’s push

Steamhammer configuration parsing bug

Why doesn’t this version of Steamhammer ever play its 5 pool on SSCAIT? I found a bug in parsing the configuration file.

There’s a bug in parsing a strategy combo which is nested inside another strategy mix. The syntax as I intended to implement it is inconsistent, and the parsing code only partially takes that into account.

In Steamhammer as configured, the effect of the bug is that whenever it should play 4 pool or 5 pool, it plays its default 9 pool speed instead. In other words, there’s not much difference, but it does reduce the bot’s unpredictability a little. In a bot with a different configuration, the effect might be worse.

the fix

If you are using the code, the fix is to make the syntax consistent.

1. In ParseUtils::ParseConfigFile(), make this snippet of code look like this. All you have to do is change "StrategyMix" to ourRaceStr in 2 places.

			// If we have set a strategy for the current matchup, set it.
			if (strategy.HasMember(matchup) && _ParseStrategy(strategy[matchup], strategyName, mapWeightString, ourRaceStr, strategyCombos))
			{
				Config::Strategy::StrategyName = strategyName;
			}
			// Failing that, look for a strategy for the current race.
			else if (strategy.HasMember(ourRace) && _ParseStrategy(strategy[ourRace], strategyName, mapWeightString, ourRaceStr, strategyCombos))
			{
				Config::Strategy::StrategyName = strategyName;
			}

2. Make the matching change in the configuration file. Everywhere it says "StrategyMix", change it to the race of the bot at that point, like "Zerg". It’s redundant, but it’s the same syntax for strategy mixes no matter the context.

strange games

Two strange events.

let’s put the expansion right there

In a game versus Krasi0, Steamhammer decided to go three hatcheries before spawning pool. It’s a greedy opening, a sensible choice against Krasi0’s slightly less greedy opening. Of course, when you’re trying to win by greed you tend to scout late, so when it was time to place the 3rd hatchery, Steamhammer did not know where Krasi0 was. The expansion drone walked past a bunker under construction and started the hatchery in the terran natural.

misplaced hatchery

Steamhammer had the good sense to cancel the morphing hatchery before it died, but still.... Opening build: Failed.

When the enemy base location is unknown, MapTools::getNextExpansion() is supposed to choose the free expansion closest to home by ground distance. It should have chosen the 6 o’clock base, not the enemy natural. It’s a bug.

wait, is this the same game again?

Steamhammer played against Microwave 2 times in the last 2 days: Yesterday’s game and today’s game. Both games were on the map La Mancha, which is a little surprising since there are 15 maps. Both games had the same positions, Steamhammer in the upper left and Microwave in the lower left. OK, it could happen sometimes. And in both games, Steamhammer played its overgas 11 pool opening, a risky opening that it is set to play just under 1% of the time.

That does not happen! This is a coincidence that should come up 1 time in 18,000, more games than Steamhammer has played. Did somebody take control of the random number generator?

Microwave was blue in both games, but Steamhammer got different colors. Whew. The games were similar, as you might expect. Microwave played overpool and was almost but not quite able to capitalize on its earlier zerglings...

zergling advantage

... then lost to the fast mutalisks that Steamhammer got by going gas first.

mutalisk advantage

A third game today between the two bots was completely different. That’s how it’s supposed to work.

Steamhammer’s ZvZ secret weapon revisited

As some people have noticed, Steamhammer’s “secret weapon” ZvZ opening, which when I first tested it scored overwhelmingly against all opponents including Steamhammer itself, is simply overhatch.

Overhatch means making up to 9 drones, spawning an overlord, and then starting a hatchery while still on 9 supply. Steamhammer’s version is overhatch 9 pool 9 gas (with drones in between buildings), parallel to its faster 9 hatch 9 pool 9 gas build. The overlord lets zerg get in a couple extra drones, so that when the spawning pool finishes the bot has 10 drones and can immediately spawn 8 zerglings. The timing is fast enough to hold off 5 pool except on 2-player maps. It puts the player in a reasonable economic position (by ZvZ standards), but also commits to zergling-heavy play because the lair will be later.

Overhatch is a rare opening and it is not written up on Liquipedia, and that is for a good reason: It is dominated by 10 hatch. In a ZvZ 10 hatch opening, you go up to 9 drones, spawn an overlord, and do the extractor trick to get a 10th drone. The 10th drone can mine for a while before minerals are available to morph the hatchery, so 10 hatch is always ahead of overhatch in minerals. There is no disadvantage to 10 hatch; it can only be better than overhatch (though only by a little). Steamhammer plays overhatch because it still does not work around the extractor bug (I have more important bugs to fix first).

results

The opening is strong against bots. Results on the SSCAIT server have been good, though less convincing than my original tests.

Steamhammer has lost several games by failing to build an extractor when it came up in the build order. It is a bug that I didn’t see in testing and haven’t solved. For some reason it hits overhatch much more often than other builds.

Steamhammer has also lost a game to Microwave’s 9 pool and another to Dawid Loranc’s 5 pool. Steamhammer’s zerglings were in time to defend with correct play, but Steamhammer pulled its drones too soon and lost some. It’s a severe defensive error. At some point I will teach Steamhammer how to defend with a drill, and then these losses won’t happen.

Steamhammer has also lost occasional games to strong opponents like Killerbot by Marian Devecka due to tactical errors. It does win most, though, even against opponents like Arrakhammer that know about the overhatch opening and are prepared to meet it.

counters

Like every opening, overhatch can be countered provided you know it is coming: You can safely open 12 hatch to end up equal in hatcheries, ahead in economy, and behind in nothing important. So Steamhammer doesn’t play overhatch every game. Steamhammer is set to play overhatch in half of games. Its other openings counter 12 hatch, which is a slow and risky opening in ZvZ. The random openings ensure that no opponent build can give a sure win; opponents have to either play better or get lucky.

If you want to counter overhatch safely, Liquipedia suggests that 12 pool gives a slight advantage. 12 pool is a safe ZvZ opening if played well. But I learned by experience that it is tough to teach a bot to play it well.

other matchups

The classic use of 10 hatch is in ZvP, where in old days it was considered a strong counter to 2 gate zealot play. 2 gate play is popular with protoss bots, so I tried overhatch against protoss too. It seems effective. I think it is doing better than overpool, which was already successful.

In ZvT, Steamhammer up through the current version has always played either zergling openings with heavy early pressure, or mutalisk openings with minimal zerglings and a heavy air attack. Thinking it through again after working on surviving early terran attacks, I decided to add a compromise opening for the next version. I picked an overhatch opening with early zergling pressure followed by a later, lighter air attack, at the cost of a weaker economy in the long run. I think it is objectively worse, but other zerg bots have been successful with similar approaches and it may work well against bots. It’s an idea that should be tried.

Tomorrow: Arrakhammer’s attempt to counter overhatch

Steamhammer next steps

Progress has been delayed by exhausting events in some kind of “real world” that I don’t fully understand. But whatever, it’s only a temporary distraction. A public repository should be up soon-ish; I have made some decisions but not all.

After that I will be, as anyone could have guessed, splitting versions again. I was planning for the next version 1.2.4 to be a mass bug fix release, but with the new SparCraft out, that doesn’t seem like the best plan.

• 1.2.4 - I’ll try the new SparCraft and incorporate it if it seems like an improvement. I expect it to be. Besides that, I plan to work on about a half dozen of the most critical bugs and weaknesses.

• 1.2.5 - Fix as many of the remaining bugs as possible. My list is way longer than I can get through.

• 1.3 - Start on opponent modeling.

I promised some form of opening learning or other opponent modeling for CIG 2016, and it is coming up fast. I have to get onto that soon and delay mutalisk work yet again. I regret the delay, because mutalisk micro is a key zerg skill and all bots are clumsy at it. When I finally get it implemented, terran bot authors in particular will be dismayed to see how hard mutalisks can hit when they are Less Stupid. But opponent modeling is also key.

I have already implemented a couple of fixes to regrouping. I corrected a conceptual error in weapon ranges versus ground distances. It remedies one case of mutalisks holding their position while under enemy fire, as well as less visible but related misbehavior. Also medics retreat with their squad when they should, instead of staying behind to “hold off the enemy while you escape.”

If I ever want to finish ahead of tscmoo in a tournament, zerg will have to learn how to survive terran early pressure. To make testing easier, I added a terran BBS opening. Like Tyr’s, it defeats Steamhammer’s mutalisk openings 100% of the time. So far, my attempts to react to it are too slow and zerg still loses. The BBS is so effective that I could not resist adding a “go pull workers” command to pull SCVs into the combat squad and make it even more vicious. Now it is easy to write all-in strategies like Oleg Ostroumov’s marine-SCV attack, or the zealot-probe all-in that Pinfel used to play.

Steamhammer versus Tyr

Here’s a curious point about Steamhammer’s ZvT and Tyr by Simon Prins. Tyr has opening learning, and center map BBS is its answer to bots which don’t defend themselves early. The BBS has always beaten Steamhammer’s mutalisk builds and lost to its zergling builds.

In the past, Tyr has tried BBS against Steamhammer and given it up after a while after losing; it concluded that a regular opening was better. Past Steamhammer versions played zergling openings 25% of the time, which was apparently enough to deter BBS even though Tyr’s slower play didn’t consistently win 75% of the time (it varied by version).

This Steamhammer version plays zergling openings ZvT 20% of the time, because the mutalisk openings are improved more (that was my thinking, at least). Tyr apparently detected the shift in game results, and now it plays BBS every game and wins 4 out of 5, a huge upswing. Can improved play can lead to worse results when it highlights remaining weaknesses for the opponent’s learning to exploit? It could also be because Tyr was updated recently. Or it could be a chance change due to the interaction of opening learning, random choice of builds by Steamhammer, and historical changes in Steamhammer’s performance.

To fix the weakness I thought of a simple adaptation, and I hope to try it out in an upcoming version. Steamhammer is prepared for early pressure versus zerg or protoss opponents, but against terran it tries to exploit the tendency of most terran bots to sit back and macro for a while. So it only has to adapt in the case of early marine pressure, as played by Tyr (with BBS) and the latest tscmoo (with an academy rush) and a number of weaker marine bots like Kruecke and KaonBot. Steamhammer should have better chances to survive if it breaks out of its prepared build when it recognizes the early pressure, and lets the strategy boss do its default thing. I doubt my simple idea is good enough by itself for all cases, but I’ll try it.

Steamhammer 1.2.3 results so far

The new Steamhammer 1.2.3 zerg plays slightly but distinctly better than the previous version. It’s worse on some points, like focussing the attention of its mutalisks, but better on enough others to make up for it. The overall result is a small but clear bump up.

The new Randomhammer plays worse than the test version of Randomhammer, and I don’t know why. Apparently I did something harmful in the last week of development, and I can’t figure out what. I worked through the list of items I changed that week, and I don’t see a problem with any of them. But there must be one. Has anybody noticed something?

It’s possible that the unknown problem affects zerg too, and zerg could be even stronger if I fixed it.

when to switch to BWAPI 4.2.0?

BWAPI 4.2.0 was released on 28 April. I have been thinking about when I want to switch over to it, and I haven’t decided.

Sooner? 4.2.0 fixes the zerg hive research bug, which pinches zerg strategy. The hive bug is nasty, so that counts for a lot. Code changes to switch to 4.2.0 seem minimal; I would want to revise the bits of the zerg strategy boss which encode the buggy tech tree. Dave Churchill has already switched UAlbertaBot over, so any problems should be minor. 4.2.0 supports Visual Studio 2017, so people wouldn’t suffer from old development tools. And of course there are various other improvements and fixes, and it’s common sense to stay as up to date as possible.

Later? Will competitions support 4.2.0? I wrote to the CIG 2017 competition organizers to see whether it would be supported in their tournament. The lead time may be short for them. We’ll see what they say. Also, given my development plans (fix bugs, work on mutalisks and opponent modeling), switching libraries would be overhead that slows me down for the moment. I’m not looking forward to switching to a new toolset when I’m still getting used to the one I’m using.

What do you think? Anybody have thoughts or experience?

Update: As Ailien points out in a comment, if you use BWTA you have to update it at the same time, and no new BWTA release is out yet. All DLLs have to be compiled with the same toolchain, per Microsoft. It may work if you compile BWTA yourself from source with vs2017 (no promises, I haven’t tried it). For BWEM, Igor Dimitrijevic suggests integrating it into your source code directly. If you did that, then it presumably does not have the same issue (I didn’t see any map-related changes in the BWAPI change list).

the right thing for the right reason

The new Steamhammer version plays worse against Iron. I expected it to—in fact, I intended it to play worse.

Iron sends vultures to roam the map. By the time mutalisks come out, the terran base is filling up with turrets and expensive to attack. The older Steamhammer, when it survived Iron’s vulture runby due to lucky timing or Iron’s mistakes, usually chased vultures and SCVs with its mutalisks as their numbers built up, which (given the bot’s limitations) was good play for the situation. Occasionally it won, when it protected drones long enough for mutalisks to build up to critical mass to take down the turrets, or for ultralisks to come out in number.

It played right, but for the wrong reasons: The mutalisks were under orders to attack the enemy base, and they didn’t. They were distracted by the enemy army. Any good play was accidental.

I want Steamhammer to play right for the right reasons. My first step was to make it play wrong for the right reasons. One of my goals for the tactical changes to unit targeting was to make squads obey their orders more faithfully. And... it’s somewhat successful. Squads still sometimes go on goose chases, and individual units often get distracted without good reason, but overall a squad with an attack order has a tendency to move toward its goal and attack it. With Iron it is particularly clear: Mutalisks take some passing shots at vultures but mostly move toward their goal. When they arrive, they underestimate the danger of the many turrets and die, so the game is lost; that is a different problem.

A future version will do more tactical analysis and pass along better orders to the squads. Then Steamhammer will start to play right for the right reasons.

Steamhammer’s endless bug list

I got 2 nearly simultaneous comments pointing out Randomhammer’s loss on time against LetaBot by Martin Rooijackers. Thanks! Randomhammer was winning, so it hurt. The problem is the “my main is full, I can’t find a place to put this building” bug, which I reduced but did not solve. A typical solution seems to be to choose a new “main base” from time to time. I would like to go further and put a pylon at each base, if for no other reason than to add cannons if needed.

Maybe it’s a good time to talk about my bugs. I have 39 bugs—so far—that I want to fix in the next version, not counting bugs I’m intentionally skipping for now. It’s far more than I can actually fix. If I fixed all the bugs, I wouldn’t have time to add more bugs! One of the worst bugs was introduced in version 1.1 in February and is still there.

The good news is that there are no known crashing bugs. Steamhammer has 1 crash dump on SSCAIT since 3 April, and it points to initialization code before Steamhammer runs. UAlbertaBot was already mostly good in that respect, and the majority of crashing bugs I fixed (though not all) were in my own code.

The bad news is that most games, both wins and losses, show the effect of bugs. Many events that may look to observers like ordinary poor play are secretly due to incorrect information tracking, or behaviors occurring at times they weren’t intended to, or something else going wrong behind the scenes. In other words, if I can fix the worst of them, then Steamhammer will play much more strongly just by working as intended.

This game McRave-Steamhammer is a bug-fest on both sides. Watch this replay only if you can bear to see an epic number of things go wrong for both players. At the end of the game, Steamhammer is mining minerals with 1 drone and gas with 3, while its other 18 drones are trapped behind a map block, and that is only one of many painful blunders. McRave did no better. The game went on far too long as both bots tripped over their own feet.

Here is one of the most frustrating bugs: In my tests at home, Steamhammer defeated Killerbot by Marian Devecka nearly 100% of the time. Since being uploaded, Steamhammer has played 3 games against Killerbot and lost 2 of them due to a new bug that I had never seen before. I can’t find the bug in games against any other opponent. Objectively, a bug that affects only one opponent is not the top priority to solve....

a dark templar drop game

Steamhammer's web page is updated with source.

I enjoyed this game of Randomhammer versus Krasi0. It was played by the test version of Randomhammer, before the release version was ready.

Randomhammer ended up protoss and tried its dark templar drop strategy. Here the shuttle has taken the long way around the map, following the edge counterclockwise, and unloaded dark templar next to the mineral line. The dark templar killed a number of SCVs plus a goliath and delayed the academy, while disrupting mining.

the drop disrupts the main

Two tanks at the front had been keeping the protoss field army at bay. The tanks pulled back to help defend the drop (in this picture they are on the high ground), which allowed Randomhammer to break the bunker and wreak more havoc in the natural.

the followup disrupts the natural

At the end of the fight, Randomhammer had its own natural up and was ahead in workers by 33 to 16, which should have been a decisive advantage. Then, of course, Krasi0 played the rest of the game much better and won regardless.

The dark templar drop is dangerous. Krasi0 was prepared: It had turrets up for detection and goliaths to shoot down the shuttle. Terran could detect the dark templar most of the places they went, and yet struggled to defend. Randomhammer did not understand that the turrets were key targets and ignored them. With sharper play during the drop, protoss might have won outright despite Krasi0’s preparation and fast defensive reactions.

It was a fun and instructive game. As protoss, Randomhammer plays the dark templar drop around 15% of the time, depending on the map and matchup.

Steamhammer 1.2.3 change list

The change list is big this time. I took over a month to do it, but I did a lot. This is primarily a feature release to add skills for terran and protoss, and to improve tactics and micro for all races.

History says that my feature releases are sometimes weaker than the previous version due to bugs. I already see new bugs that never came up in testing, bugs I did not see even in the Randomhammer test version. Sigh. Yesterday’s bug list was longer than I could hope to finish before July, and today’s....

drop

Terran and protoss have limited support for drop strategies. Dave Churchill implemented part of it in UAlbertaBot, and I filled in the many gaps and made it work.

Terran and protoss can drop once, with a predetermined unit mix, from 1 dropship or shuttle, near the mineral line in the enemy main base. The transport cannot pick its units up again. The transport cannot return to pick up a new load (it idles in the enemy base after unloading). If you make a second transport, there’s no support for loading it up and making a second drop. The transport follows a fixed sneaky path around the edge of the map. (It would be easy to change the drop target, though.) Even with these severe limitations, drop strategies can be worth playing.

Zerg drop is not supported because it’s a little more complicated. Zerg has to research drop and then choose an overlord, and usually research overlord speed too. Also dropping once with 1 overlord is not as useful for zerg. I’ll probably implement multiple-ship drops and repeated drops around the same time as zerg drop. I have made a start, and it will get better.

As written, the setup for the drop—arranging the production of the tech and units—is fully in the hands of the opening book. The opening book sets the OpeningGroup to "drop" to declare a drop build. The StrategyManager can then do as it will with the drop opening group; I had it transfer to another opening group. It should be no problem to move drop setup into StrategyManager so that drop can happen or not depending on game events.

The drop is coordinated by CombatCommander using newly added squad order types. See CombatCommander::updateDropSquads(). To change the units to drop, modify CombatCommander::unitIsGoodToDrop(). The transport movement is carried out by MicroTransports, most of which was written by Dave Churchill with additions, tweaks, and bug fixes by me.

Terran plays a vulture drop strategy around 10% of the time (depending on the matchup and map). Protoss plays a dark templar drop strategy around 15% of the time (ditto). The dark templar drop especially can be deadly.

tactical changes

• Every race (not only zerg) gets separate ground and flying squads. See CombatCommander::updateAttackSquads().

• Every race is supposed to get a mobile detector for each squad, as zerg does, provided the detector has been made. I noticed that it doesn’t work for terran science vessels, which sit by the starport. Another bug for the list. I’ve seen it work for observers, so I hope there is not a regression.

• Don’t assign an air target to a squad that can’t shoot at air units, or a ground target to a squad that can’t shoot those. See CombatCommander::getMainAttackLocation(). One hydralisk among the ultra-ling will get the squad assigned to shoot down carriers, so bad behavior is possible, but it is... self-limiting.

• Overlords are an acceptable tactical target in CombatCommander::getMainAttackLocation(). It’s made possible by the above fix. In UAlbertaBot, overlords are explicitly skipped over so that zealots and zerglings aren’t sent to chase them.

micro changes

• Targeting is more flexible, relying on a combined score rather than separate priority and range (which was brittle). The change needs more tuning to approach its potential. The change allows others:

• To reduce goose chases, fast enemies score lower when they are moving.

• Workers are always acceptable micro targets in MicroManager::execute(). UAlbertaBot and former Steamhammer versions often ignore workers in the middle of the map to reduce goose chases. The code was complicated and introduced a harmful limitation.

• Targeting priorities are adjusted, especially priorities related to workers.

• When regrouping, do not retreat from an enemy unit that cannot attack you. Retreating units used to stand back 128 pixels even from enemies that could not harm them, so you would sometimes see mutalisks fleeing from firebats.

• When retreating from an enemy that can harm you, retreat beyond enemy sight range as well as beyond enemy firing range. This often results in retreating farther. I added bonus distance for retreating from tanks, though I see in games that it is still not far enough. Units try to retreat out of range but don’t understand how to navigate around each other.

• Detectors, such as overlords, are a little more cautious and should wander into enemy fire slightly less willingly. They still die a lot.

UnitUtil::CanAttack() had a bug inherited from UAlbertaBot. Instead of only fixing the bug, I rewrote the function to understand more unit types, which made it possible to simplify other code. It now understands that bunkers, reavers, and carriers should be treated as able to attack.

UnitUtil::GetAttackRange() tried to understand bunker range, but had a bug, and it didn’t know about reavers or carriers. I think it now understands bunker, reaver, and carrier range correctly.

• The bot surrenders when all hope is lost. It says “gg” and goes idle for 1.5 seconds before leaving the game. See GameCommander::update() and GameCommander::surrenderMonkey(). The behavior can be turned on or off by a new config option Config::Strategy::SurrenderWhenHopeIsLost.

terran

• Terran tracks the locations and times of comsat scans to avoid scanning redundantly. I implemented a very simple system using MapGrid. It’s not fully accurate but it’s a huge improvement over the previous version, which would blow 100% of scanner energy of all scanners the moment it spotted a dark templar. Now it scans only moderately more often than it should (it scans cloaked units it notices whether it can fight them or not).

• Marines and firebats use stim, an important skill.

• Medics mostly stay near marines and don’t run ahead. This is a bigger improvement than stim. Medics still have a problem with regrouping. Even so, infantry play is much improved.

• Tanks stay sieged while an enemy is in range. They still siege and unsiege way too often, but now they behave better when fighting in sight of enemy buildings.

StrategyManager::getTerranBuildOrderGoal() is updated to research stim, to make more transitions, and stuff like that.

• The 2 factory openings are more efficient: The vulture opening and the tank opening. My inexperience with terran openings was showing.

protoss

• Protoss supports more units: Reavers, carriers, and archons (which all require special handling). Reavers crawl around and try to join the army; they work reasonably well. Carriers stay home until they have 4 interceptors (well, occasionally they wander off). Carriers (like scourge) should be put into the flying squad only if there are other flying units; otherwise they stay with the ground squad. Since there is no support for psionic storm, high templar as they are produced automatically merge into archons. I didn’t implement a way to ask for an archon, you get one when you make 2 high templar.

StrategyManager::getProtossBuildOrderGoal() is updated to use the new units. Zealot openings add archons and carriers later in the game. Dragoon openings add reavers after the second nexus. Plus various other less important changes.

• The 10-12 gate opening is improved.

zerg

Zerg has the most changes by count, but they are simpler. Except for the openings, all the changes are in StrategyBossZerg.

• No longer get scourge before they are known to be needed. It turned out to hurt more often than it helped.

• Make a second evo chamber only if the first is busy. The bot too often started a second evo before it had scared up funds to upgrade carapace in the first, or made 2 evos when rebuilding even when no more upgrades were needed.

• Fixed an oversight allowing a rare production freeze related to overlord speed.

• Make a spire for air defense, even if it is not otherwise needed.

• Make emergency zerglings when under dangerous ground threat.

• Ground emergencies end after 20 seconds, not 30. I’m considering whether 15 or 10 seconds might be better.

• Choice of air or ground units is improved versus all races. For example, if the enemy has too many spores, the bot will stop mutalisk production. A bug causes a useless hydra den to be made against terran; I fixed that once, it is a regression.

• Go ultra-hydra much less often. The bot was way overusing that unit mix.

• When the enemy makes static defenses, respond with drones. The change is simple but effective, as seen in the recent game against XIMP by Tomas Vajda where Steamhammer took the map much faster than before. You can see Steamhammer make a burst of drones when it finds more cannons, until it reaches the maximum 75 drones.

• New overhatch openings, other opening tweaks. Some openings are shortened because the strategy boss can now do the right thing.

configuration file

• Strategy mixes can get different weights depending on the map size, and repeated strategy mixes can be factored out into strategy combos. It's explained in this post and implemented in ParseUtils. (Tech note: I used BWTA to count the start locations, so I had to move map analysis ahead of config file parsing in UAlbertaBotModule. I didn’t realize in time that BWAPI can count the start locations. All you should have to do is change BWTA:: to BWAPI::Broodwar-> in the call to getStartLocations().size() to remove that point of dependency.) All races use the map size feature to prefer some strategies on appropriate maps.

• I added a boolean strategy option SurrenderWhenHopeIsLost to control surrendering.

• I added a macro option AbsoluteMaxWorkers and set it to 75 for all races. Zerg already adhered to the 75 maximum, so this affects terran and protoss. Making too many workers is bad because it reduces the army size in the late game. 75 workers leaves 125 supply for army.

• I added another macro option ProductionJamFrameLimit and set it to 1440, which is 1 minute. If no macro action (like producing a unit or starting research) is carried out in that time, the production manager assumes that production is frozen by a deadlock and clears the production queue. This at least prevents production freeze bugs from bringing Fimbulwinter, and it doesn’t cause harm if production is slow because of lack of workers. Terran and protoss have many production freeze bugs, and zerg has a few despite an eradication campaign.

• I added a debug option DrawMapDistances.

• I removed the debug option DrawStrategySketch since it was limited and only for zerg. Use DrawStrategyBossInfo to get the same zerg info and more.

code

• The regex bugfix in MacroAct::MacroAct(const std::string & name). I learned it from gnuborg, who credits jaj22.

• I fixed bugs related to finding the unit type of a MacroAct that is not a unit. The bugs probably caused occasional bad behavior, though I don’t know what.

• Renamed the micro managers with a Micro- prefix. RangedManager became MicroRanged, TransportManager became MicroTransports, etc. More specific names make the code easier to understand.

• Removed unused files HardCodedInfo.* and snips of unused code throughout. Some unused code I left in place, when it seemed potentially useful.

• No longer time MapTools every frame, since the class doesn’t have a job that it does per frame. It’s a utility to be called by others.

SquadData::addSquad() no longer redundantly requires the squad’s name (already known by the squad itself).

SquadOrder::isCombatOrder() and SquadOrder::isRegroupableOrder() factor out decisions that used to be scattered through the micro managers.

• I changed many cases of for (auto & unit : units) to (const auto unit : units). A unit is already a pointer, no need to take a reference to it. I hope the optimizer comes up with the same code in both cases, but redundant references are bad style.

CombatCommander::update() updates all squad memberships in one go. In a previous version I tried to optimize it to spread the work across frames, which turned out to risk problems.