archive by month
Skip to content

new bot RedRum

RedRum is a new terran bot. I would say “Yay!” but this version of RedRum is identical to Steamhammer 2.3 playing terran. It’s the same binary with a different name, and there are no changes to the configuration file that affect play. It does give the author as Ayran Olckers, the bot name as SteamRoll v0.1, and the bot’s race surprisingly as protoss.

I suppose this is a test run to figure out how to do stuff. Version 0.1 implies a future version with a bigger number. When RedRum starts to become interesting, perhaps under a different name if it turns into protoss, I’ll write about it again.

the third defiler bug

Looking closely at the newly implemented queen play, I noticed a bug that caused delays in action. The queen would spot a good target and prepare to launch its parasite... then lose track of what it was doing and execute a move instead, find the good target again, etc. I fixed it to keep proper track of its intentions, and suddenly the queen’s actions were prompt to the point of being overeager: It would move into range and cast its parasite, then before the parasite landed, parasite the same target again! I had to fix that too; it was not enough to stick to targets which are not already parasited. Then I realized... oh... this must also be the long sought Third Defiler Bug. Queens and defilers have their own code, but they work about the same way.

Last fall I added defiler support. In the winter I fixed two serious bugs (see the zerg section) in defiler control. And I suspected that there was a third one, because defilers still reacted sluggishly. This is the third bug—I finally found it.

When the queen fix is properly generalized for defilers, I expect that defilers will start getting stuff done. As ground units they will still meander into traffic jams and struggle to coordinate with their food to consume, and dark swarm (which is extremely hard to use well) will still be restricted to narrow circumstances. Even so, I expect defilers to be much more active, more nearly what they should be.

So, as usual, the next release should have more improvements than planned.

Parasite works moderately well. On average the queen does not really pay for itself, but it’s a small expense (no research and the queen’s nest is there anyway), and I expect it will pay off in a few games. If the queen is lost, the strategy boss waits 3 game minutes before ordering up a new one, so even if the queen gets irradiated instantly it won’t be a big drain on resources. And every once in a while it can infest a command center.

a fast building placement idea

This is an idea I came up with while working on building placement in the live Steamhammer. In that version I made the basic operation “can this building be put here?” faster by cleaning up redundant calculations. In the future I want Steamhammer to do complex building placement optimizations on the fly, requiring many steps, which means it will be useful to speed up each step even more. I haven’t implemented the idea, but it’s simple and seems broadly useful so I want to write it up for everybody.

Checking “can this building go here?” first of all means checking whether all the tiles the building will occupy are buildable and unobstructed. BWAPI can do this in one call. Steamhammer also checks certain adjacent tiles, and sometimes tiles adjacent to a neighboring building, to make sure there is free space and units can move around. The net effect is that certain rectangles of tiles are checked, one tile at a time: Is this one clear? The next one? The next one? There are a few extra checks like “is there pylon power?” but checking open space is the main part.

If you’re going to do a lot of building placements, as I am planning, then you can reduce the check of any one row or column of tiles to a single lookup in one of two simple precomputed data structures: How much room is clear to the right of/below this tile?

The algorithm is trivial. For example, to find out how many tiles are clear to the right of each tile on the map, start with a currentRoom counter set to 0, and scan each row of map cells from right to left. If a cell is open, increment currentRoom and store it; otherwise, reset the counter to 0 and store that. Done.

So if you want to place a 4x3 building with 1 tile space around it, you don’t have to check 6x5 = 30 tiles individually. You can check the 5 rows with 1 lookup each. Furthermore, if you’re going to compare different possible locations to choose the best, the minimum of those 5 values tells you how many tiles you can slide the building horizontally—you verify all those potential building placements with no further work. If you’re comparing many placements, you should easily earn back the investment of computing the extra data structure.

If you only want a fast first check for clear terrain, you can build the lookup table or tables once at the start of the game. If you want to take into account your own buildings and other stuff that you know about, you can build the table fresh when you need it, or you can update it incrementally as buildings come and go. The incremental algorithm is not hard. If you know the general area you want to build in, you can restrict the table to that area—for example, within the bounding box around the creep of a given base.

It’s simple and not entirely obvious, though I won’t be surprised if some bots already use the idea. I thought it would be useful to write up.

write a bot!

I’m starting to worry about the lack of new bots on SSCAIT. The old standbys are going strong, with updates and improvements, but there are no newcomers. With nothing added to the pipeline the pressure falls, that’s physics, and eventually it will run dry.

I don’t know the causes, but I know there are two places to look, outside and inside. How much is due to shifts of interest outside in the big world? What’s hot depends on factors like visibility and prestige, and I don’t feel that I can affect it—maybe you can. How much is due to the inside, shifts in perception of the BWAPI community? Do people feel discouraged from joining? It might be due to perceived difficulty in getting started, or perceived newbie-unfriendliness in some form (elitism, rudeness, etc.), or something else. I may be able to make a small difference on that side.

write a bot!

The game of Starcraft Brood War opens a huge range of strategies for players. The hundreds of bots that have been written to play the game are nowhere near exhausting them. In practice, that means that if somebody writes a bot and doesn’t flat out copy a strategy already used, then the bot will play differently than any other bot—it may be good or bad, but it will be fresh. That makes it a contribution to the community, which is why I want to encourage new bots.

Writing a Starcraft bot is sort of like drawing pictures. You have to learn some basic skills first, or your picture won’t be any use. But the most basic skills you need to draw a recognizable picture are not difficult, and it doesn’t take long to learn to draw a simple cartoon. To extend the metaphor, if the cartoon expresses an interesting idea, then it is an interesting cartoon even if the technical drawing skill behind it is not well developed (the secret of Randall Munroe). A Brood War bot that does something different from all others is an interesting bot.

Coding a bot is also like drawing in that you are free to choose your stopping place. You can draw one cartoon that expresses your idea and be done with it (I have literally done that and I think it was worth it), or you can devote your life to improving your skills and try to become Rembrandt. Or anything in between. Marine Hell is an example of a “first cartoon” bot. Its description says This bot was written from scratch in 5 hours following official tutorial. I would like to keep it “as it is” to show how easy can be to write simple bot which is capable of winning. Marine Hell is not a strong contender, but it wins games and it has been playing continuously on SSCAIT since March 2017. At the other end of the spectrum, I’ve been working on my bot Steamhammer since December 2016 and intend to continue for years, and I think that is worth it too; others started earlier and are still going. Do as little or as much as you want.

The AITT tournament series of bots with severely limited code size are another way to see that a bot does not need to be large and complex to be interesting.

If you decide to go ahead and write a bot, your first decision—before you type a line of code—is whether to start from scratch or to fork a starter bot. Both ways are good; both ways can be fairly easy or as hard as you like; both ways can lead to strong bots. Look around and take your choice.

If you are unsure about interesting play strategy, I offer two hints. A large proportion of bots follow one or the other of these broad strategic patterns: 1. Make tech switches. If you make one unit type and press aggressively with it, your opponent is forced to respond. Then you switch to another unit type, one that puts different pressure on the opponent, and you are sure to win some games. It can be a complex calculation (Steamhammer tries to figure out what tech switch will hurt its opponent), or a sequence of tricks (krasi0P goes cannon contain then dark templar then carriers), or it can be as simple as always making this, then at a fixed time making that instead. 2. Defend soundly, build up during the defensive phase, then when you’re big and strong, head out and go break stuff. Bots as varied as SAIDA, Johan Kayser, XIMP by Tomas Vajda, and ZurZurZur follow this pattern.

I don’t have to offer more detail than that. By the time your bot is able to play a complete game, at the latest, you will have your own ideas. I promise.

In the meantime, I am making slow progress myself. I bought new hardware to replace a laptop that’s 10 years old (seriously!), and I have workflows and stuff to migrate, mostly things that have nothing to do with Starcraft.

BASIL unit destruction statistics

The BASIL stats page includes a table of unit types with how many of the type have been created and destroyed on BASIL in the last month. From this we can gain boring insights, such as that buildings are more likely to survive the game than units. But I also see a few interesting points.

Here are the basic units with their chances of dying. The cheaper the unit, the less likely it is to survive. Marines should have a lower chance to live than zealots, because sometimes you make marines only in the early game. To me, it’s not obvious that zerglings should have a lower survival rate than marines. Notice that zerg (48.5%) has a slightly higher overall winning rate than terran (47%). Maybe zerg mines more and burns more units overall.

type% destroyed
zealot71%
marine75%
zergling80%

What units had the best chance to survive? It seems that most unit types (leaving aside buildings and temporary units like eggs) are more likely to be destroyed than not. The table includes units with less than 40% destruction chance. The champion is the terran siege tank. I think that’s because when terran is able to make a lot of tanks, terran wins! The low death rate for dropships (but not shuttles at 45%) may mean that dropships maneuver more cautiously—reaver drops call for aggressive shuttle movement. It’s striking that, except for the tank, every unit in the table is a flyer. Most have ample hit points; tanks, vessels, carriers, queens, and guardians have long range and can stand off from the hottest part of a battle. Another possibility is that only stronger bots use high-tech units at all. Notably missing are the terran valkyrie and zerg devourer.

type# made% destroyed
siege tank18486013%
carrier2401318%
arbiter336723%
dropship316827%
science vessel1563533%
queen1499234%
battlecruiser513336%
guardian402137%

Some units you don’t expect to often survive the game, but sometimes they do anyway. My thoughts: If the scarab count includes scarabs made but unfired and remaining in the reaver’s inventory, the number seems too low; if it includes only scarabs in flight at the end of the game, it seems too high. Maybe it doesn’t count a scarab as destroyed if it was inside a destroyed reaver? That’s a lot of expensive unused nukes! Is the high number of active scans at the end of the game because some bot or bots scan for unseen bases when all targets are cleared? It’s too bad that only scanner sweep is included in the table. Other spells like psionic storm [an error; see comments], disruption web, and dark swarm are also represented as units; the difference is probably that scanner sweep is owned by the player, while other spell units are neutral.

type# made% surviving
scarab1495900.23%
nuclear missile44918.26%
scanner sweep1484781.80%
broodling141841.03%

more Steamhammer 2.3 bugs

Earlier, I pointed out 2 rare game-over bugs in Steamhammer 2.3. It turns out that there are 2 other serious bugs in this version, which are not rare; they are causing a good proportion of the bot’s losses.

One is a bug in turning gas collection on and off. The bug can turn off gas collection even when the bot needs gas to continue production, causing a production freeze that can last for the rest of the game (not likely to be long with no production). It may have been introduced when I refactored the code for gas decisions. The other is a bug that cancels vital hatcheries (and perhaps other buildings) for no apparent reason. I suspect an error in one of the emergency “uh oh, no drones!” or “panic! I need those resources back NOW!” tests. There are other possibilities.

Critical bugs go straight to the top of my list.

The bugs also point out a weakness in Steamhammer’s design: Decentralized decision making. Decision rules that take direct action are scattered through the code. Of course a bug in any rule can cause bad behavior; that’s inevitable. The weak point of the design is that the separate rules, sometimes far away from each other in the code, have to cooperate so they don’t override each other’s decisions. The gas collection bug is clearly a coordination bug; one rule says “I need gas for the next production item” and some other rule is incorrectly overriding the decision, “nah, I wanna turn off gas.”

Compare the unit mix decision, which is made using a more indirect method: Rules collect evidence, then in a second stage the evidence is weighed and the decision is made. The evidence is explicit, so bugs are easier to trace, and evidence-collecting rules do not need to cooperate with each other, they only need to weight their evidence consistently. Machine learning systems conventionally follow this collect evidence, then decide paradigm as a matter of course.

a trivial rule of thumb for lurker targeting

One of the items on my list is good lurker targeting: Lurkers should aim for the target that will bring about the most total damage, with the lurker’s line of splash damage. In the current release, Steamhammer’s lurkers use the same targeting as most units, choosing the closest available target when other things are equal. It’s not so smart, but improving lurker targeting has been a low priority; the full analysis is more effort than it’s worth for the time being. Lately I hit on a simple idea to improve targeting without doing any deeper analysis. It’s a rule of thumb that I notice when I play myself, but for some reason I never thought of implementing it before.

Suppose a lurker is to choose one of 2 targets, and it knows how far away each is but nothing else. It has to choose blindly. Which target is the better choice? Does one of the targets offer a better chance of blindly landing splash damage on the other, with the lurker spines reaching out in a line? It might be counterintuitive, but geometry gives an answer: The more distant target is better. If you aim for the near target, the far target subtends a smaller angle from the point of view of the lurker. If you aim for the far target, the near target subtends a larger angle, so you are more likely to hit it by chance. If you don’t believe me, draw some circles on paper, or start up the game and try it!

The same reasoning works if there are 3 targets; pick the farthest. If targets are dense, it doesn’t matter where you shoot, and if targets are sparse and you do no further analysis, then aiming for the farthest is best. It’s dead simple, so I implemented it in Steamhammer, choosing the highest priority target at the greatest distance rather than the smallest distance. It is a small but real improvement, and it was hardly any effort. There is a disadvantage, which is that the more distant unit may be better able to sidestep the lurker spines, since it has more time to react. But not many bots dodge lurker spines.

Of course it’s much better to do the full analysis: For each target, calculate which enemies the lurker will hit and what the hit is worth. Ideally, predict how the enemy units will move, taking into account their likely decisions, and correlate their paths with the extending line the lurker spines will follow. And optimize the fire of all lurkers at a location as a group, so that they cooperate to kill more efficiently (2 lurker shots kill a marine, so these 2 lurkers should aim here and here to overlap their splash damage). It is an elaborate calculation, and I don’t think it’s worth the effort for now; better to improve Steamhammer’s other decisions first.

random bots on BASIL

Today I revisited the BASIL stats page with its collected numbers. The random bots got me thinking.

Over the stats period, the random bots collectively scored 56.8%, making random the most successful choice of race. On BASIL, the server chooses the random race before the game starts so that the opponent knows it, so theoretically there should be no game play advantage to being random. There could still be an advantage in confusing the opponent by playing a wider range of strategies, each less often—or that could be a disadvantage, depending on how the learning of each side works. In practice, does playing random give an edge, or did stronger bots choose to play random?

It seems impossible to answer the question by comparing strength numbers between the randoms and the rest. Do the random bots have higher elo? Well, they scored better! The result says nothing about the direction of causation, if any.

Another line to answer the question is, do the random bots score better or worse than their component races playing independently? We can answer by averaging the elo ratings, because elo is designed so that strength differences can be added and subtracted. I compared PurpleDestiny, tscmoo, and ChimeraBot.

PurpleDestiny has elo 2273 at the moment, and I get 2333 for the mean elo of its 3 components. There is no evidence of an advantage for playing random while purple.

Tscmoo random is at 2348, while its components average to 2146. It may be that playing random is effective for cows (“moo!”). But it could also be that the apparent components aren’t actually part of tscmoo. They were updated at different times, and I expect that they are configured differently too, with different sets of strategies allowed. If so, the comparison may not mean anything.

ChimeraBot (made of Iron, McRave, and ZZZKBot by Chris Coxe) is at 2342, while its components average to 2330. But Iron and McRave have both been updated since ChimeraBot was assembled, and I believe the updates were improvements. If so, the true mean of the components should be lower, but in any case it is probably different. There is at best weak evidence of an advantage for playing random while chimeric.

The bottom line is that the result is inconclusive. I haven’t found enough information on BASIL to judge whether playing random is an advantage, or a disadvantage, or a wash.

By the way, the stats page says there are 18 random bots, but I count 11 on the ranking page (2 disabled). Does the ranking page not show all bots?

Steamhammer and queens

When I announced that Steamhammer 3.0 would be next, I forgot a step: I want to upgrade to BWAPI 4.4.o. I actually want to make a 2.3.1 release first with the upgrade. I think I can probably do it this month, along with other additions, even though I may not start the work until next week.

Just now I don’t feel like any serious work, so I started to implement queens. Queens are not essential; you can be a great zerg and never spawn one. Often enough, queens are not useful at all. But queens are fun, and I feel like doing fun stuff.

I’m starting with parasite, and I’m thinking the order should be parasite, then infest command center (you get both of these with no research), then ensnare, then broodling. I don’t expect to do them all at first, but I will eventually.

My initial plan is to always make 1 queen versus terran, if the situation permits, in hopes of infesting a command center. And to make 1 queen against protoss if Steamhammer spots juicy parasite bait, like a carrier. In ZvZ a queen is too expensive, unless maybe you can broodling defilers and ultralisks if the game goes that late.

In the longer run, I want Steamhammer to learn for itself which tactics work, and which work against each individual opponent. It should be possible to measure whether parasite brought in information, whether ensnare harmed the opponent, and so on, and estimate whether the queen and the research to use it paid dividends. Decisions based on data are better decisions.

parasite

Parasite is rare in pro games, though it has been used. If you have queens at all there is usually a better use for their energy. But bots are not as knowledgeable as pro players. Could parasite be useful?

I am going to try parasiting flying critters, on maps that have them, to see if it’s useful. And I’ll try parasiting expensive enemy units: Science vessels, battlecruisers, carriers, arbiters. I expect that a few strong terrans will react well, and the bulk of bots will not notice the parasite and will give Steamhammer free information. But we’ll see!

By the way, parasiting a science vessel is not too dangerous if done carefully. Irradiate has a range of 9 tiles, while a queen has vision range 10 tiles, so a queen that approaches cautiously has good chances to launch a parasite without getting irradiated. Parasite has range of 12 tiles (the same as the range of a sieged tank), so if other units spot for the queen then parasite can be always safe.

How to react? If you spot a parasited neutral unit (and it’s not your parasite), kill it. If you’re terran and one of your units gets parasited, you can research restore for medics and remove the parasite. That will take time, though (unless you’re Krasi0, which researches restore pre-emptively and cures spell effects in moments). Zerg has 2 ways to remove parasite (if it ever happens, which is unlikely in ZvZ), both with limited use: 1. If a drone is parasited, you can turn it into a building. 2. If you have a queen of your own, you can place your own parasite on your unit, which overrides the enemy parasite. Protoss doesn’t have any options, and can only be rid of the parasite by killing its own unit.

You can also move a parasited unit away from your army, or use it to show the enemy what you want the enemy to see. The opposite approach is to put it in the front of your forces, so it is the first to be killed.

infest command center

What’s to say? If you bought the queen already and you can infest a command center, you should! For now, I won’t bother with infested terrans, or with details like stopping the attack when the command center falls below half HP so that it is not destroyed before the queen can infest it. Leaving the infested command center where it is may slow the enemy from retaking the base.

ensnare

Ensnare is useful against fast units in groups. I’ll try it first against marines, wraiths, and corsairs. Vultures are hard to tag, but I might experiment. It’s also useful to reveal cloaked units, so it may also be worth researching against dark templar, arbiters, and maybe ghosts.

An ensnared unit moves much more slowly (usually at half speed), and most unit types also shoot a little more slowly. It will be difficult to retreat, or to complete any other tactical maneuver. A logical reaction is to hold your ground until the green goo wears off; you lost a lot of mobility and only a little firepower, so rely on firepower.

broodling

Broodling is expensive to cast; it costs 150 energy, which takes a long time to build up. It’s also the only queen ability that can justify making more than a few queens. It’s good against expensive ground units like tanks and high templar—provided you keep the queens alive so they can do it again (the 100+100 cost of a queen plus the cost of the time to build energy is worth more than one 150+100 tank). Broodling is most valuable in the very late game, when the map is mined out; at that point you want to favor spellcasters no matter your race, because you won’t have the resources to replace units.

There are 2 counters to broodling: 1. Kill the queens. 2. Make units that cannot be broodlinged (wraiths, reavers, archons), or are not worth the cost of broodling (marines).

Steamhammer 2.3 early returns

I’m pleased with how the new Steamhammer 2.3 is doing. Not only is it scoring wins where it could not before, its play looks sharper and cleaner. It’s mostly due to bug fixes. It beats XIMP by Tomas Vajda again (command jam bug fixed in 2.2), and it is back to its former success with heavy early zergling pressure (unit movement fixes in 2.2 and 2.3 plus zergling value fix in 2.3). I added many new openings in 2.2, and the unsound “dawn hydra rush” (those hydras arrive in the morning gray) is scoring well against SAIDA due to SAIDA’s broken reaction. The same opening worked against Iron when I wrote it, but one of Iron’s updates added a reaction and Iron is now safe. The value of the other new openings, positive or negative, will take time to show.

Randomhammer’s better building placement make bases look prettier. Having fewer buildings bursting into the center of the map can only help play, though I think that most opponents which are able to exploit the vulnerable buildings were going to win anyway. The tank improvements make terran factory play look almost... non-ridiculous. The tank play was awesomely bad before; now it gives the impression of trying to do something sensible, though it doesn’t always succeed. And, of course, drop openings work again; that may not be reflected in performance right away, because Randomhammer remembers the results of its previous version, which learned to avoid the broken drops against some opponents. Still, I’ve seen a few crushing drop games.

BASIL is better than SSCAIT for strength measurements. Here is Steamhammer’s elo graph from BASIL:

graph showing strong rise

Version 2.3 was uploaded 2 April, and includes the improvements in 2.2 and 2.3, since the previous running version was 2.1.4. The graph shows a strong rise on 3 April, 75 elo over its base, with a peak nearly 50 elo higher than the next highest peak in the graph. It’s pretty good evidence that Steamhammer is improved; the elo increase is likely 50 or more.

The same for Randomhammer:

graph showing questionable rise

This is not as clear. The peak begins to rise on 4 April; I think that is mostly because of game scheduling. It is about as high as previous peaks on the graph, and it is not convincing that it is statistically meaningful rather than a random winning streak. I’d say there is weak evidence for a strength increase. I will be disappointed if Randomhammer doesn’t end up showing a detectable elo rise.

I did a round of work on overlord safety last fall, and improved it enough that it was no longer one of the top weaknesses. Now other aspects of play have improved enough that overlord safety is again a critical weakness. There are also 2 game-over bugs that guarantee a loss. One causes drones to hang out with the minerals instead of mining; it’s rare. The other causes general confused behavior, and it is extremely rare. Rare bugs with no identifiable trigger condition are tough, but they have to go.

AIST S3 announced

Nathan Roth aka Antiga has announced AIST S3 (passing it on in this comment). The tournament will be held next year, with the same end-of-February submission deadline as the S2 edition. Plenty of time to prepare!

Don’t miss the key changes at the top: Source will be published, and BWAPI 4.4.0 is required (or later, if we have a later BWAPI by then).

Next: Experience with Steamhammer 2.3 so far.

CIG 2019

For anyone who hasn’t noticed, the CIG 2019 tournament is announced. The key info:

Registration date: 17 June
Submission date: 10 July
BWAPI versions: 3.7.4, 4.1.2, 4.2.0, 4.4.0
Latency setting: LF6 (“Fastest”)

As I hoped and expected, they are supporting the latest BWAPI 4.4.0.

Last year, CIG 2018 had some issues. (Note: One item I listed as a tournament issue, Ziabot’s problem, was likely Ziabot’s own doing, and the build order breakdowns were apparently due to the LF6 latency setting that bots were supposed to be ready for, and can also blamed on the contenders—though you have to wonder why they decided to change the ground under the feet of returning bots.) The build order breakdowns affected Steamhammer and messed up its play in every game. Making the debacle worse, Steamhammer suffered a severe crashing bug, which was of course on me. All in all, it left me with an impression of unfairness and it was not a fun experience. I’m not inclined to play in CIG this year.

I do expect to analyze the results, though. If all goes well, maybe next year.

Steamhammer 2.3 change list

SSCAIT has been running Steamhammer 2.1.4 from December, skipping Steamhammer 2.2 that played in AIST S2. To see everything that’s changed since December, you also want the Steamhammer 2.2 change list.

Voters have been busy trying out the update. Fixes in version 2.2 restored Steamhammer’s ability to smash XIMP by Tomas Vajda, even from an inferior opening, so that was no trouble. Steamhammer also tried its super-fast “dawn hydra rush” in a game against SAIDA, bringing out SAIDA’s broken reaction. It’s stuff from version 2.2; version 2.3 should make zerg only slightly stronger compared to 2.2. Terran and protoss are a different story.

Source release soon. It’s more work than you may imagine.

The most important changes are in bold.

buildings

Most of the new code went into building placement. I added a special-case building placement mechanism that checks each incoming building to see if it should be placed differently than the default rules say. I use it in several ways. The net result is that terran bases are much more compact, and terran can sometimes play a long game without ever spilling buildings into the center of the map, which is quite a change. It does happen at times, though. Protoss bases are more compact too, but the benefit is less. Protoss still sprawls a fair amount. Zerg bases too are affected, but it’s barely an improvement because zerg doesn’t make many buildings in the first place.

Terran builds along the map edges of its base, using the space to compactly place supply depots, academies, and armories in a single line (they don’t double up). The buildings are 3x2 tiles in size and line up neatly. More total buildings fit into a base. It doesn’t help a base which does not reach the edge of the map. Also certain maps have unbuildable tiles along the edge and see no benefit. Usually, though, it helps a lot.

2 buildings may be adjacent. 2 buildings that are the same height may be placed shoulder-to-shoulder, and 2 buildings that are the same width may be stacked vertically; the limitation is so that I could reuse code that I wrote for terran edge placement, but it makes sense anyway as a space-saving measure. It applies to most buildings; there are a few exceptions like pylons that are treated differently. It allows only 2 adjacent buildings, checking that a building chosen as a buddy is open on all sides. That way building placement creates no blockades or long detours. It applies to all races. Terran, with free building placement, benefits the most. Protoss benefits some, but pylons and pylon power get in the way. Zerg bases can fit more buildings too, but it doesn’t bring any visible benefit to Steamhammer’s play.

When building placement fails, Steamhammer looks for a new “main base” to hold future buildings. “Failure” in this sense means that either the building could not be placed, or else it was successfully placed but ended up in a different zone than requested (the building gets built there anyway, it’s usually not awful). It keeps track of the number of times placement has failed at each base, and chooses the base with the least failures to date. It’s hardly perfect, but it works better than the old system of from time to time choosing a new main base at random. It works especially well when terran expands to a different main with plenty of building space. Protoss switches main bases the most often, and zerg by far the least.

• Protoss tries to place a pylon at every base, in case it someday wants to choose the base as a new main base to build at. Or wants cannons there. It doesn’t insert extra pylons, it places regularly scheduled pylons at new bases as they come up.

• I fixed 3 separate off-by-one bugs (inherited from UAlbertaBot) that affected right and bottom edges. One was in building separation checking; on the right and bottom sides, they were kept 1 tile farther apart than requested. That was the worst one, because it wasted space around many buildings. It was visible, and held a place on my bug list, but I hadn’t found the cause. One was in building placement checking at the right and bottom edges of the map; buildings were kept 1 tile farther away from the edge than required. One was in the base overlap check; buildings were kept 1 tile farther than necessary on the right and bottom sides of a potential base location. All bases are a little more compact because of these fixes, though you might not notice with a casual look.

• I fixed a rare bug—so rare that I have never seen it—that theoretically could allow a macro hatchery to overlap the location of a base that we might want to take in the future.

• Formerly, building placement made frequent redundant checks for things like “is this tile reserved for another building?” and “are there units blocking this tile?” I gave it a severe scrubbing, and now there are few redundant checks. The basic operation “can this building go here?” is faster than before because it wastes less computation. Building placement overall is not faster, though, because the special case placements do more basic operations.

• Formerly, reserved building tiles were drawn (when the debug option was turned on) in bright yellow. I found it glaring, so I changed it to dim gray. The option is turned on in the release version.

• During the rewriting, BuildingPlacer::buildable() became redundant and was removed.

operations and tactics

MicroManager::execute() didn’t execute all orders, a bug which caused drops to do no damage. Version 2.2 fixed the command jam bug, which prevented transports from picking up units to drop. With that out of the way, when the squad arrived at the enemy base with order Drop (which in that context should mean attack enemies near the drop point), the order was not executed and the units moved to the order position and sat in the enemy base, getting killed without firing a shot. Oops. When was the bug introduced?

In FAP, I forgot to correct for twoUnitsInOneEgg() in setting unit prices for the combat simulation. That theoretically affects zerglings and scourge, but scourge work differently and in practice only zerglings were affected. They appeared twice as valuable to FAP as they actually are. Oh, that’s why zerglings seemed to be so shy! Zerglings are back to their proper level of boldness; they are more aggressive in fighting everything except other zerglings. Zealots and workers especially should be afraid.

Lurkers in a unit cluster which was joining up with a cluster ahead could be mistakenly given contradictory orders one after another, causing them to get stuck or to vibrate in place. The bug also affected medics and defilers, though not severely. Lurkers were often delayed in the middle of the map, which could be a major setback.

• A unit cluster with no surviving combat units which was falling back to the base was mistakenly given 2 different orders on each frame, causing it to behave erratically and usually get caught and die. I solved it by adding a Fall Back cluster status instead of incorrectly using Retreat, which comes with its own different behavior. This affected terran the most, when only medics survived in an attack.

• UAlbertaBot provided unitClosestToEnemy() for each squad, used in tactical analysis. Steamhammer inherited it and renamed it the vanguard unit. Until now, the vanguard was used only internally to the squad. Now the vanguard, if set, is publicly available via squad.getVanguard(), so it can be used at the operations level. It is used in deciding which enemy base to attack: A base near the current vanguard is preferred. It attempts to direct the squad to targets which are closer to or on the way to the existing squad target. I hope it will reduce cases where Steamhammer wants to attack the main and tries to run by the natural... without understanding what it is doing, so that it turns back after taking damage. I also hope it will be better at switching targets to a new base that appears near the squad’s path, and better at choosing bases that are near each other to destroy in sequence.

• Mildly prefer to attack an enemy base other than the enemy starting base. It is a popular heuristic, I thought I’d try it. Not sure it will help.

• Steamhammer calculates the “front point” of the “front base” that needs to be defended, now using the center of the base’s resource depot, no longer the upper left corner. In doing that, I noticed that the center was calculated incorrectly (even simple things can be completely wrong), so I fixed that. I also switched other uses of the base position to the center, when appropriate. It seems like an improvement, though not a big one; the front line is no longer biased to the left.

micro

the.micro.MoveNear(unit, targetPosition) does unit movement when up-to-the-frame accuracy doesn’t matter—as it often doesn’t. It compares the new target position you give it with the unit’s existing target position, if any. If the two are close enough together and not many frames have gone by, it doesn’t bother to issue a new command, but concludes that the existing target is good enough for now. This greatly reduces APM in the cases where it applies, which prevents units from freezing due to excess commands. The new feature is used to move clusters which are trying to join up with other clusters (which are often themselves moving), and in micro when chasing an enemy which is still far away via the.micro.CatchAndAttackUnit(). In practice, units now do not freeze for long periods. If you look for it, you can see many cases where units freeze for a short time, but the combination of unit unfreezing from version 2.2 and this feature means that they unfreeze quickly. I tested by setting up a game with big dragoon-on-dragoon battles, and could not see any dragoon freezing for longer than a moment. Zerglings freeze for longer periods, but are much improved over version 2.2.

terran

Tank siege decisions are much improved. Steamhammer’s long-time mechanism for tank siege has separate decision criteria for siege and unsiege: Siege if shouldSiege and not shouldUnsiege; then unsiege when shouldUnsiege. That allows it to do things like not bother to siege if the only targets are defenseless enemy buildings, but not to bother to unsiege after other targets are defeated if enemy buildings are still in range. But the criteria were so sloppy that in practice tanks were barely able to fight. I made 3 changes. First, when a tank is sieged, it prefers a target outside of its minimum range. Formerly it preferred the closest target, meaning that if any target was inside minimum range the tank had to unsiege to shoot at it. It’s not efficient. Second, when facing a single enemy threat (meaning a ground enemy that can hurt a tank), don’t bother to siege. Siege mode has higher DPS, but the time it takes to siege negates that, and with only one thing to shoot at there will be no splash damage. There are exceptions: Siege anyway if the single threat is a bunker, cannon, sunken colony, or reaver. Third, if all the targets are melee enemies and all the targets are at the same terrain level as the tank, then don’t siege. It’s a heuristic; kiting is generally better than siege in tanks versus zealots and tanks versus zerglings if the melee units can reach the tank, and the reverse if a cliff is in the way. There is no consideration of whether a wall may be in the way (as on Empire of the Sun, for example), or whether a mass of other terran units is in the way. The result of the 3 improvements is that tanks are deadly, as they should be. The biggest errors in tank usage are no longer in micro, but in tactics; a tank also unsieges if the whole squad decides to retreat, and the squad decides that without considering the cost of unsieging tanks.

• Tanks prefer to target Large enemy units. Hit the dragoons before the zealots, you will do more damage. Unit size as one of the targeting criteria was already implemented for ranged units in general, but tanks have separate micro.

• No longer automatically make a bunker in response to a detected Heavy Rush. It was sometimes useless and almost never at the right timing.

protoss

The “away from home” bugs are fixed. Reavers and carriers no longer approach the enemy before starting to build scarabs or interceptors, and high templar again merge reliably into archons instead of wandering into the enemy base, unable to storm. The bugs seem to have been introduced in version 2.0 in September.

• Scarabs and interceptors are ordered as they can be built, rather than queued up. It’s a little more efficient.

• Carriers historically have been put into the flying squad if the flying squad exists, and otherwise stay with the ground squad so they work together. Now if there are 4 or more carriers, they go into the flying squad regardless and act independently. It’s primitive but likely an improvement on average.

the.micro.MergeArchon() supports dark archons. Steamhammer doesn’t know how to use any of their abilities, but now you can make them.

• React to mutalisks with stargate and corsairs. The reaction is implemented via BOSS, and it is so sluggish that it barely helps. As I implement production goals for strategy adaptation, the reaction will become quicker and crisper.

zerg

• Be looser with macro hatcheries. I found that when Steamhammer ran short of larvas, it was too slow to build enough hatcheries—sometimes it walked along the edge the whole game, growing its economy faster than it could catch up in hatcheries. With this change, I may have overcorrected; now it sometimes makes too many hatcheries and has larvas it can’t spend. As part of strategy adaptation, I will have it predict larva needs so it can hit on the nose most games.

• If the minerals are on the left of the starting hatchery, do the larva trick to gain a tiny resource advantage. It makes virtually no difference. Stream watchers will have to know what to look for to even notice that it’s happening.

openings

Most terran openings needed adjusting. The adjustments were largely timing changes to take advantage of the extra resources provided by mineral locking, corrections to avoid bad queue reordering, and getting supply depots in time. The more complex openings (and terran has a lot of complex openings) I repaired to a higher standard than they were built to in the first place, so as a set the terran openings are better than they have ever been. They work more reliably and hit earlier timings.

• I couldn’t resist adding the terran opening 8-8-10Vultures, which rushes a factory and pokes with a vulture that the enemy may not be expecting so early. Terran has more than a few fast barracks and fast factory tricks; when strategy adaptation is mature enough it will be able to try many of them.

• The protoss openings did not need as much adjustment; only the high tech openings needed fixes. DTRush is slightly faster, and CorsairDT and DTDrop are tweaked. With surplus resources from mineral locking, CorsairZealot and CorsairZealotDT move out with 2 zealots more at the same timings as before. I think CorsairZealot is particularly tough on zergs.

code

• Use UnitType::canBuildAddon() instead of checking the building types by hand. Use UnitType::requiresPsi() instead of UnitUtil::NeedsPylonPower(). Know your BWAPI (unlike me)!

• The option Config::Debug::DrawMapInfo shows another bit of info: It draws a red circle over the “front base” that is to be defended (e.g., the natural if Steamhammer owns a main and natural), and another over the “front point” near it where the defense is to go. It connects the circles with a red line, making a red dumbbell. The dumbbell is there to show you how dumb Steamhammer is, and what a weight it still has to lift.

• If you turn on the right debug option, terran and protoss will print a “building supply” message when inserting a supply depot or pylon into the production queue. I moved it from the option DrawBuildOrderSearchInfo (which talks about BOSS stuff) to DrawQueueFixInfo, as a portent of the removal of BOSS in the coming corporate restructuring.

• I made another pass through the Visual Studio settings and found lingering references to BWTA and SparCraft (!). How did those get by? I was sure I’d gotten them all. They didn’t have any bad effect that I know of, but they’re gone now.

• I set the floating point mode for code generation to “fast” instead of “precise.” Not doing numerical analysis here. It doesn’t matter at all if some bits to the far right of the binary point are a little funny.

• In FAP, I changed instances like sqrt(x) < y to x < y * y. Multiplication is cheaper than square root. The VS2013 optimizer may do the strength reduction for me, especially with “fast” floating point, and I’m pretty sure the more powerful VS2017 optimizer does. Anyway, the code seems just as clear to me, so it’s no loss.

Steamhammer 2.3 uploaded

I’ve uploaded Steamhammer 2.3, including Randomhammer. The previous uploaded version was 2.1.4, the tournament version online since December; version 2.0 played in AIST S2 and I did not upload it to SSCAIT because “it would just be a few days” while I fixed up terran and protoss. Famous last words.

For this version I turned on 2 different debug options. It draws map info, which is mainly where the bases are and who it believes owns them (it says “mine” or “yours” on some bases). It overlays a red dumbell shape which points out the “front line” base where the main static defenses will go, and the point that it tries to center the defenses on; you get to see how wrong it is. I also turned on drawing of reserved building tiles in dim gray. Some tiles around the minerals and gas are permanently reserved so that no buildings interfere with mining. Otherwise, tiles are intended to be temporarily reserved until a building goes there. Rarely, a bug causes causes a building to be canceled without unreserving its tiles, wasting the space.

I’m expecting zerg to be modestly stronger because of bug fixes, and terran and protoss to be significantly stronger. Once the elo numbers start to settle, I expect to see Randomhammer moving up.

Stay tuned for the change list and stuff.