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.