Skip to content

Release 2.0

Compare
Choose a tag to compare
@kant2002 kant2002 released this 15 Jan 04:45
· 12 commits to master since this release

Code changes

  • More stuff in UnitUtil: Cooldown and FramesToReachAttackRange() functions added, and used in micro. GetWeapon() functions reworked for simplicity. Damage-per-frame functions added to compare weapon strengths. IsCompletedResourceDepot() added, factoring out code that was repeated in several places.
  • UnitInfo::estimateHealth() estimates the health of a unit which may not been seen for a while, accounting for protoss shield regeneration and zerg hp regeneration. (Terran medic healing and SCV repair are not easy to predict.)
  • InformationManager::enemyHasSiegeMode() added, and used in tactical calculations.
  • In GameCommander, I sorted the manager calls so that managers which gather information are called first, and managers which use the information are called later. They had gotten jumbled over time. The main effect is that Steamhammer reacts 1 frame faster after discovering the race of a random opponent, a crucial difference that I estimate will, over Steamhammer’s lifetime, save approximately zero games.
  • I renamed SquadData::addSquad() to createSquad(), since that’s what it does, and reworked it for simplicity. I removed the declaration of SquadData::clearSquad(), which was not implemented.
  • Some calls in WorkerManager iterate through bases instead of through units to find base-related information. It’s faster and simpler (but I did have to spend time to fix a bug that I introduced in the process).
  • More unnecessary includes removed, bringing a negligible improvement in compile times.
  • I removed the configuration option Config::Micro::UnitNearEnemyRadius. The value is now chosen dynamically in code.
  • In the game info display (turned on with Config::Debug::DrawGameInfo and drawn in the upper left), most labels were not needed because the meaning is obvious. I removed the labels of items other than “Opp Plan”. Less clutter is better.
  • The TimerManager display, turned on with Config::Debug::DrawModuleTimers, had grown disorganized and probably incorrect. I straightened it out. I also improved comments in the code to prevent future disorganization.

opponent model

The opponent model has always distinguished between opponents that appear to follow the same plan every game, and opponents that vary their play. Until this version, it used the information only in a minor way. Now it selects openings using an entirely different method for multi-strategy enemies. If you play the same every game, Steamhammer will try to find the best single response, exploiting your predictability. If you mix up your play to confuse Steamhammer, then Steamhammer will mix up its play to confuse you; you get minimal predictability to exploit. We’ll see how well it works, but I’m expecting it to make a big difference in a long tournament like AIIDE.

  • Against a single-strategy opponent, Steamhammer sticks with the variant of epsilon-greedy that it has always used: With probability epsilon, explore randomly; otherwise, choose the best known opening according to a weighted win rate that tries to take the maps into account. It’s not strictly classic epsilon-greedy, though, because epsilon varies according to the loss rate: If we are losing a lot, explore more often and play the best known opening less often. (It’s an adaptation to having more openings available than can be tried.) I have modified it so that the exploration rate increases more rapidly with the loss rate, because I found it was too often repeating an opening that won 1 game out of many, instead of looking for a better choice.
  • Against a multi-strategy opponent, Steamhammer starts with the same weighted-win-rate calculation that it uses in the single-strategy case. Each opening it has already played is an option, and has a measured win rate. Exploring a new opening is an option, and its win rate is the mean win rate of openings that have been tried, its best estimate of how likely a newly explored opening is to win—but with a hard floor, so that the exploration rate never goes too close to zero. It randomly chooses among the possibilities, giving each a probability proportional to the square of its win rate. Squaring the rates gives openings with win rates near zero little chance of being chosen—unless most openings have win rates near zero. If all win rates are zero, because there are no wins yet, the hard floor on exploration means that Steamhammer explores every time. If the win rates are high for some openings and low for many others, exploration will be rare and Steamhammer will most often randomly choose one of the better openings. It’s ad hoc but makes a certain amount of sense.

macro

  • Mineral locking. Steamhammer’s implementation follows Locutus in outline, but is different in detail. Mineral locking helps mainly in macro games, which Steamhammer is now able to play better because of the squad changes, so this was an opportune time to add it.

construction

  • Prefer to expand to bases near the edge of the map. Bases near the edge are usually (not always) more protected than bases near the center of the map. In practice, Steamhammer now mostly avoids taking the risky center bases on Heartbreak Ridge and other maps, and the exposed mineral only bases on Python, at least until later in the game. I had to tune it carefully so that the natural of the 1 o’clock base on Tau Cross, far from the edge, is still preferred over the exposed 3rd base at the edge. Someday I’ll implement map analysis and figure out a real measure of exposure to attack.
  • Bug fix: Don’t try to build at a location which a worker cannot reach. It never happened, as far as I know, but there was a mistake in the code.

tactics

  • In the overview I said that workers are not transferred to base that is in danger, but there is more to it than that. Each base keeps track of whether it is being attacked severely enough that workers appear to be in danger; the estimate is made by CombatCommander::updateBaseDefenseSquads(), which I wrote about under base defense, and can be accessed via the Base objects for each base with base->inWorkerDanger(). If a worker is idle, meaning it is due to be assigned a new task if one is available, then it is not assigned a task at a base where workers are in danger. A worker is normally made idle after completing any task: worker was just created, gas collection is being turned off so worker no longer needs to mine gas, worker is finished defending itself and should be put back to work, and other cases. Workers are not only not transferred to an endangered base, they are often (not always) transferred away from the endangered base because they had to defend themselves, or were pulled for defense, or otherwise changed tasks. It’s hardly perfect, but it saves workers and greatly improves Steamhammer’s resilience to attack. It was a critical improvement. Related weaknesses remain: Steamhammer may still try to build at the endangered base, or transfer drones to a distant base through the enemy army.
  • Fixed CombatCommander bugs in deciding which enemy base to attack.
  • Rules for recognizing enemy cloaking and assigning detectors to our squads are slightly improved. Steamhammer pays attention to whether it has cloaked units itself and needs to catch enemy observers. This allows overlords to stay safer in some game situations: We don’t have lurkers, therefore we don’t have a strong need to hunt observers, therefore overlords can stay home.
  • In feeding units to the combat sim, an enemy building which was last seen uncompleted is entered as completed if is currently out of sight. It is sometimes an improvement, sometimes a mistake. It would be better to track the estimated completion time and use that (a number of bots do).

micro

  • Previous versions changed former stateless module Micro into an object with state, but did nothing new. This version updates the state with each of our unit’s orders and a little more information, but still doesn’t use the state for anything. It’s all prepared for serious work, though.
  • Enemy unit movement prediction is smarter. It takes distance into account. Also, prediction is used differently in different cases to get better results in practical situations. Mutalisks, wraiths, and vultures now use prediction; as instant-acceleration units they are kited by a different routine than other units, which didn’t use prediction until now.
  • Kite only units which the enemy has targeted. If nobody wants to shoot you, you don’t have to step back from the shooting. This especially helps hydralisks, which fire more slowly when kited and tend to get in each other’s way.
  • Some bits of micro explicitly take latency into account in their calculations, especially kiting. It’s more accurate.
  • Don’t chase an enemy if we’re predicted to be unable to catch it. CanCatchUnit() (defined in Common.cpp) figures it out. It makes less difference than I expected.
  • Targeting priority: A ghost which is nuking is the highest priority target. An enemy defiler is also a high priority. These two were oversights. There are other targeting tweaks, for example to reduce cases of attacking the pylon when the cannon behind it is firing; it’s not fully successful.

zerg

  • If we are short of mutas or lurkers (by a simple hardcoded count), then do not substitute a drone for a muta or lurker, no matter how much we may want drones. This was the biggest cause of delayed tech switches, and fixing it makes strategic play crisper at key times. This was one of the most important fixes in version 2.0.
  • Late in the game, add extractors willy-nilly everywhere that they are possible. Steamhammer was too often gas-starved in the late game, too slow to get more gas when it was needed. This is also an important fix.
  • Limit scourge more stringently. Sometimes Steamhammer makes so much scourge that it has no gas for anything else, causing macro problems as it delays production to get more gas.
  • The building manager is much more cautious about turning a failed expansion into a macro hatchery. It only orders the change if it appears that we actually need a macro hatchery.
  • Build a queen’s nest sooner in some situations. This is to speed hive tech when it is needed. It doesn’t make a big difference.
  • If the enemy has too many corsairs or valkyries, get air carapace. This gets air armor for overlords even if we are not making any other air units.
  • Favor guardians more, especially versus mass cannons. Past Steamhammer versions reduced guardian use by too much, and this starts to correct it.
  • Emergency reaction: If we’re dangerously short on drones, don’t spend one on a building. Oops.
  • Emergency reaction: If we have no bases but do have hatcheries, then make sure that the drone limit is at least 3. Having “no bases” means that no hatchery is at a predefined base location; we might still have hatcheries that can mine. Steamhammer formerly thought that, without bases, it had no need for drones. That was OK if it had drones already, not if they were all dead. Now Steamhammer has a chance to recover, provided the enemy is also prostrate after a base trade.
  • Don’t automatically make a sunken in reaction to a proxy. It was often an overreaction.
  • Don’t automatically get an early sunken versus protoss 2 gate (the sunken was usually too early) or against zerg 2 hatch (it was often unnecessary).
  • When planning a morphed unit type (such as a lurker), don’t count it as using up a larva. This minor bookkeeping fix should occasionally make for better production decisions.
  • Cancel grossly excess overlords even in the opening book. This may help if an emergency situation comes up in the opening, but it is mainly meant to mitigate bugs which cause production loops. No simple production loops are possible, but there seem to still be some complex loops where unrelated emergency reactions fire, and each prevents the other from recognizing that it has already taken action. It’s rare, though.
  • Don’t let rebuilding the spawning pool cause a production jam, and don’t allow multiple copies of the spawning pool. It was a rare but deadly bug in production unjamming.
  • Fixed a crash if a hydralisk den, lair, or spire was dropped in the opening (in reaction to an emergency). It was that specific.
  • Fixed a rare bug that could prevent gas from being retaken after it was lost.
  • Fixed a bug in defensive reactions that could request zerglings when there was no spawning pool.
  • Fixed an unimportant bug in deciding to make a hive. It had no real consequences.

zerg openings

  • Fixed a number of openings that had suffered bit decay: They were broken or mistuned due to code changes, such as queue reordering and mineral locking.
  • Added new turtle openings designed to exploit particular enemy strategies: 11HatchTurtleHydra, 11HatchTurtleLurker, 12HatchTurtle, ZvZ_OverpoolTurtle. These are meant to stop specific rushes and leave Steamhammer in a sound position.
  • Finished up and optimized the anti-forge-expand macro openings ZvP_3BaseSpire+Den (a good success) and 4HatchBeforeGas (not as effective). Steamhammer is finally able to play macro games well, so this was important. To play these openings truly well, though, Steamhammer needs greater ability to understand and react to the enemy’s timings.
  • I fiddled with opening probabilities, mainly to continue to make openings more equally likely so that the opponent model can explore more efficiently. But also to include the new openings and to adjust to Steamhammer’s new strengths and weaknesses.
  • I split the opening 9PoolSpeed into 2 variants. One variant keeps the same name and makes fewer zerglings (hit them by surprise, then transition to a normal game), the other is called 9PoolSpeedAllIn and makes more zerglings (hit them hard and maintain pressure). Both are more effective in their ways than the former compromise opening.
  • A few ZvZ openings make 1 drone fewer, to keep zergling numbers as high as possible.
  • Some other changes.