Skip to content

Releases: kant2002/steamhammer

Release 3.5.10

08 Dec 12:27
Compare
Choose a tag to compare

Tournament preparation

  • Special preparation against 9 prospective AIIDE 2021 opponents—the ones it might make a difference against, plus Stardust where Steamhammer is at risk of scoring zero. I followed the same preparation plan as last year: For each opponent, choose a small number of builds that have historically won, or that seem to have good chances, and enter them into history as fictional single winning games. Let learning do the rest.

It amounts to giving hints “try this a few times before giving it up.” Steamhammer has a better chance of finding good builds early, and is not weighed down with masses of outdated learning data if the opponent brings surprises.

Information

  • Remember whether the enemy has used psionic storm this game. I wanted to feed the information into lurker spacing decisions, but ended up not implementing lurker spacing, so the feature is unused for now. There are other potential uses.

Static defense

Changes to static defense include tuning to make the right amount in different situations—zerg static defense is expensive, and needs to be worth it. I think the tuning is improved versus terran, fairly good versus protoss, and still weak versus zerg.

  • Fixed a crash due to division by zero. The bug fix does not affect strength, because the crash only happened when Steamhammer had no bases left. Yes, it was dividing by the number of bases. How easy it is to forget that you may already be dead! For my part, I forget that nearly every day.

  • Morph forgotten creep colonies into sunkens or spores, if and when they happen to be needed. The building manager sometimes slips up and forgets to morph a creep colony that was intended to become static defense. If defense is not needed, it will remain a creep for the time being. When the static defense planner decides that it is needed, it may turn into either a sunken or a spore. At some point I’ll implement tactical analysis and Steamhammer will have an idea of when the enemy might attack in strength. Then it will be able to leave all colonies until they are needed.

  • Try to place spore colonies in the mineral line, rather than somewhere vaguely near the hatchery. This helps ZvZ the most.

  • Make one sunken colony less per base, compared to before.

  • If the enemy has many tanks with siege mode, sharply limit the number of sunkens. They become a waste of minerals.

  • Make more spores versus mass wraiths and mass scouts.

Buildings

  • Anti-cannon sunken reaction failed due to errors in building placement introduced in a recent version. Fixed.

  • Other attempted improvements to anti-cannon sunken placement.

  • Added configuration option Config::Skills::UseSunkenRangeBug so that I can turn the feature off when it’s not allowed. It’s part of building placement; see BuildingPlacer::getAntiCannonSunkenPosition(). It’s off for AIIDE, where use of the bug is not allowed. It’s on for SCHNAIL, since it’s allowed in human games.

  • Steamhammer might try to build a macro hatchery directly on top of the main hatchery in the opening. The hatchery failed to build and the drone assigned to build it was left idle for a time, a serious breakdown. Fixed.

  • In rare cases, a building might be placed invalidly so that it could not be built. Fixed.

Squad orders

  • Each squad keeps track of the last time its order was changed to a different target. It also remembers the most recent frame that any cluster of the squad attacked, and the most recent frame of a retreat. (“Attack” usually means that the combat sim said “go attack”, not that any unit fired a shot.)

  • The above info is used by the air squad in deciding whether to keep attacking its current target, or seek an undefended target of opportunity. If the last attack was a long time ago and the last retreat was just now, then the mutas are sitting around and should try another target. They look for the closest undefended thing and try that instead. Unfortunately, the closest undefended target is often as inaccessible as the original target—it can be attacked in theory, but Steamhammer doesn’t have the smarts to do it in practice. So far, the feature is not worth the effort I put into it. I think it will become worth it when I implement more pathing and harassing skills.

  • In defense, defeat enemy proxy pylons when nothing more dangerous threatens. There was always code to do this, but it was broken in a subtle way. The method for assigning units to squads is too complicated; I’ve got to find a better idea.

  • In defense, count an enemy proxy creep colony as 2 units, not 1. When pulling drones to defeat the proxy before it can finish morphing into a sunken, Steamhammer will pull 4 drones and win the fight instead of 2 drones and lose. (3 drones would be ideal, if no other unit interferes.)

Recon squad

The Recon squad has been a valuable feature ever since I implemented it. But lately Steamhammer has become strong enough that Recon’s weaknesses are hurting. For example, classically the Recon squad only pays attention to units that it can see, ignoring the remembered positions of enemy units, because its purpose is to see what’s going on. But suppose the squad consists of 1 zergling and it wants to scout an area defended by a sieged tank. The ling approaches to see, gets splatted by the tank. Another ling is assigned, approaches, splatted, etc., until the target times out. The process is, as people say nowadays, unsustainable.

I made 3 changes. None is critical in itself, but together they make the Recon squad safer and more effective and count as an important improvement.

  • Combat sim attends to all enemy units, as for other squads, not only visible enemy units.

  • When the squad is restored after it has become empty (for any reason, not only losing all units to the enemy), reset its target to somewhere else.

  • Don’t assign the squad a target that is already in view. If the Watch squad or an overlord can see the target, the Recon squad doesn’t need to. As always, if no targets need scouting, disband the squad.

Irradiated squad

I improved the behavior of irradiated units, but it still doesn’t work as intended. I’m convinced that bugs are hidden somewhere in the infrastructure code, not in the top-level decision code.

  • The code was already clean, but I simplified it a little more.

  • An irradiated unit keeps farther away from its friends than before. This is the most important change, even though the old distance was already outside the irradiation splash range.

  • Flying units seek in a wider radius to find enemy units to splash radiation onto. Mutas are fast and may get there in time to do a little splashing.

  • A slight change to burrow decisions.

Scouting

  • Release the scout worker early in a few special cases: If there is an overlord nearby to continue the scouting work; if the scout runs into a completed enemy bunker or photon cannon. There are details to the conditions; for example, if no enemy unit type has been seen yet beyond those the enemy had at the start of the game, then the scout stays on the job. Steamhammer usually scouts early, and returning the scout is economically good. An enemy bunker or cannon (if not a proxy) means on the one hand that the scout cannot advance, and on the other that the enemy has no intention of attacking right away, so Steamhammer can return the scout now and wait for zerglings to arrive to keep watch.

Squad tactics

  • Don’t retreat forward if the enemy is near at all. The feature was meant to fix the case where one cluster of units is attacking the enemy, while a smaller cluster farther away was afraid to approach because it could not win on its own. But if an enemy was between the two clusters, which could happen despite a triangle-inequality test to try to prevent it, the cluster retreating forward would walk through the enemy and get shredded. Instead, a Regroup cluster close to an Attack cluster is itself changed to Attack in a second pass through the cluster status decisions before they are executed. The failure cases are non-horrible, and the change fixes one of Steamhammer’s biggest tactical weaknesses. At some point I’ll rewrite it so that clusters fighting the same enemies are treated together, not separately, but that’s for the future.

  • Enemy unit clustering is turned on, so that known enemy units are grouped into clusters just as Steamhammer’s units are. The config option Config::Debug::DrawClusters draws the enemy clusters in red circles to contrast with Steamhammer’s clusters in white circles. The enemy clusters are used in various decisions at the cluster and unit level.

  • An unhandled case led to poor lurker retreat decisions. I rewrote the code to simplify it and fix the bug.

  • When retreated all the way to the retreat point, lurkers burrow and tanks siege. Formerly, both remained ready to move, which meant that they were unready if the enemy advanced. It may not sound important, but it’s a big improvement. Indecision between advancing and retreating is common, which causes the familiar burrow/unburrow frenzy, but it’s a net gain by a wide margin.

  • When retreating, count a sieged tank or a burrowed lurker as immobile defense, an option to retreat toward. Formerly, Steamhammer only looked for static defense.

  • When seeking a cluster ahead to join this cluster with, use the squad’s order distance instead of the air distance. The order distance is the ground distance for ground clusters or the air distance for air clusters. This fixes some poor decisions made by ground units near terrain features.

  • The code to retreat behind static defense was rewritten to be correct for a change. The actual behavior doesn’t change much, though.

  • Be a little quicker to declare overlord danger at a base, so that new overlords are not spawned there to die usele...

Read more

Release 3.3.5

05 Feb 09:28
Compare
Choose a tag to compare

Production

  • The “build beside the base” bug (mentioned here) is fixed. It’s a damaging bug and the fix is critical, but the issue that learning hides bugs means that damage will be ongoing for a while yet.

  • Building manager can construct sunkens and spores when ordered, carrying out both steps itself. Formerly, laying down the creep colony, and then morphing it to a sunken or spore, were separate steps that had to be queued as two distinct items. Further, there was no connection between the queue items, so sometimes a creep colony intended to be a sunken instead became a spore, and vice versa. The change ensures that you get the static defense you ordered when and where you want it, and simplifies other code so that future features will be easier. The implementation is not perfect; a game against Stone shows that it can go wrong when the spawning pool is destroyed and has to be replaced.

  • Fixed a production bug that prevented research from being done in a hive or greater spire. The result was a production freeze, so this is a critical bug fix, though the bug was rare. When I updated to BWAPI 4.4.0 I ensured that research could be ordered in a hive or greater spire, as newly allowed by the BWAPI version, but since my mind is a steel trap I was not clever enough to verify that the research succeeds.

Scouting and information

  • A terran scan counts as mobile detection. For some decisions, like how useful it will be to make lurkers, having ever seen an enemy scan counts the same as having seen a science vessel or an observer—it means the enemy has the tech. (The question “does it look as though this location is in range of an enemy detector?” is different and was already answered in version 3.3. See UnitUtil::EnemyDetectorInRange(), which did not need any code change under BWAPI 4.4.0 to notice enemy scans.)

  • I was annoyed by games where Steamhammer’s drone scout was stopped by a bunker or cannons at the enemy’s front, and since it was unable to move forward, stuck there for the rest of its life as the game continued around it. Must scout—can’t scout—do nothing—die young after a wasted life. I added a rule to release the worker scout in that situation once friendly combat units arrive to keep an eye on the front. It will help the economy and my mood.

Overlords

  • Formerly, overlords not needed for any other purpose were assigned to wait at Steamhammer’s front defensive line, where the primary sunkens go if there are any. It turned out they were too vulnerable there; sometimes masses were shot down before they could escape. Now one overlord is assigned to the front line, and leftovers are sent to the current “main” base, where they are less available but safer. Occasionally the main base changes and they undertake a mass migration, but I haven’t seen it cause a problem.

  • Assign overlords to watch island bases, when it is safe and with a low priority.

Micro

  • MoveSafely() is smarter. Its purpose is to move a unit to its destination while avoiding enemy attacks. Now a moving unit in danger from enemy mobile attackers seeks nearby friendly units that can defend it—an air unit seeks anti-air defenders, while a ground unit seeks anti-ground defenders. It works by clustering all potential defending units, and looks for a cluster that it can reach. (Clustering is done centrally by the ops boss, on demand, and cached for the frame. A common case is that many overlords are independently moving safely, so that clustering is more efficient than seeking defenders unit by unit. It also provides more information for the decision, like how strong the cluster is.) If it doesn’t find defenders, or if it is in danger from a static building that can’t chase it, then it retains the old behavior of fleeing directly away from the attacker.

  • MoveSafely() has a safety margin. The margin is wider for a worker, and for a unit that has no regular attack (like a flying detector or a spellcaster). This is a big improvement that makes overlords safer. It has more effect in practice than the above change of seeking defenders. The reason there was no safety margin before is that I forgot it—I let myself be interrupted before I had entirely finished the feature. Concentration is important!

Zerg

  • A bug caused gas mining to go severely wrong in a small proportion of games, persistently mining gas when it needed minerals more, a weakness that I originally fixed in version 1.0. In one game, only 3 drones survived and all of them mined gas the rest of the game even as gas built up to 8000 and minerals were out. I didn’t pin the cause down 100%, but the only code that could have caused it was a check that said “hey, I have too many drones and some are idle, there’s no loss in mining gas whether I need it or not.” I commented out the check, which never worked quite as intended anyway, and I haven’t seen the bug since. The ultimate error is likely in the worker manager.

  • All-new spore building code fixes further spore placement bugs beyond what the building manager changes fix. It is rather a lot of code change for a small behavior change, but the new code is more general and modifiable and future improvements will be easier.

  • Limits on making sunkens and spores are slightly altered. Sunkens to protect against vultures and dark templar are possible minutely later in the game. It is a little more willing to add a spore despite already having a spire to defend with scourge.

  • The building placer is a tiny bit smarter about sunken placement to stop cannon rushes and bunker rushes. I don’t notice any practical improvement.

  • Steamhammer rarely had more than 1 queen on the map, though it is configured to keep up to 6 and often decided to make more than 1. Something is not right in the strategy boss. I switched it to make queens in batches, as resources allow, rather than one by one on each call “what should I make now?” Now it reaches as many as 2 queens on the map... there is still a bug somewhere. 2 queens are not an efficient number for broodling.

  • Minor updates to support multiple defilers. Formerly, Steamhammer never made more than 1 defiler at a time, in part because defiler micro is cpu intensive (it was much more cpu intensive before I fixed its original bugs). I noticed that some opponents were quick to target the defiler, and killed defilers reliably so that little defiling occurred. Making more defilers, currently 2 at a time, is my attempt at a quick fix. It may help, though from games so far I think not much.

There is a small update to the strategy boss, to order more defilers up to a limit. Also, if the enemy is nearly dead, don’t make more than 1 defiler; it won’t be useful. Trivial changes to the micro controller for defilers, MicroDefilers, slightly improve efficiency; it already supported multiple defilers.

  • Small adjustments to ZvZ counters in the strategy boss. Nobody will notice.

Configuration

  • Config::Debug::DrawDefenseClusters draws the air defense and ground defense clusters used by MoveSafely() to find defenders to flee toward. A unit that can shoot both air and ground will belong to both an air defense cluster and a ground defense cluster. Static defense buildings are included in the clusters, so that (for example) an overlord fleeing a corsair may take refuge with a spore colony.

  • Config::Skills::MaxDefilers is added. It’s currently set to 2.

Openings

  • Added 9PoolSpeedSpire.

  • Two related but different openings were named Over10HatchHydra. Oops. I renamed one of them to Over10HatchHydraB.

Release 3.3

05 Feb 09:24
Compare
Choose a tag to compare

BWAPI 4.4.0

  • Steamhammer is updated to BWAPI 4.4.0, at long last. In AIIDE this year, it was the only updated bot which still relied on the older BWAPI 4.1.2, now Positively Ancient by community consensus.

Part of the change is switching from VS2013 to VS2017. VS2017 has a more capable compiler backend with a stronger optimizer. Steamhammer’s DLL size fell from 1,211,392 bytes for version 3.2.20 to 1,100,800 bytes for 3.3, reflecting the difference in compiler, small changes in Steamhammer’s size, and any changes in the size of BWAPI.lib. That’s about a 9% improvement in object size for the effort of upgrading, surprisingly large. The bot presumably runs faster, but I didn’t measure it. Steamhammer already runs fast, so I doubt any speed improvement matters.

  • If the opponent is terran, Steamhammer now tracks enemy comsat scans. Call InformationManager::getEnemyScans() to fetch the current scans. BWAPI 4.4.0 makes enemy scans available, where BWAPI 4.1.2 did not.

Errors related to spell units

The spells comsat scan, disruption web, and dark swarm are represented in BWAPI by special units which belong to the player who casts them. Code that looks at units often has to know that. I searched through Steamhammer for code which did not know it, and found cases. Some were due to scans and only had to be fixed because of the 4.4.0 upgrade—it’s a subtlety for authors to be aware of.

  • An enemy scan does not imply that the enemy has air tech.

  • When deciding how many scourge are needed, don’t count enemy scans as air units.

  • In squad targeting, do not target scourge at an enemy scan.

  • In micro targeting (which is different from squad targeting), do not target enemy spell units.

  • When clearing neutral blocks (like blocking eggs that are part of the map), do not target neutral spell units. A small number of maps have permanent neutral dwebs or swarms.

  • In map analysis, don’t mark the areas covered by neutral spells as unwalkable.

  • Don’t try to include a spell unit in a squad. I think spell units didn’t get in anyway, but now they are cut off at the first validity check, so it is as safe as can be.

Zerg

  • Research in a hive. Until 4.4.0, a hive could perform no research due to a BWAPI bug. Steamhammer worked around it by getting all its research done before upgrading to hive, crimping its strategy choices. In hive rush openings, it was unable to research overlord speed ever, a serious issue. I’m so glad this is finally cured.

  • Research +3 air upgrades. Until 4.4.0, it was not possible to upgrade in a greater spire due to a BWAPI bug, and Steamhammer had a workaround to avoid +3 spire upgrades altogether.

  • Trivial bug fix: If Steamhammer lost its queen’s nest at any time after it started morphing its hive, but did not lose the hive, it was unable to replace the queen’s nest. Well, it rarely needed to, but it does have queen skills. The limitation is lifted.

  • Indiscernible bug fix: Prevent a production freeze that could have happened if Steamhammer wanted to research burrow, had no hatchery other than a lair or hive, and the lair or hive was busy researching something else. There was virtually no chance of this bug ever occurring.

Openings

  • No doubt under the influence of an Infernal Compulsion Engine (old tech now superseded by Electric Motives), I added the zerg openings 9Pool8Hatch and 9Pool9Hatch. Crona plays a related opening with success.

Release 3.2.19

05 Feb 09:19
Compare
Choose a tag to compare

Safe movement

  • Micro::MoveSafely() is a drop-in alternative to Micro::Move() for use by units which prefer to never come under enemy fire. It follows the simple method of running away from the nearest dangerous enemy, gaining 80% of the benefit of optimized hazard avoidance with 20% of the effort. If you know what to look for it’s easy to see cases where it makes a worse decision than potential fields would, but you have to look.

  • Overlords use MoveSafely(), except for squad detector overlords which already have their own way to avoid danger. Formerly, one of Steamhammer’s great weaknesses was that it would generously donate overlords to the enemy cause. Sometimes it would try to transfer an overlord to a distant base when an enemy army happened to be on the path, fail, try again.... In the worst cases, overlords would appear to converge from all sides on a group of marines or dragoons as if they were flying ultralisks closing a surround. That is all gone. Overlords are lost at a reasonable rate and live longer, more fruitful lives.

  • Workers also move safely using some of the same code, though the implementation is more involved than MoveSafely() because of the special needs of workers. Micro has a suite of helper functions. There is one exception: When moving to construct a building, just go there. The scout worker does rely on MoveSafely(), and it has become more adept at surviving to see what is going on. Overall, it’s a clear benefit. When zealots raid, the workers scatter and have to be chased down, at worst causing delay to the enemy and at best surviving to return to mining.

  • If burrow is researched, workers burrow to avoid danger instead of running away, unless an enemy detector is seen to be in range. This behavior is a delight to watch. Zealots raid, or a reaver lands—and the enemy sees nothing but puffs of dust as the workers disappear under the ground. After the attack is cleared, the workers pop up and instantly return to work. Steamhammer still loves to transfer workers across the middle of the map where the enemy is roaming, but now the workers realize the risk and burrow for safety. The enemy may like to scan when it sees units burrow (Steamhammer terran does that), or may have an observer which was out of range when the workers burrowed but can be brought over, so it’s not entirely safe, but it’s a breakthrough compared to the former behavior of running willy-nilly into the grinder. Also if the enemy moves away a bit the workers may unburrow, try to continue, come too close again and reburrow—which is funny if nothing else.

Overall, safe movement is a huge gain. There is room to make it far better yet, but that will take incremental refinement over time. There are disadvantages in certain situations. For example, when there is only one base and it is raided, then the workers flee or burrow and there is no mining whatsoever to fuel production and defeat the attack. It might have been better to keep mining and accept the loss of workers. Terran could do something like send 1 wraith to each mineral line and stop all mining, and in fact I have seen Steamhammer lose in similar ways.

Scouting and overlord assignments

  • Every overlord is assigned a location to move to and stay at. These parts are unchanged: One overlord is under the control of the scout manager early in the game. Some overlords are assigned to squads to serve as detectors and provide vision. The remaining overlords belong to the Overlord squad. What is different is that the Overlord squad assigns a location to every overlord it controls. Formerly, the Overlord squad assigned locations to some overlords and left the remainder floating wherever they happened to be, which might be in the middle of the map. It was not efficient scouting, and it was not safe for the overlords (but it was easy and I got it done).

  • The Overlord squad has gained a general assignment system similar to (but simpler than) what I plan for the deferred Scout Boss. It lists useful overlord destinations in priority order, then assigns the closest available overlord to each destination in order. If there are leftover overlords, as there generally are by the middle of the game, the remainder are sent to the front line of the front base (both “front” ideas are detailed in sections below)—basically, they wait together in a clump near where the enemy is likely to try to attack. It’s a reasonable try because the overlords use MoveSafely() to flee dangers.

  • Early in the game, one overlord is assigned to survey the main base for hidden proxies. It uses the new function MapGrid::getLeastExploredNear() to repeatedly find what place inside the starting base has least recently been seen, and goes there. The result is that the overlord flies an irregular, adaptive, hard-to-predict and fairly efficient search pattern (and it takes literally 2 lines of code inside the Overlord squad thanks to the infrastructure). I was inspired to add this by a game versus Ecgberht where the terran built a hidden proxy factory in a far corner of the zerg base, a strategy that has earned it a lot of wins over Steamhammer. Typically Steamhammer has no idea that vultures are appearing in its base because of a proxy and fails to defend effectively, but in this game an overlord accidentally scouted the factory and Steamhammer crushed the proxy brutally. It was a short step to scout on purpose.

  • If the enemy has no mobile anti-air units (somewhat uncommon), then an overlord is assigned to watch the enemy natural. Further overlords are assigned to guard our bases against cloaked units, just as formerly. If the enemy has transport and does not have flying overlord hunters, the main base scouting pattern restarts to watch for drops. If the enemy still does not have mobile anti-air units (rare by the point there are enough overlords for it, but possible versus Stone, versus a persistent zealot rush, versus a zerg going zerglings, or very late in the game after the enemy’s army is wiped out) then overlords are assigned to watch every base on the map. As always, if there are flying overlord hunters then overlords congregate at spore colonies instead. There is a lot of room to make strides in overlord deployment; future Steamhammer versions will do things like find overlord perches where they can watch without being seen.

  • The scout manager also controls its overlord somewhat differently. If an enemy turret, cannon, or spore colony appears in range of the overlord (generally when it is in the enemy base), then the overlord is immediately released from scouting duty. It is reassigned either to a combat squad or to the Overlord squad, and in either case attempts to safely make its way to a new destination. (I wanted to have it cruise around the edge of the enemy base to keep scouting, but it was too much for now.) Releasing the overlord loses scouting information, but losing the first overlord this early in the game is a severe setback and it was happening too often, so I think it’s the correct trade. If the overlord remains safe in the enemy base, however, it no longer sits still over the enemy resource depot but instead scouts the enemy base in a * pattern: It goes to the depot, then calls MapGrid::getLeastExploredNear() to find another place in the enemy base that it needs to look at, then returns to the depot, etc. That way it regularly revisits the most important spot, but also pokes into the corners of the enemy base so that it sees more.

  • Squad overlords, or properly squad detectors since science vessels and observers are handled the same way, are also controlled slightly differently. The flying squad detectors have long had abilities to avoid dangers and seek out cloaked enemies, and they could try to protect themselves from air attackers by seeking friendly units that can shoot air. Now, rounding out their skills, they also try to protect themselves from ground attackers by seeking friendly units that can shoot ground. We’ll see how well it works!

Building construction

  • Critical bug fix: It was possible for the building manager to accept a worker for a construction job while the worker manager believed that the worker was still available for other tasks. Ouchies. The worker was alternately given conflicting commands and achieved nothing. The building it was supposed to construct was hugely delayed or canceled, a game-risking error.

  • When choosing a hatchery to morph into a lair, if possible choose a hatchery that is away from enemy units. For example, if there is a scout circling the main, start the lair in the natural where it won’t be seen right away. I wanted this to be a first step in denying and delaying information to the enemy. I wanted to also place other tech buildings out of enemy view when possible and safe (they’re constructed rather than morphed so it takes different code), but I didn’t have time. I did add UnitUtil::IsTechBuildingType() so that Steamhammer can distinguish tech buildings from other buildings (to also eventually be used in prioritizing buildings to destroy in an enemy base).

  • Bug fix: When a worker was handed over to production manager or building manager to construct a building, for 1 frame it would be given 2 inconsistent commands, one from worker manager before the reassignment and one from the production manager (to move into position) or building manager (to start construction) after reassignment. I solved it by the simple expedient of running the production manager and building manager before the worker manager, being careful to comment the change so it is not later undone by mistake. The result is that the worker is able to follow its movement or construction command one frame earlier, so the building starts sooner by one Planck time.

  • The production manager replaced a worker requisitioned for construction if the worker was locked down, stasised, or maelstrommed before it could be handed off to the b...

Read more

Release 3.1

04 Sep 06:09
Compare
Choose a tag to compare

Expansion order

  • Take bases in a better order. Reading the code that chooses the next expansion showed me a few gross bugs, which I fixed. I also adjusted values to be a little less wrong. It’s still none too smart; for example, it doesn’t understand that zerg base order versus terran should be much different than versus protoss. The worst remaining problem, though, is caused by a bug in the building manager: When workers repeatedly die before reaching the building site, the building manager may cancel the building without unreserving the tiles, so that the base can never be taken for the rest of the game. That’s bad, but I intentionally left it unfixed for now because some of the bug’s effects are good. If you repeatedly fail at taking a base, then, well, maybe you shouldn’t try to take that base. Steamhammer’s base-taking behavior becomes adaptive. I don’t want to fix the bug until I can provide that adaptivity on purpose rather than by mistake. Failing to expand to the same unsafe base over and over is not a winning plan.

  • I added a debug option to the configuration file, DrawExpoScores, which draws Steamhammer’s idea of the value of taking each base. It’s generally a positive number for bases near Steamhammer’s main and a negative number elsewhere on the map (which doesn’t matter, it simply picks the highest value). If the base cannot be taken, it draws the reason instead.

Micro

  • Ranged units give higher priority to targeting tanks. This was inspired by games in which Steamhammer’s hydralisks saw a factory with a tank on the other side, and decided to shoot at... the factory.

  • Bug fix: A worker that had just mined out a mineral block might go idle. When it happened, the worker not only wasted its life doing nothing for the rest of the game (not even watching cat videos), it also blocked the path that it had been given the task of clearing. Now that’s some powerful laziness!

Terran

The terran changes are related to repair of buildings and to lifting of buildings.

  • Bug fix: It understands that it can’t repair a building which is not completed. I believe the effect of this aboriginal bug in the code is that an SCV is assigned to repair, can’t start because the building is not repairable, and gets reassigned the next frame. I didn’t verify it, but it must slow down mining.

  • Mass-repair a bunker or turret. The response time is slow, so it doesn’t work as well as it should. A simplified calculation makes a rough guess at the right number of SCVs to assign (it does get the correct answer in the case of repairing a bunker under attack from dragoons).

  • It can repair multiple buildings at once. The original code, inherited from UAlbertaBot and little changed until now, could repair one building at a time. For buildings other than bunkers and turrets, it assigns one SCV each. Only a fixed proportion of the total SCV force is allowed to repair at a given time, so that mining is not impeded too much.

  • It repairs buildings other than bunkers and turrets only after they fall to half health. If it’s only a hurt a little, it’s not worth it. Mining is the priority.

  • In a build order, the command "go lift [terran building type]" lifts all buildings of that type which are able to lift. For example, "go lift engineering bay" lifts all engineering bays that can lift. If a building is producing a unit or researching, it is not able to lift and ignores the command.

I originally wrote up lifting while working on the scout boss. Since the scout boss is deferred, there is currently no code to tell the lifted building to do anything. It can’t land and it doesn’t move, it just floats in place. Lifting is limited, but it does free room in the base for other buildings.

  • The strategy manager automatically lifts any barracks and engineering bays when the opening is complete and the build calls for factory production only. So you should rarely need to use the lift command in a build.

Zerg

  • In build orders in the config file, some upgrades used to require the race name, like "zerg flyer attacks". That still works, but now if you prefer you can leave out the race and write only "flyer attacks". It was a missing case in the parser.

  • Build sunkens at outlying bases to provide some defense against vulture raids, sneaky dark templar, and small drops. If Steamhammer suspects that one of those specific things may be coming, it builds a single sunken colony at each base that it expects may be in danger—for drops, that means every base, while for ground raids it skips the sunken at main bases in the hope that a sunken at the natural will be enough. The aim is to add the minimum of static defense. ZvZ is not affected. I expect this to be most effective against terran vulture raids, reducing drone losses and giving the zerg main army time to react.

  • Against valkyries or corsairs, get air armor a little earlier. It will help for the rest of the game.

  • If we have gas-heavy hive tech, make extractors more freely. I keep telling Steamhammer, “Hey, this is late game already, what’s the holdup? Why haven’t you taken gas at every base?” Somehow I can never accelerate the late-game extractors enough.

Release 3.0.2

04 Sep 06:03
Compare
Choose a tag to compare

Skill kit

  • The skill kit makes it possible to extend the opponent model with any kind of game data, so that in principle Steamhammer can adapt any aspect of its play to the opponent based on experience. To implement a new skill under the skill kit, write a subclass of the abstract class Skill. You need to set a name for the subclass (_name) and implement methods enabled() (should the skill be loaded for this game?), update() (which may carry out the actual skill, or may only collect information), and putData() and getData() (write or parse your data for the game record). You also have to implement feasible() (check quickly, is it possible to execute the skill?), good() (is it a good idea to execute the skill?), and execute() (carry out the skill when feasible and good), but if you prefer you can let update() do all the work, just have feasible() return false, and supply trivial implementations for the others.

  • There is a new game record format that records modestly different information about each game, and includes skill kit data. Steamhammer can read records in the old format or the new format, so existing data can be kept.

  • The updated gas steal skill uses the skill kit and knows a lot more about Starcraft than the original gas steal skill.

  • There is a new enemy unit timing skill. All it does it record data.

  • Base ID numbers from the map analysis are now constant across games, so that the numbers can be stored in the opponent model and used to remember the initial base positions.

Proxy skills

  • Steamhammer now has basic proxy skills so that you can write a wide variety of proxy openings. There are new macro locations such as @ enemy natural and new things that you can do with macro locations, like send workers there ahead of time.

It is also possible to use the skill kit to write more sophisticated proxy openings which make dynamic decisions.

Production

  • Fixed: A bug caused distant buildings to start later than necessary because of an error in figuring out when to send the worker.

  • Improvements to the handling of production jams: Don’t declare a jam when we are out of resources. Don’t declare a jam when we are maxed on supply. Also, clearing a jam correctly resets the timer so we don’t loop on declaring production jams. The changes correct occasional minor problems, nothing serious.

  • If a worker sent to build gets locked down or maelstromed, we immediately assign a new worker. For some reason, Steamhammer used to assign new workers only for stasis.

  • If we’re protoss, and we’re constructing a building with a worker from the same base as the building, it’s OK to assign a worker that is carrying minerals or gas. It will barely delay our income. Terran and zerg continue to insist on builders with empty hands.

  • Some production code is slightly simplified.

Other infrastructure

  • Mine out blocking minerals on maps that have blocking mineral patches. In the SSCAIT map set, that is Destination and Heartbreak Ridge. WorkerManager sends a worker to mine out the minerals once there are 2 bases and at least 18 workers total. The implementation is not complete and works only for mineral patches with 0 minerals; it doesn’t work on maps where blocking minerals actually contain minerals (mostly quite old maps).

  • Resource tracking: Keep track of the remaining minerals and gas on the map, as information allows. Since writing those two posts, I extended the code to also keep track of whether a mineral patch is mined out; formerly, the code could not tell the difference between a 0 amount mineral patch and a mineral patch that no longer existed (it’s used in mining out blocking minerals).

  • Decide on the value of taking a base, possibly a base that is partially mined out, based in part on the remaining count of mineral patches and the remaining total resources. To get this tuned right I had to retune other aspects of expansion decisions too, or else it would take center bases too soon.

  • The internal The system to simplify information access is extensively reworked and lets you reach much more information.

  • Maintain global unit counts every frame. I removed the old UnitUtil::GetAllUnitCount() and UnitUtil::GetCompletedUnitCount() calls. The information is used so often that it’s better to compute the numbers once and for all each frame.

  • Infer the existence of enemy buildings that we haven’t seen if the buildings are prerequisites of things we have seen. When we see a dark templar, we know there is a templar archives, among other buildings.

  • Accurately predict enemy building completion times in the UnitInfo system that tracks enemy units. Steamhammer now knows when enemy static defense that it saw under construction will complete, and uses the information in combat simulation (it formerly used a gross approximation that sometimes caused misbehavior). The info is not yet used in recognizing the enemy plan, but it will be valuable when it is. The info also affects squad targeting sometimes.

  • A proxy enemy supply depot, engineering bay, or pylon by itself is not an emergency and doesn’t cause the enemy plan to be recognized as Proxy. Don’t overreact.

  • InformationManager::enemyGasTiming() remembers the time that the enemy first visibly used gas. For example, if we see a vulture, then we know there’s a factory, so we know that the enemy has spent some vespene. It’s one piece of data that goes into deciding whether to steal gas: It’s recorded in the new format game records, and the gas steal skill looks at the numbers from games with no gas steal to get an idea of the enemy’s usual behavior and decide whether stealing gas now will interfere with it.

  • A minor improvement to UnitUtil::EnemyDetectorInRange(), which tries to judge whether a cloaked unit of ours is detected by the enemy: Now it knows that a blinded detector can no longer detect.

  • I fixed a bug in InformationManager that could cause it to believe that a destroyed pylon existed for 1 extra frame, a bug with no detectable consequences. There should be a Rammstein song about that.

  • I removed the WorkerData::depots data structure and its updating code, which was not only unused, but unusable because it was incorrect. I also removed the MacroAct::_race value, which is redundant and was used only for error checks that have never failed in Steamhammer’s life and would be easy to debug if they did.

  • I removed various unnecessary includes.

Configuration

  • New macro location @ gas only makes it possible to take a gas-only base (with no minerals) on those rare maps that have them. The zerg strategy boss knows how to do this and will automatically do it sometimes. This is on top of the new macro locations for proxies.

  • I removed the macro location @ macro in favor of @ main, which so far means the same thing. Though I’m thinking of splitting them again in the next version, when they may no longer mean the same....

  • Added configuration option Config::Debug::DrawResourceAmounts which draws Steamhammer’s idea of the remaining minerals or gas in each mineral patch or geyser—the amount and, if it’s not current, the frame it was last observed. It’s turned on in the uploaded instance, so you’ll see it on the SSCAIT stream. Also Config::Debug::DrawTerrainHeights which draws a number for the terrain height at each tile, with doodad terrain levels in purple.

  • Changed the configuration option Config::Debug::DrawWorkerInfo to draw the worker’s job code on each worker and target lines to show where the worker is going. Formerly it drew the worker jobs in a column, which was hard to relate to the game situation. Updated Config::Debug::DrawStrategyBossInfo to add the target queen count to its display of information.

  • Renamed configuration option Config::Skills::AutoGasSteal to Config::Skills::GasSteal; it sets whether the gas steal skill is enabled. Renamed Config::Debug::DrawUnitTargetInfo to Config::Debug::DrawUnitTargets because it is shorter.

  • Removed configuration options Config::Debug::DrawResourceInfo which was confusing, Config::Skills::RandomGasStealRate which appears to have never been used by any fork, Config::Debug::DrawMouseCursorPosition which I don’t find value in, and Config::Debug::DrawBOSSStateInfo which is not very informative even when using BOSS.

Squads

  • Fixed reaver stuttering, which was caused by a bug. Reavers are slow enough without spending half their movement time stopped.

  • InformationManager::getNearbyForce() uses the predicted completion time for enemy buildings. This is how the info gets into combat sim.

  • The recon squad: Don’t form it before 6 minutes into the game. Formerly the squad was constituted whenever there were “enough” units, which could cause a zergling rush to be weakened by diverting some lings to reconnaissance.

  • The watch squad: Even if a watch squad zergling is the last zergling on the map, it will remain on station. Formerly, in an emergency it would rejoin the main army, where it did no good and no longer guarded its base from being taken by the enemy. More importantly, stay above ground when detected and endangered. IceBot dealt successfully with the burrowed zerglings: When the SCV could not start construction, it scanned and attacked. The zergling was forced to the surface but instantly reburrowed again and soon died. Oops.

  • Squad targeting in the cleanup phase of the game: Don’t send a squad after enemy units that the squad can’t attack. This prevents some cases of zerglings following a floating ebay and the like. There are advantages to following, but I hope this way Steamhammer will be less often distracted from finishing the game.

  • Be willing to pull workers a longer distance versus an enemy proxy than versus zerglings. Keeping the workers near their minerals saved many games against zergling attacks, but prevented the workers from engaging proxy buildings. That’s fixed.

  • I made cha...

Read more

Release 2.4.2

04 Sep 05:54
Compare
Choose a tag to compare

Configuration

  "Skills" :
  {
    "SCHNAILMeansHuman"       : true,
    "HumanOpponent"           : false,
    "SurrenderWhenHopeIsLost" : true,

    "ScoutHarassEnemy"   : false,
    "AutoGasSteal"       : true,
    "RandomGasStealRate" : 0.0,

    "Burrow"             : true,
    "MaxQueens"          : 1,
    "MaxInfestedTerrans" : 0
  },
  • The SurrenderWhenHopeIsLost, ScoutHarassEnemy, AutoGasSteal and RandomGasStealRate items are moved from the Strategy section to the Skills section of the configuration file.

  • An internal flag Config::Skills::UnderSCHNAIL is added. It does not appear in the configuration file but is set by code. It is true when Steamhammer detects SCHNAIL’s schnail.env file in the read directory. Code can use this to do something different when running under SCHNAIL; it may be useful someday.

  • A flag SCHNAILMeansHuman is added. If UnderSCHNAIL and SCHNAILMeansHuman are both true, then Steamhammer overrides the configured value of the HumanOpponent flag and sets it to true.

In other words, if you set SCHNAILMeansHuman to true, then whenever Steamhammer is running under SCHNAIL, it will assume that its opponent is a human. That should almost always be what you want. If it’s not what you want, you can turn off SCHNAILMeansHuman and set the HumanOpponent flag by hand.

  • Steamhammer messages “gl hf” at the start of the game if it thinks the opponent is human. It actually wishes the human to have bad luck and suffer torment (BLAST), but it doesn’t mind lying. The real purpose of the message is so you can tell whether the HumanOpponent flag is turned on when it should be.

  • The game message was formerly messed up. I think I finally fixed it.

  • In the IO section of the config file, I separated Config::IO::PreparedDataDirectory (bwapi-data/AI/om/ for prepared opponent model files) from Config::IO::StaticDirectory (bwapi-data/AI/) for reasons of what I prefer to call clarity. The change doesn’t affect anything but a name in the code.

Release 2.4

04 Sep 05:51
Compare
Choose a tag to compare

The Killer Feature

The “Killer Feature,” which is no more deadly than your average killer app, is to burrow zerglings at bases that the opponent is likely to want to take soon. CherryPi did this a couple of years ago, and I was surprised that bots which know how to cope with spider mines laid to block base locations were often unprepared for burrowed zerglings doing the same thing. Two years later, bots which remain unprepared may get into trouble. Burrow has many many uses, and Steamhammer will take advantage of more of them in the future; in choosing a burrow skill, I am looking ahead. There are 3 parts to the system.

The strategy boss by default researches burrow after Steamhammer takes its third base. If the opening build takes three or more bases, it starts the research shortly after the opening. This is late enough in the game that the research is not a major expense, but it does lose the opportunity to exploit burrow early on.

The 9PoolHatchBurrow opening researches burrow much earlier. It is for use against opponents which may be vulnerable. 9PoolHatchBurrow is a variant of the Styx opening which collects 200 gas instead of 100 and researches burrow immediately after zergling speed, trading some of the zergling punch for the burrow ability. The two upgrades finish at almost the same time, because burrow (1200 frames) doesn’t take as long as speed (1500 frames). The aim is to get burrow early while pressuring with zerglings, and try to burrow a zergling in the enemy’s natural to delay or displace the expansion and mess up the enemy’s build. Burrow normally finishes before the enemy has scan or observers, so even an opponent which knows how to react may be delayed.

I tweaked the learning data so that this build will be given a try against a few opponents.

The Watch squads are for scouting and base denial. The design attempts to gain the most impact with the least investment. The combat commander creates from 0 to 4 Watch squads (depending on Steamhammer’s ground strength and other factors) of 1 zergling each, and assigns the squads to watch the bases closest by ground to the enemy main. It may also assign overlords to watch further bases, but usually by the time there are overlords to spare, it is not safe to assign them. A Watch squad behaves like any other squad, except that if a squad member finds itself at the order position and is able to burrow, it does. (It’s literally a few lines of code.) Once at least one zergling is under the ground, the combat commander attempts to keep the most important Watch squad on station despite any reverses, because to disband it would throw away the investment.

When Steamhammer decides to expand to a base, any Watch squad stationed there is disbanded immediately. The zergling unburrows and joins the ground army long before the drone trundles in to make the hatchery. The disbanding is 1 line of code in a condition in the combat commander, and the unburrowing and leaving is standard behavior that was written into the squad long ago. The whole Watch implementation is as simple as I could make it.

I’m eager to see how the Watch implementation works in practice. When Steamhammer faces a full range of opponents, the results of a new feature are always more complicated than I see in my testing.

Configuration

  • I added a new configuration section Skills which is intended to separate out some items from the long Strategy section. For now, it has Burrow, MaxQueens and MaxInfestedTerrans items. Later I’ll move some items over from Strategy.

For this SSCAIT, Burrow is true, MaxQueens is 1, and MaxInfestedTerrans is 0. The strategy boss is willing to make up to 2 queens, but I decided that the second one probably costs more than it is worth for now. Steamhammer has a bug in the production system that prevents it from making infested terrans, so it’s better not to try.

Infrastructure

  • UnitInfo keeps track of whether a terran building was lifted when it was last seen. For some reason I resisted doing this earlier, but it’s important information. The first use is in squad targeting, when checking whether an enemy building is a good target for a given squad.

  • Another use of the terran lifted building info is a new skill: If all known enemy buildings are lifted and all known enemy units are air units, Steamhammer will only include anti-air units in its unit mix. It sounds obvious, but ultra-ling is a potent way to finish off a zerg or protoss which has only air units left, and is only weak versus terran that has lifted buildings. This skill is intended to solve a rare difficulty in finishing off a terran—I have seen it happen in only 2 games.

  • Don’t try to expand to a base which is known to be blocked by an enemy building or burrowed unit. There’s no point in sending a drone to build on top of a spider mine which has been scouted. This also, of course, checks whether the building is lifted.

  • Efficiency fix: Use base->getTileDistance() precalculated ground distances in some places instead of recalculating the distances.

  • Config::Debug::DrawMapDistances now draws tile distances from its current main base rather than from its starting base. You can see what Steamhammer considers to be its current main base, which may change during the game.

  • I removed the unfinished and unused Region and Regions classes. I had forgotten they were there.

Zerg

  • Research Burrow, if enabled in the configuration, usually just after the third base is taken. The strategy boss will delay the research for some emergencies or if the economy doesn’t justify it.

  • The Watch squad scouts and denies bases. It is implemented for zerg only. Other races don’t have enough cheap units to dedicate some to sitting around, and are better off with the Recon squad alone.

  • A critical bug in upgrade checking could cause production freezes. Ouch. Fixed.

  • In ZvZ, get +1 melee attack instead of +1 ground carapace as the first ground upgrade. It’s cheaper, and it’s what humans usually do. I think the theory is that killing drones faster is more important than a small edge in resisting mutalisk bounce attacks.

Openings

  • The 9PoolHatchBurrow opening is added. See above.

  • Minor tweak to ZvP_3BaseSpire+Den. It gets 1 more drone.

Release 2.3.5

04 Sep 05:38
Compare
Choose a tag to compare

Opponent model

  • Support pre-learned data files. If Steamhammer does not find a learning file for a given opponent in the read directory, it looks next in a “static” directory to see if there is a data file for the opponent there. The config variable Config::IO::StaticDirectory points to the static directory, and is set to bwapi-data/AI/om/ in the release version (“om” stands for “opponent model”). After the game, it proceeds as usual: It writes the pre-learned game records, followed by the game record for the current game, into the write directory; after write is copied to read, there is no reason to refer back to the static directory. Locutus does it essentially the same way.

The AIIDE version of Steamhammer includes pre-learned opponent model files for 12 of the registered bots. Most of these files don’t have much in them beyond a few sample strategies that have won in the past, so that Steamhammer doesn’t have to cast about blindly to find a likely build. Best play against Iron is more complicated—Steamhammer knows 3 very different successful openings with varying win rates depending on the map—so the pre-learned file for Iron includes 50 games to give Steamhammer an excellent winning rate right from the start. All the game records were originally extracted from Steamhammer’s learning files on BASIL.

Operations

  • Squad targeting: In deciding what enemy base to attack, count defenders in a smaller radius, unless the enemy is terran and has siege mode (then we need the wide radius to include any tanks that may be sieged). This helps Steamhammer more accurately choose the least-defended enemy base to attack next.

  • There was a copy-paste error in the code to detect whether the enemy has siege mode. The siege mode information was returned correctly, but it mistakenly set the flag that means “the enemy has static air defense,” so Steamhammer would believe there were turrets whether there were or not.

  • Squad targeting: Don’t order a squad to attack an addon. I changed ranged units to never attack addons, to avoid wasting time when they should be attacking something else. (Melee units will, though, because it may be the closest thing.) That unexpectedly caused difficulties in finishing off games versus terran, when units might collect around an enemy addon and never attack it, rather than attacking a known building that was perhaps farther away.

  • Squad targeting: If no enemy buildings are known, seek enemy units which may still be findable. This can help Steamhammer finish off winning games faster.

  • A terrific bug caused enemy unit counts to be horribly wrong in many cases. Steamhammer sometimes believed that the enemy had a negative number of units of some type. The broken unit counts were not used by many decisions—the most important decisions use the player snapshot unit counts, which are accurate—but decisions that did use them could be completely wrong.

  • UnitInfo projects when enemy buildings will complete, based on their HP when last seen. It’s not entirely accurate; the calculation leaves out some factor that I haven’t figured out yet. To see the calculated times on the screen, turn on the config option Debug::DrawEnemyUnitInfo. In code, the call getEnemyBuildingTiming() is one way to get the information. This data could make plan recognition more accurate, but is not used for that yet; it is used only to check the enemy spire timing in ZvZ.

Tactics

  • Calculate map tiles in range of enemy static defense and keep the data available. There are separate grids of ground danger zones and air danger zones. A few uses of the data are implemented; many more are possible. Steamhammer will not place buildings in a ground danger zone; this is a vital skill to survive cannon rushes, and has saved games for Steamhammer against AIUR by Florian Richoux. The information also feeds into unit targeting decisions. Steamhammer’s units prefer to fight outside enemy static defense range when possible; Steamhammer has a stronger preference to pick off undefended targets.

  • Squad detectors avoid danger and seek cloaked enemies. Formerly, detectors stayed with their squads and otherwise ignored the world around them. Steamhammer lost overlords freely, a major weakness. Now they retreat out of range of enemies that could shoot them down, and move toward cloaked enemies that need to be detected. Science vessels and observers benefit too. It’s usually a big improvement, but there are cases where enemy ranged units zone out the overlords, or enemy cloaked units distract them from where they need to be. Overlords that are not acting as squad detectors (some act as base detectors and some are left idle) are as carefree as ever and can still be lost at a high rate.

  • A squad detector is supposed to move back home when it finds itself abandoned—when the squad it was detecting for is gone. I don’t think this feature works, or at least, detectors still make all sorts of illogical movements.

  • Better combat sim results against cloaked enemies. If all enemies in the area are undetected and they can hit us, retreat without further calculation. If some enemies are detected, do the sim to see whether to fight or run. The change makes play vastly stronger in certain situations.

  • FAP accounts for cost of scarabs and interceptors, and the full cost of zerg morphed stuff. It doesn’t make a big difference, but combat sim scores are a little more accurate.

  • Ranged units are better at ignoring enemy zerg larvas when moving somewhere else. They’ll get distracted less often.

Micro

  • Issue at most 1 move command per 3 frames in the micro system. Zerglings get stuck less often. I still see it happen from time to time, but I think most watchers will see zergling movement as smooth. The underlying code can send move commands to the micro system every frame if it likes, but the micro system will skip or delay some of the commands if they are too closely spaced.

  • MoveNear() had a potential crashing bug. It never happened as far as I saw, but a unit being given its first command ever could execute invalid code and crash.

  • Use MoveNear() rather than Move() in more cases, to reduce unnecessary commanding. MoveNear() ignores commands that “don’t make a difference”—it says, “eh, we’ll end up close enough, don’t bother.” It’s for use when precision doesn’t matter, which is a lot of the time.

  • Builder workers were being issued an unnecessary move command on the same frame that they were told to start construction. In the worst case, which was not frequent, building construction might be delayed by 1 frame. Still, it’s fixed.

  • Steamhammer’s melee units can be configured to retreat when low on health, to regenerate health (by zerg regeneration or terran medic healing or protoss shield regeneration). The change is, this no longer happens if the unit is irradiated. Net regeneration will not happen, and since it’s a melee unit it’s likely to be right next to the enemy, exposing enemies to the radiation. This mainly helps ultralisks.

  • Clip the result of DistanceAndDirection() to the map boundaries, instead of returning a bad result for the caller to deal with. In practice, the effect is that in some situations a unit will move to the edge of the map rather than not moving at all. I’m not sure it’s an improvement in play terms, but the code is safer.

Zerg defilers

  • An outrageous bug could put a defiler into both the defiler controller and the melee unit controller, meaning that defilers were issued zergling commands intermixed with their defiler commands. “Now AttackUnit() that building!” I was floored. The error was in code that was “so simple it could not have a bug,” and the bug was caught by an error check in the micro system, far away from the underlying problem. At least it was easy to fix.

  • Cast dark swarm over enemy ranged units, not only over enemy buildings. Formerly, Steamhammer could not use swarm against, say, marines on the open field; it had to reach the enemy base before the conditions for the spell were triggered. It was a severe limitation (justified by Steamhammer’s poor swarm skills at the time).

  • Choose the nearest zerglings as defiler food, not the first zerglings that happen to come up in looping through units. Defilers consume sooner and cast swarm and plague at a higher rate. A defiler generally arrives at the front line already charged up with energy, so even if it is irradiated instantly it is still likely to get a swarm or plague off.

  • A typo prevented research of Metasynaptic Node, the defiler energy upgrade. I fixed it and adjusted the conditions to be safer.

  • Slightly loosen the conditions for making a defiler in the first place. They work better now, make ‘em sooner.

• Swarm and plague scoring adjusted for better effect. The thresholds are reduced, so that the spells can be cast in more situations. Swarm over lurkers counts double. Plague counts more on carrier interceptors, less on buildings. Various other tweaks.

  • Fixed a bug in avoiding the overlap of dark swarms. Swarms less often overlap wastefully (though it still happens, for at least 3 reasons).

  • FAP bugs in understanding dark swarm are fixed (I added dark swarm to FAP, so all the bugs are my doing). There was an error in recognizing melee units that can hit under dark swarm because of a confusion between range and squared range (I renamed stuff and added comments to make it clearer). FAP also now realizes that a worker cannot do damage under dark swarm, while a reaver can. The effect of the fixes is that units under dark swarm make more accurate decisions about whether to keep attacking.

  • A rare bug could allow multiple defiler mounds.

Zerg scourge

  • Do not target an enemy that is covered by enemy static air defense. Steamhammer used to throw scourge away by the ton to cannons or turrets; this solves the issue. Scourge will chase the enemy, but turn around for...
Read more

Release 2.3

04 Sep 05:26
Compare
Choose a tag to compare

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...
Read more