archive by month
Skip to content

Steamhammer 2.2 status update

It looks as though Steamhammer 2.2 with regions and without BWTA will likely not be ready right after SSCAIT finishes, as I had planned. It will take longer because more stuff needs fixing. For one example, today Steamhammer lost versus UITtest because of a bug where drones entirely stopped mining minerals. I currently have WorkerManager instrumented to the gills to trace it. For another, yesterday I fixed several causes of rare production freezes and also added a workaround for the serious macro glitch that happens when Steamhammer wants to spend a lot of gas and is collecting gas slowly. Game-losing bugs like this are second on my priority list after crashes.

Also on my list is a bug that can cause infinite creep colonies to be built in the main base, instead of a limited number in the natural for defense. And I want to get the second building construction delay bug; fixing the first one got the spawning pool to start earlier, but the spire seems to start later, and that loses games too.

Plus of course I have added a few openings and made the usual varied fixes and changes. I always do.

high and low ground

In my current implementation, regions are defined entirely by chokes, which are themselves defined as narrow places in the terrain. I’m considering whether to change the definition of chokes to include changes in ground level. A narrow ramp counts as a choke no matter what. I’m thinking that maybe a wide ramp should also count as a choke. It has a similar property of defensibility; the difference is that the defensibility is asymmetric: It is easier to hold the top than the bottom. Since it’s defensible you care about it and may want to treat it as a region edge, no matter which side you’re on.

pathfinding

I’m not going to do pathfinding right away (though I’ll likely take initial steps soon), but here is my current plan. I want to separate high-level and low-level pathfinding. A high-level path from A to B is a sequence of chokes to go through, basically the same as BWEM provides. If you’re already in the same region, the sequence is empty. A low-level path is a sequence of positions to go through. A high-level path can be planned fast and if necessary replanned fast. A low-level path has to attend to details, so it saves time if you never have to plan farther ahead than the next choke, especially if you may change your mind.

For high-level pathfinding, Steamhammer needs to know all the chokes and whether each one is open or closed at last report. Therefore chokes must be found without destructible map obstacles (not how my current implementation works), and then each choke analyzed to see whether it is blocked. I also want to know the choke width, in case not all units fit through, to play on maps like Third World with narrow ramps and Blue Storm with a narrow entrance. For threat-aware high-level paths, it needs a measure of threat for each region and/or choke.

For low-level pathfinding, I want to work at the 32x32 tile level as much as possible, because the 8x8 walk tiles are 16 times as much data. I thought of scaling the “how much room is around this walk tile?” data to tile size, taking the max of the walk tile room values within the tile and filling in that as the room around the tile, perhaps with forcing to zero if the value is small or other adjustments. Other grids will also be at tile scale: This tile is blocked by a building, the threat at this tile is such-and-such. A path could be found at tile level, and any tricky parts double checked at finer resolution if necessary.

For air units, regions don’t matter and probably all path planning can be done at tile scale. Then detailed movement decisions related to firing and cooldown will be made frame by frame at pixel scale as now.

zones? areas?

In related news, I’m thinking of changing the name “regions”. Starcraft has its own idea of regions, represented by BWAPI::Region objects. They work differently and Steamhammer currently doesn’t use them, but they could be useful for some purposes. It would be nice to avoid a name clash, so that when you see a variable named region you don’t have to look up the type to find out what it is.

I like short names, so I’m thinking Zone or Area. Any other suggestions?

what major feature should be next?

After map analysis in the upcoming Steamhammer 2.2, what major feature should I work on next? I haven’t decided. I need to make progress on all fronts, but the largest features should be done one at a time so that they don’t step on each others’ toes. My hope is to have a powerful major feature ready in time for AIIDE 2019 in the fall, a version that I can call Steamhammer 3. As always, I’ll also do many minor features and fixes and stuff. Before I start in, I expect at least a Steamhammer 2.2.1 or 2.3 version with more map analysis features, such as support for finding paths through nydus canals, or at least better static defense placement.

1. Strategy adaptation. This has a lot of parts, and calls for adding judgment skills that don’t exist yet. As phase 1, I would create abstract openings in a general format, and allow the current concrete opening lines (which specify an exact build order) as implementations of the abstract openings. If no concrete opening is known for a given abstract opening, or if the situation changes and the intended opening has to be adapted or abandoned, Steamhammer will have to make up a new concrete build order for the situation. As phase 2, I’ll have Steamhammer collect data on what works. For making the initial opening choice (and for later decisions), I’ll drop the current hand-coded probabilities and rely on the data, so that Steamhammer’s choices will be empirically grounded. At this point, Steamhammer will have far more flexible reactions during the opening builds. As phase 3, I’ll extend the abstract openings to choices of abstract strategy over the whole game. At this point, instead of following hand-written opening lines or hand-coded rules, Steamhammer will weigh decisions: I see the cannons. I can bust them with units, or fly around them, or take the opportunity to grow my economy. Which is better this time, hydras or mutas or drones? Steamhammer currently knows openings for these 3 possibilities, but if it is following its strategy rules, the rules always say to make drones.

2. Operations boss. I want to dump CombatComander and replace its functions with OpsBoss, which currently exists mainly as a stub. The combat commander has a largely fixed set of squads, and its main job is to assign units and give orders to each squad. The ops boss will have goals and plans to achieve the goals. It will make up squads more dynamically, and assigning units will be the tail of its work. The ops boss will be able to carry out multi-step plans like taking island bases (transport a worker, mine out the blocking mineral patch, take the base, transfer workers, add defenses, return workers when the base is mined out) or complex drops, and in general will do more varied and interesting stuff.

3. Squad structure—effectively, the tactics boss. I think the Squad class needs to be completely rewritten; it is not powerful enough to represent all the behaviors that a squad needs. See awkward points and design ideas. As part of this, I would implement formations including large-scale surrounds and some level of support for different kinds of unit coordination: Vultures screen the tanks, dragoons leave a gap for the reaver to shoot through, flying detectors and arbiters maneuver to do their jobs better, etc.

what to do?

Micro still needs tons of work, but I think I can treat micro improvements as a sequence of minor features that I can tackle one at a time. Building and unit placement is important. Another vital subsystem that needs rework is production. All aspects need to be moved under the production goal system, which will improve macro for all races and let me dump BOSS for terran and protoss—and also ties in with strategy adaptation. It’s a necessary change, but ideas 1, 2, and 3 above are also necessary and seem more likely to win tournaments this year.

To me, strategy adaptation and the ops boss are the most tempting. Both make play more fun and interesting, and potentially much stronger. Strategy adaptation would stick to my original strategy-first development plan. From a development efficiency point of view, it is logical to work on squad structure before the ops boss, or at the same time because they interact and their needs are interrelated. But if I work on them together, I might not finish them this year. It’s possible that I could decide to do selected parts of more than one idea.

What do you think? One of these, or something else entirely?

funny map analysis picture

It turns out there are a lot of ways to calculate regions and chokes. In the course of putting one together, I’ve been doing some other map analysis that should be useful for micro and pathfinding. Here is one that doesn’t work yet, a color-coded debug drawing which is supposed to show the room available around each walk tile: How much space is there for a unit or army to fit into? If you know a path, you can check the tiles to find out which units are small enough to travel the path. Or you can figure out how many of your units fit behind the enemy mineral line—should you go there?

incorrect and funny-looking dot diagram

Unfortunately, it’s no good as it stands. Among other mistakes, it claims there is no room in places where there obviously is. It makes a funny picture, though.

Like BWEM, I also calculate the distance from the nearest unwalkable tile. Iron makes good use of that information. That code worked correctly on the first try....

which weaknesses are critical?

The tournament version Steamhammer 2.1.4 suffers from a command jam bug which reissues commands far too often, causing many to be dropped. It’s a critical bug with devastating effects, causing units to ignore their orders—to freeze in place, to wander past the enemy taking fire without noticing, and so on. It starts having an effect often before the zerg supply reaches 50, and the effect grows worse as supply increases. By the late game, large groups of units are sitting uselessly around the map doing nothing. It’s a critical bug and intolerably severe.

But how critical is it really? I look at every game that Steamhammer plays. Based on tournament losses, I estimate that if I had fixed the bug before SSCAIT started, Steamhammer’s rank would not be #10 as now, but #7—not much gain considering how closely the ranks are spaced, only a few percentage points up in win rate.

How can such a calamitous bug have so little practical effect? In Steamhammer’s early days, one version had a bug that subtly caused building construction to be delayed. I doubt any stream viewer noticed; I didn’t notice either, until surprised by unexpected losses. Experience and test games proved that it was a critical bug that caused a high rate of losses against early aggression. By comparison, the command jam bug is identifiable as the cause of loss in only a few games, like the one loss against XIMP by Tomas Vajda. In other games where the bug struck hard, as against ICEbot and MadMix, Steamhammer struggled more than it should have but won regardless.

Apparently the bug causes losses only against a narrow range of opponents which play macro games and are strong enough to exploit the weak play that the bug causes. There is no effect against a strong opponent like SAIDA, or against the weakest opponents which lose to Steamhammer’s first 6 zerglings. One explanation is that most opponents either prefer early aggression, or else fall to Steamhammer’s early aggression. Another explanation is that I may underestimate the damage the bug causes; maybe it leads to losses that are not clearly attributable.

forge expand reaction

Why is it still called “forge fast expand”? It was a fast expansion when invented, but by today’s standards it’s not fast at all. That’s why I say “forge expand.” (It has the same number of syllables as FFE).

Though I still have region work to do, today I decided to make an important improvement to how Steamhammer reacts to forge expand and other safe macro openings. The tournament Steamhammer makes 3 attempts to adapt: 1. If the enemy’s opening plan was predicted, it tries to select a good counter opening. 2. Otherwise, having missed the prediction and gone down a poor path, it cancels any planned static defense which is now unnecessary, and 3. makes extra drones to catch up in economy. If it’s still in its opening book, it stays the course and tries to minimize the disruption by changing planned zerglings into drones, which cost the same.

Its plans are still disrupted, though, because the extra drones and the omitted static defense cause minerals to build up. Steamhammer waits until the opening is over before it makes macro hatcheries and otherwise spends down its excess resources, and that is often too late. Zerg can’t keep up with the enemy’s economy and falls far behind.

Today I added 2 new reactions that happen when we want extra drones so that resources threaten to build up: 4. If possible, take gas early (or take another gas early). Putting drones on gas slows down mineral accumulation and may speed up tech openings, so that mutas or lurkers come out sooner. If gas accumulates too much, Steamhammer will stop gas collection, so there’s little downside. 5. Make extra hatcheries as conditions seem ripe. One or all of the extra hatcheries may be placed at expansions, depending on the situation. The rules are more cautious than the macro hatchery rules that apply once the opening is over, because they’re still trying not to disrupt the opening line. The overall effect of the new reactions is that Steamhammer pursues the tech of its opening line, sometimes faster since it has more income, gas, and larvas than expected, and transitions into the middle game in a stronger position. It’s making a big difference in test games, including wins from positions that were sure losses otherwise.

The fix is inspired by recent losses, especially the 2 losses to Skynet by Andrew Smith when it unexpectedly (to Steamhammer) switched from zealot rushes and DT rushes to forge expand. To my intuition, the forge expand reaction seems much less important than the command jam fix, which is a critical bug fix that affects far more games. And yet, taking into account test games and the rate at which Steamhammer was surprised by macro openings in the tournament, I estimate that it will save about 2/3 as many losses—in terms of improving elo, both seem almost equal. How does that happen?

Apparently you have to measure the severity of weaknesses, because intuition does not seem accurate. Unfortunately, to measure with an A/B test, first you need to fix the weakness. Maybe that is an advantage of machine learning, which does its entire job by measuring weaknesses and correcting them.

random Steamhammer notes

A few unrelated notes about Steamhammer:

The bug that causes Steamhammer to drop commands is due to a missing & in an inconspicuous declaration, causing a data structure to be copied instead of referred to. Updates are made to the copy instead of the correct data, then the copy is thrown away. Even after I deduced that something was being copied behind the scenes, it was tricky to nail the exact mistake.

I developed an opening that I feel I can properly call Fried Liverpool. Like the Fried Liver Attack from chess, mentioned in a comment, it’s crazy sharp and can put on tremendous pressure. Steamhammer can’t play it yet; it needs a couple new features. I tried it by hand and found it is effective against unprepared opponents. Maybe I’ll get it working in time for version 2.2.1 or thereabouts (the one after the upcoming 2.2).

Steamhammer just lost a game against the cannon bot Jakub Trancik. I don’t remember another loss against Jakub Trancik since early last year (maybe I have a bad memory). During the tournament I can’t log in to fetch the game records, but I assume it is the first game against this opponent since version 2.0. It takes a long time to collect enough game records. I’m glad I fixed the proxy recognition bug, or Steamhammer might have lost the next game too.

Steamhammer status

As I write, in SSCAIT Steamhammer is tied with BananaBrain for #8-#9, at just under 80% win rate. I’m happy with it. But Steamhammer is one of only 2 bots (the other is #26 NLPRbot) which has not yet played any games against the current top 5. I expect to take losses and slip down in the ranking. A finish near the middle of my predicted range of #7-#13 seems likely.

For some reason I don’t feel like analyzing CherryPi and SAIDA yet, though I’m sure I’ll get around to it. I’ve been working on the upcoming Steamhammer 2.2 instead. I’ve removed all references to BWTA other than regions, and I’m making good progress in implementing my own regions; the outline of the code is there, and supporting data is calculated and looks correct. Finish that and replace references to BWTA regions, and only a few small odds and ends remain before I can drop BWTA. Debugging time is unpredictable, because my regions will be different and may affect play. But I’m likely to be done in time for the end of the tournament.

Today I decided to take a break from that and fix a critical bug instead. I verified what I have been suspecting: There is a deadly one in the new micro system, causing it to reissue commands far too often. That makes the APM shoot over 90K and probably saturates Starcraft’s queues so that commands are lost in transit. That explains unit freezing and misbehavior once the zerg army grows large, and I hope it explains the production freezes too. The bug is resisting me so far; something behind the scenes is mysteriously resetting the “yeah yeah, I already did that” marker. But the code is simple and I’ll nail it before long. The bug is responsible for a lot of bad play during the tournament, but strangely for only a few losses.

As the tournament approached I was trying to make low-risk changes. The code is simple, but I still misstepped. I think my first cut of the micro system was OK, since it passed tests then, and the bug was introduced in later changes as I “improved” it.

SSCAIT runs of upsets

I am amused: As I write, Steamhammer is ranked #11 in win rate in SSCAIT. It has played 4 games against players ranked higher—and won all of them. The games are 1-0 Krasi0P (I expect the second game to also be a win), 2-0 Killerbot by Marian Devecka, and 1-0 Hao Pan (the second game could go either way). All the losses that pushed Steamhammer down to #11 were against weaker players. That’s a change from last year, when Steamhammer performed consistently and had comparatively few upsets in either direction. Some losses are caused by bugs (0-1 XIMP by Tomas Vajda) or by Steamhammer’s standard weak play (0-1 AILien), but I think the lion’s share are due to poor opening choices by the opponent model: Steamhammer is performing inconsistently because it is thinking on its own.

Current #14 LetaBot by Martin Rooijackers has a similar record: It has played 6 games against higher-ranked players and won 5 of them, including its game against Steamhammer (it happens sometimes).

Overall, I think the biggest upset so far is #50 KillAll 1-0 #2 PurpleWave. Of course the tournament is only about 1/4 over.

another building delay bug

Constructing buildings efficiently is one of Steamhammer’s most fragile behaviors, because it involves coordinating across modules in an ad hoc way. In my change list for the latest version 2.1.4, I described a bug that delayed the start of buildings. The bug was an interaction between the production manager, the building manager, and the building placer.

Now I’ve discovered another bug with the same symptoms—an already placed building is re-placed elsewhere, causing a delay—that also involves 3 modules. This time it’s the building manager, the production manager, and the worker manager. This bug bites when a pre-positioned worker arrives too early at its designated location and has to wait for resources or tech to be ready. How clever of the first bug, to hide the second one from my view. I think computer bugs evolve camouflage, just like living bugs; hide or die.

Now I’m trying to restructure the interaction to be more robust. My preliminary plan is to pass control to the building manager as early as possible and put it in charge of the rest, to try to keep the module interactions simple and organized. It will involve storing a little more state.

Meanwhile, in SSCAIT I’m not seeing many surprises. Not enough games have been played to firm up the rankings, so my range of expectations is still wide—I guess it’s normal that nothing much is unexpected. Steamhammer has about the right mix of wins and losses in games that could have gone either way. It is entertaining that the score table only gives a rank to bots that have played 30 games, while the games are doled out randomly. At the moment, #1 is Soeren Klett with 15-15, and #2 is Jakub Trancik with 11-19. Visiting space aliens will not understand how the competition works.

Steamhammer 2.1.4 change list, SSCAIT 2018 version

The version 2.1.4 change list also includes the changes in the unreleased test versions 2.1.1 through 2.1.3. I rolled them all up. A lot of the work in 2.1.4 was fixing bugs that I introduced in the test versions. Expect source release tomorrow, if I find the energy.

The most important improvements are in bold.

UnitInfo

UnitInfo was inherited from UAlbertaBot. It is responsible for keeping track of enemy units that may be out of sight.

• Keep track of burrowed units, both zerg burrowed units and spider mines. Formerly, when a unit burrowed, Steamhammer thought “oh, it disappeared from its last seen position” and lost track of where the unit was. Now the units are tracked and get passed to the combat simulator, and could be used for other purposes—”mines are ahead, send an overlord now!” It’s a little tricky, by the way. If you detect a burrowed unit then you detected it, but if detection is not available and a unit disappears, then why? When a zerg unit burrows, it has the order Orders::Burrowing, so you can distinguish a burrowing unit from a unit that merely walks out of sight. But a spider mine has the order Orders::VultureMine no matter what it is doing. So I simply marked spider mines down at the position where they were last seen, and it works accurately so far though it could be wrong in rare cases. BWAPI doesn’t provide “a cloaked unit in this position would be detected if it were there, therefore it’s not there,” so for now I ignore the case of a burrowed unit which moved away or was destroyed while out of sight. At some point I’ll add a feature to cover BWAPI’s lack.

• I renamed the field lastHealth to lastHP, since that’s what it is. I decided to use “health” to mean HP + shields.

• Steamhammer 2.0 added UnitInfo::estimateHealth() to estimate the health of an unseen unit, accounting for protoss shield regeneration and zerg HP regeneration. Terran repair and medic healing are not so easy to predict. This version adds separate estimateHP() and estimateShields() for use by the combat simulator.

The HP and shields of an undetected enemy are 0 because the enemy unit is not detected (easy to understand, right?). Steamhammer formerly took it literally and did not pass an undetected enemy unit in sight range into the combat simulator, because a unit with 0 HP is paper. I had assumed that Steamhammer was weak against dark templar because FAP doesn’t support cloaking and detection, but it was deeper than that. I fixed UnitInfo and the estimators to assume that a visible but undetected enemy has full HP and shields. Hmm, maybe a better fix is possible?

combat sim

• Use estimateHP() and estimateShields() for a more accurate representation of the starting situation. Formerly, for unseen enemies, the combat sim used the last known HP and shields (if the HP were not incorrectly 0 for an undetected enemy, as mentioned in the previous bullet). The estimates take into account regeneration since the units were last seen. Cloaked units are understood much better, though FAP still doesn’t understand that it can’t hit them without detection. Otherwise, the estimators rarely make a big difference.

Mutalisks versus spore colonies situations play adequately again. A bug was introduced in version 2.1.

Combat sim is centered on the nearest enemy rather than the frontmost friendly unit. UAlbertaBot provided a system where it picks one of its own units as the vanguard of its force, draws a circle around the vanguard, and includes everything that can fire into the circle in the combat sim. When our force moves forward, more enemies are included, so we may retreat, causing fewer enemies to be included, so we advance, etc. Steamhammer 2.0 changes this to include one cluster of friendly units (based on the unit clustering algorithm) in the combat sim, plus the enemies in the circle. Steamhammer 2.1.4 now centers the circle on the nearest enemy instead of the vanguard friendly unit. As friendly forces move back and forth, the set of enemies often stays the same. It greatly reduces vacillation and unit suicides. The circle is also smaller, to encourage aggression.

• Bruce @ Locutus pointed out a FAP bug confusing ground and air units in unitsim(). I fixed it, and it helps... to a limited extent. It’s a severe bug, and I expected a bigger difference.

• The FAP unit field airMinRange is always 0. I removed it and all its uses. Since it was tested in an inside loop, all sims involving air units run a trifle faster. The groundMinRange affects sieged tanks, so it has a use.

• Units that are under maelstrom (detail stolen from MCRS) or under disruption web are excluded from the combat sim by UnitUtil::IsCombatSimUnit(). A dwebbed unit could move out of dweb, but will it? The combat sim doesn’t understand it.

• The whichEnemies is reworked and completed. It specifies which types of enemies should be included in the combat sim, which makes a difference because Steamhammer decides the result by the unusual but successful criterion “who has more stuff left over at the end?” I renamed AntigroundEnemies to ZerglingEnemies because, believe it or not, it’s clearer, even though it doesn’t apply only to zerglings. You’re a zergling enemy if you’re on the ground (a zergling can hit you) or you’re in the air and you can shoot down (you can hit a zergling). A corsair is not a zergling enemy and is excluded. I added GuardianEnemies (which is unused) and DevourerEnemies (used) to complete the set (AllEnemies was already there). The CombatSimulation setup class calculates all the exclusions more accurately than before to pass the right units to the combat sim.

• Steamhammer scores the combat sim by unit prices. Some units have deceptive prices that don’t represent their value. For example, BWAPI arbitrarily says that a spider mine has mineral cost 1. I made special cases for deceptive prices.

micro

• Nearly all micro actions now have bookkeeping in MicroInfo, and the action of moving (which is when units get stuck) is handled completely by the MicroInfo system. Any move commands are now carried out at the end of the frame, after additional checks are done. I think units get stuck less often, though with more experience it becomes harder to see; maybe I’m fooling myself. At worst, the extra bookkeeping will make it easier to get units to follow their orders. On the downside, some bugs in the previous test versions were caused by failing to record changed orders in the MicroInfo system. I believe that this includes the recent production freeze bug, which I hope is fixed now. I should figure out how to avoid the risk of this kind of bug; I will have to change something.

DistanceAndDirection() is corrected and simplified. It’s a utility in Common.cpp which takes a base point, a direction point, and a distance. The direction point specifies a direction from the base point, and the routine returns a point at the given distance from the base point in that direction (it’s scaling a vector). The distance can be negative. There was a basic error: It calculated the (x, y) offset from the base point correctly, but forgot to add the base point to the offset, so the code looked right when I read it but the result was completely wrong! Since I was touching it anyway, I also simplified the code.

• A ground unit which finds itself directly next to an undetected enemy dark templar will try to flee away from the DT (using DistanceAndDirection()). The DT has to work harder and some units escape danger, but many units still get hit, especially if there is more than one DT. A disadvantage is that the fleeing units get disorganized and work together even less well than usual.

• Guardians are kited by the same code as mutalisks. It reduces cases where they marry a target and refuse to switch to a better one.

operations and tactics

• Attempt to retreat behind static defense, instead of stopping in front of it. It’s not entirely successful, but it seems to help some.

• There are a number of changes to base defense. There is a minor rewrite to simplify one part and improve efficiency. The enemy scout worker is no longer ignored; any enemy in the base is now reason to form a Base squad and clear the base; it helps deny enemy scouting. When deciding on how many defenders to assign, Steamhammer now weights enemy workers more lightly and certain tough enemy units more heavily, so the squad size should be more appropriate to the threat.

• The base defense squad also assigns a detector under narrower conditions, which ameliorates one major cause of mass overlord suicide. Unfortunately there are other causes.

• Don’t assign a detector to an otherwise empty squad. There was a loophole.

• Fixed a minor bug in dropping the empty Base squad of a destroyed base. It had no important effect. I think there is still one more case where dropping an empty squad does not happen as intended.

• For most of Steamhammer’s life, it has been the case that a melee unit next to a sieged tank does not retreat, but attacks the tank instead. I extended it slightly: If the tank is in the process of sieging or unsieging, the unit also does not retreat. It’s a little more insistent about hitting the tank while it can.

• For purposes of operations targeting, a refinery building is considered always reachable by ground. It’s one of the 4 cooperating bugs that I hit recently. This is, of course, a workaround and not a fix. If Steamhammer becomes aware of a refinery on an island....

early-game scouting

• In the scouting code that Steamhammer inherited from UAlbertaBot, a potential enemy starting base is considered scouted and unoccupied if we have explored the TilePosition where the enemy resource depot would be, and nothing is there. But that’s a little inefficient; it’s the position of the upper left corner tile of a building which is 4x3 tiles in size. If we are approaching from the right, say, then it’s one of the last tiles of the building location that we see. So now Steamhammer can recognize a base as unoccupied if we have scouted any of the 4 corners of the building location. The early game worker scout sometimes saves giant fractions of a second in finding the enemy. Someday I’ll add creep recognition too, which will save a useful amount of time when scouting a zerg enemy.

building construction

Expansion hatcheries could be mistakenly reassigned as macro hatcheries due to a bug in the building manager. The advent of this bug is what caused Steamhammer to so often expand slowly in the early middle game. Steamhammer’s traditional damn-the-torpedoes-take-the-map attitude is restored.

Buildings were often re-placed after their initial placement due to a subtle interaction bug that has been around since the beginning. This is what caused the spawning pool drone to move into position, stop, then move to another position before starting the pool. The bad behavior: The production manager notices that the pool is coming up, asks where it should be placed, and moves a drone there to pre-position it, trying to arrive just as 200 minerals become available. Then the building manager runs the placement code again, rejects that position because it is blocked by a drone, chooses a new position, then assigns the nearest drone. Now the building manager assigns the drone first, then places the building, usually keeping the same location because a drone does not block its own building—that’s the sneaky interaction. In most cases, but not all, the closest drone can be assigned to the building because the building was already placed by the production manager. The bug was hard to understand because its 3 parts are in 3 different files. At some point I’ll figure out a way to place the building only once unless a problem occurs; that should avoid the remaining problems. Anyway, the effect of fixing this is that buildings commonly start a little sooner with less wasted drone motion, which can help a lot if one side or the other is rushing.

opponent model

Checking for enemy proxies had a serious bug. If the location of the enemy base was known, the check did not run at all! On a 2-player map, the enemy base location is always known. That is why Steamhammer lost so many games against Juno by Yuanheng Zhu under the false belief that its opponent was playing a Turtle strategy rather than a cannon rush Proxy strategy. In fixing this, I moved proxy checking from the information manager to the Bases class, and (with the extra info that class makes available) extended it so that it now checks both the main and natural for enemy proxies. When I first wrote the code, no bots proxied to the enemy natural and checking your main was enough.

terran

• I had to touch the tank code to update it for MicroInfo, and I couldn’t resist a tweak. Tanks siege and unsiege too often, and I cut away a tiny bit of the stupidity: An unsieged tank does not siege if faced with a single enemy melee unit.

zerg

A serious bug in defiler control caused defilers to jitter back and forth seemingly randomly instead of moving to the front where they are wanted. Fixing it also makes the defiler code run substantially faster; there is little risk of overstepping the frame time in the late game due to defilers. This is the second serious defiler control bug I fixed; version 2.1 had the first fix. Defilers are still not active enough—is there a third serious bug?

• A minor bug could prevent a dying defiler from casting one last plague.

• Try harder to avoid making a duplicate or unnecessary defiler mound. It still happened in 1 test game; I don’t know how.

• Even in an emergency, research consume for defilers. That’s when we need it most!

• After an emergency spawning pool because the enemy is rushing or proxying, save larvas so we can get as many zerglings as possible right when the pool finishes. Steamhammer has lost games by making drones while waiting for the pool to finish.

• If the enemy played a fast rush, be more cautious about expanding to the natural. It might not be safe.

• Make emergency zerglings in response to the enemy ground army, not the enemy total army. I saw games where Steamhammer made emergency zerglings to defend against mutalisks, and found itself surprised that it didn’t help.

• I saw Steamhammer lose a number of ZvZ games by making all zerglings versus mutalisks. It’s not always a mistake, but if there are enough mutas and they don’t let themselves get too far out of position, then the lings will do nothing but die (since they don’t know how to scatter or hide). I fixed it to do that less often.

• Emergency sunkens are allowed even if they may not finish before the enemy attack arrives. Steamhammer was trying too hard to avoid overdefending. They are still not allowed if the enemy is rampaging in the natural—most bots will build sunkens then, but to me Steamhammer looks too awkward when it tries, and loses too much. This change involved adding to the “emergency” state a separate “EMERGENCY NOW!” state, which is updated independently.

• Make macro hatcheries faster when there are more drones. It’s a crude rule, but it should improve macro a modest amount.

• Steamhammer has continued to have the problem of overproducing scourge, using up all its gas and delaying other production that it needs. I keep tightening limits, and they seem never tight enough. I added another limit: A total of 12 scourge are allowed to be alive at any one time.

• If we’re maxed, trim the production queue to keep it short. In the late game, Steamhammer likes to put a lot of items in the queue at the same time, because it has the larvas and the resources and it can make them all nearly simultaneously. But when it reaches supply max, it can’t make things quickly any more. The long queue prevents Steamhammer from reacting to changes; it has to work through the whole queue, losing one unit before it can produce the next one, before it empties the queue and reconsiders the situation. Now Steamhammer ruthlessly prunes the queue to a couple items, so it can react and do the most important things first.

• Recognize that zerglings are weak versus dark templar. For some reason, this tidbit of knowledge never made it into the unit mix scores.

• Be more willing to add a second spore colony if the enemy makes multiple scouts. Scouts are not that dangerous... if you actually react to them.

• Don’t try to make a spore colony in the natural base when we don’t own the natural base. This generally causes the spore to be built at the edge of the main base closest to the natural, which is rarely helpful.

• The preferred army size in ZvP is tweaked upward (I adjusted a parameter from 0.60 to 0.65). I concluded that sometimes Steamhammer simply does not make enough fighting units.

openings

• I added 5HatchBeforeGas. It cheats and makes 1 extractor just before the 5th hatchery and 1 after, to avoid a bug that comes up when trying to build 2 extractors simultaneously (the building reservation system is tile-based and doesn’t work in that case, because all geysers are non-buildable for buildings other than a refinery, so it tries to place both extractors on the same geyser).

• I added 8Hatch7PoolSpeed, another rush opening. It’s not configured to be played, and it takes Steamhammer many games against an opponent before it experiments with unconfigured openings, so you won’t see it during the tournament.

• I added a strategy combo AllIn which collects the all-in attacks, such as 8Hatch7PoolSpeed above. It’s not used for now. I’m thinking that exploring all-in openings should be a phase in the exploration program that happens before exploring all openings without restriction. In the meantime, those who wish to play with their own copies can configure AllIn openings for use if they like.

• The 3 hatch mutalisk openings now build a 4th hatchery before mutalisk production starts. The hatchery finishes around the same time as the opening’s last mutalisks. The opening was tuned when I first wrote it, but with mineral locking introduced in version 2.0, it accumulates excess minerals. Steamhammer struggled to recover in the middle game from the macro imbalance of the opening. Mineral locking can make a huge difference in macro openings.

• The usual minor tweaks to openings and probabilities.

configuration file

• If the strategy boss debug option is turned on, you get separate red “emergency” and “EMERGENCY NOW!” indicators. They are independent; either can occur without the other, or you can get both at once. “PANIC” didn’t seem like the right word. Maybe I should call it “DOWN IN FLAMES”?

• A new debug option DrawHiddenEnemies draws remembered positions for out-of-sight enemy units. It was described in this post on Steamhammer 2.1.1.

• There was an accidental duplicate of “Counter Naked expand vT”. Dropped.

The next release should be Steamhammer 2.2, according to my plans as of today (ask again tomorrow). I’m low on energy and feel like skipping an interim 2.1.5 release that fixes the terran and protoss bugs. The headline feature of 2.2 will be that BWTA is dropped and Steamhammer does all its own map analysis. I hope it will be done in January around the time SSCAIT finishes. I want to drop BWTA and upgrade to BWAPI 4.2.0 as separate steps, so that I know what to attribute bugs to. Moving to BWAPI 4.2.0 might be version 2.2.1—I am looking forward to being free of the zerg bugs of BWAPI 4.1.2.

Next: Tournament prospects. Some time after that: CherryPi and SAIDA analysis from AIIDE 2018.

tournament-ready Steamhammer 2.1.4

Steamhammer 2.1.4 is uploaded. It’s ready for the tournament, and it will be the tournament version unless I slip in a few last minute changes. Source release and change list tomorrow, or thereabouts (I have stuff to do that might cause a delay).

This version does have a known bug with transport loading that affects terran and protoss, so the terran and protoss drop openings are not working properly. Also unit clustering interacts with behaviors for a few protoss units: Reavers move far from home before they start to build scarabs; carriers before they start to build interceptors; high templar before they merge into archons (which is all they can do for now). I may make an interim release in the 2.1.x series before the tournament is over to fix these for anybody who wants to download from my site. Otherwise, I expect the next version to be 2.2 after the tournament; headline feature: Dropping BWTA.

the 4 cooperating bugs

Yesterday I pointed out a game versus CUBOT where Steamhammer failed to finish off the enemy and had to win on points when the game timed out. It was due to 4 bugs, and I listed the bugs. Today I want to expand a little: The bugs were all necessary for the bad result. If any one of the bugs were not there, Steamhammer would have destroyed the last building, the enemy extractor, and finished the game on its own.

These are important bugs, because it is important to kill CUBOT fast so it stops spamming how much it needs gas.

1. The extractor was considered inaccessible by ground, so ground units did not try to attack it. The tactical targeting does not send a squad to attack a target that the squad can’t reach. Steamhammer decides ground accessibility like this: If the map were empty, could a unit walk to the position? You can’t walk on a geyser, so the check is incorrect in that case.

If ground units happen to wander close enough to the extractor, they will attack it anyway. The micro targeting takes over. The can’t-reach-a-refinery bug is a known problem, and I never fixed it because, until this game, Steamhammer’s other behaviors had always been robust enough to eventually find and kill any leftover refinery buildings.

2. The Ground squad knows there’s an enemy building left but believes it can’t reach the building, so its job is to explore the map for other enemies. It decided to check the enemy’s mineral-only expansion. Unfortunately, the shortest path there is blocked by a mineral block, and Steamhammer does not know how to path around the block or remove the block. So the Ground squad could make no progress.

3. The Recon squad cannot get jammed in the same way, because if it fails to reach one target, it times out and switches to another. It should eventually check everywhere and kill the extractor. But in this game, a single zergling froze in place at the top of the enemy upramp, and the other zerglings of the Ground squad were positioned so that they could not pass it to reach the downramp that they could not pass because of the mineral block. Stuck units are less common, I think, but still happen. The Ground squad was effectively frozen into a position where it blocked the Recon squad from ever reaching the enemy extractor.

4. Mutalisks don’t care about ground reachability. Despite all the above problems, Steamhammer still would have finished the game on its own if it had continued normally, teching up to mutalisks. But a never-before-seen bug froze production, and Steamhammer stopped making units altogether. I think I’ve diagnosed the bug, and I will fix it.

None of the 4 bugs is critical on its own. They had to cooperate closely, even to the point of freezing one zergling in the right position and placing others around it carefully so they could not move forward or back. Maybe instead of fixing the bugs, I should find the coordinating committee and disband it.

Steamhammer 2.1.3 test version

Yesterday’s version 2.1.2 turned out to have a serious bug that occurs on SSCAIT and not in my test environment. The problem is that a drone on the way to start a building may be reassigned in the middle of its journey, and another drone sent to build instead. If it happens once, it causes a delay in construction—and it often happens repeatedly. Today’s version 2.1.3 tries to fix the bug. I can’t reproduce the bug, even though it happens in every game on SSCAIT, but I know what code is responsible for reassigning drones. I made a couple of improvements that are valuable in their own right, in the hope that one of them will also fix the bug. If not, I don’t know what I’ll do. I don’t want to roll back because my changes are improvements otherwise, and the deadline looms.

Update: Whew, my fixes worked.

Steamhammer 2.1.2 test version

I’ve uploaded the next test version to SSCAIT, Steamhammer 2.1.2. The biggest change is that stuck units are less common. There is still an issue where units can occasionally freeze en masse in the late game, but it’s rare in my tests and so far I’ve only seen it when Steamhammer was winning and it didn’t matter. To fix sticking, I finished up and enabled part of Steamhammer’s new unit control infrastructure, work that has been inching forward for months. I didn’t change anything else or take any unsticking actions; the new structure usually works better by nature than the classic structure inherited from UAlbertaBot.

There’s also a fix for a building manager bug that incorrectly turned expansion hatcheries into macro hatcheries. The bug sometimes made play much worse, but also sometimes made it better, so testing is called for.

Steamhammer 2.1.1 test version

I’ve uploaded Steamhammer 2.1.1 to SSCAIT. It’s a test version that I don’t expect to release source for. I’ll follow a plan similar to last year’s: Upload a series of test versions as the tournament approaches, in hope of catching any new bugs and weaknesses before it is too late. The version that goes into the tournament will be whatever is ready by then, and that is the version that I’ll do the full release job for. Last year I used “1.4a1” and so on as test version numbers. This year it will be “2.1.x”.

There are quite a few changes, and they are probably not what you are expecting. I count 5 fixes for serious bugs that could easily lose games, plus mitigations to reduce 2 important weaknesses, plus a bunch of quick corrections and tweaks for less important issues that came up. There is still 1 major bug at the top of my list to fix before the tournament, and we’ll see whether I’ve introduced any awful new weaknesses—some of the changes are risky, it would not be a surprise.

I disabled Randomhammer until after the tournament. It’s not broken or anything, I just felt like turning it off in plenty of time this year. Everybody else will get in a few more last-minute games.

I changed the debug drawing options to show off a new option that I added, DrawHiddenEnemies. It draws 4 symbols to represent known enemy units and buildings that cannot be seen at the moment: An enemy that is out of sight gets a small green circle at its last seen location, or a yellow circle if it was burrowed when last seen (especially useful for spider mines and lurkers). An enemy that is out of sight and is known to be no longer at its last seen location gets a red X instead. And an enemy which is in sight and is not detected gets a larger violet circle (a faint color that I think of as representing the cloaking field) and is labeled in white with its unit type. The picture is from a game versus Iron. The yellow circles are known spider mines outside detection range, and the green circle and red X mean that at least 2 more enemies are out of sight, likely nearby.

hidden enemies symbols

I’m not finished with AIIDE 2018. I want to analyze aspects of CherryPi and SAIDA. I’ll squeeze that in too, sooner or later.