archive by month
Skip to content

Steamhammer test version 1.4a1 uploaded

The annual rush of new bots is well underway. The latest is a batch of terran bots from the Charles III University of Madrid, none of which seems to be 100% working yet. One step at a time!

Meanwhile, Steamhammer has been unchanged on the server since September, a longer stretch than ever before. I have been working more slowly, but it has been a long time and I have done a lot in total. But mainly I delayed in order to release 1.4 with the promised opponent model, and yet I didn’t feel like working hard on the model.... And now the 20 December SSCAIT tournament deadline is threatening to wrap around my neck. I’ve made a ton of improvements, and it would be crazy to go into the tournament without a look to see what new bugs I’ve added too.

I’m still not sure exactly what will be in 1.4, but today I uploaded the test version Steamhammer 1.4a1. Why that version number? Because it’s inconsistent with the version numbering scheme I used before, and nothing could be more important than inconsistency!

This version has noticeably more complex and interesting play than the September Steamhammer. Most of the opponent model features are disabled; I expect to turn on more of them for the tournament version, because the gain can be big. But watch this version and you will see much improved scouting in the opening and middle game (to support the opponent model), somewhat smarter decisions from squads (to support the opponent model), better reactions to some kinds of rushes (as a result of the opponent model), and many tweaks to strategy (because it desperately needed them). On the stream, look in the upper left for the new “Opp Plan” line that tells Steamhammer’s inference of the opponent’s intention in the opening. It starts out as “Unknown” and often stays that way the entire game, but sometimes changes to “Fast rush” or “Heavy rush” or one of several other values. A few of the values can lead to dramatic strategy shifts, "Heavy rush" has only a subtle effect, and others are unimplemented and have no effect.

I’ll go into detail starting tomorrow.

igjbot

Zerg igjbot is new today on SSCAIT. It has been crashing a ton, but when it plays successfully it shows a thoughtful design.

Igjbot seems to follow the same plan every game. It opens with a standard 9 pool speed build that is safe against rushes and puts on early pressure (or kills weak opponents outright). It doesn’t follow up with heavy zerglings, but goes for a quick spire. An opponent that is too worried about the zerglings is at risk from the sudden air attack. But igjbot doesn’t press the air attack heavily, either. It adds to 3 hatcheries and switches back to mostly zergling production. The specific build order is efficient, at least early in the game (later on it collects more gas than it can use).

I thought igjbot’s most impressive game so far was versus Krasi0. Krasi0 did not seem ready for the fast mutalisks—it was still constructing its engineering bay when the first mutalisk arrived, and canceled it when the mutalisk attacked the unfinished building. As more mutalisks arrived, Krasi0 had to use all its defensive skill to put out the fires in its base and stay alive. Terran won, but had to struggle for it! In the picture, besides the burning buildings, notice the marks of canceled and destroyed buildings, and also the worker and army numbers.

Krasi0 frantically defends

For a brand new bot that wants to get by with 1 build against all races and opponents, I like igjbot’s game plan. It is safe against early aggression, it tends to force opponents into defense, and it tries to whipsaw the opponent with a tech switch and then a switch back. It’s not boring like another 5 pool bot. It’s a simple plan that is suitable for most situations and demands more from the opponent than from igjbot, and that’s perfect if you’re starting out and haven’t gotten far. Igjbot has micro weaknesses, no ability to expand, and other common problems, but those things take time and a new bot hasn’t had time yet. With smart strategy, it can still do fairly well.

Randomhammer’s marines versus protoss

This game Randomhammer-MegaBot 2017 is an example of why it’s not such a good idea to go marines versus protoss. Randomhammer still does it (15% of the time in the live version) because its other TvP strategies are also ineffective.

Stage 1: MegaBot went 2 gate zealots while Randomhammer answered with marines from 2 barracks. If MegaBot had been aggressive with the zealots it likely would have won early, because Randomhammer doesn’t understand early game marine-zealot micro and it lets the marines get hit far too often. But MegaBot did not press. In the picture, the larger zealot army is overcautiously retreating.

MegaBot retreats for no reason

Stage 2: Randomhammer got academy tech while MegaBot was still on zealots. The terran force had been dangerously small because of poor macro, but it was growing. Then the zealots took a bad engagement moving across a bridge in widely separated formation, and got wiped out. Stim is strong, and slow zealots are not the right unit to face marines and medics.

Randomhammer annihilates zealots

Stage 3: MegaBot got dragoons, which it should have done much earlier. Defending the ramp, a small number of dragoons was just able to hold the infantry force that had destroyed far more zealots. The better tactical situation (defending a choke instead of trying to pass through a choke) and better unit choice of dragoons versus marines made a huge difference.

MegaBot narrowly holds its ramp

Stage 4: MegaBot expanded and formed a mixed army of dragoons and zealots. Randomhammer built factories for tanks and also expanded but lost the command center to dragoons. It was partly due to more weak macro (gotta replace BOSS).

The game went on because MegaBot decided not to win on the spot, but morally Randomhammer was lost. In the end, though, MegaBot crashed. The game is also an example of the importance of reliability.

I chose the game to write up because of the stark contrasts between stages. The zealots seemed strong at first, then went poof after stim finished. A trickle of dragoons in the next stage was enough to turn it around again. The game would have been a better example if MegaBot had gotten reavers or storm and showed the infantry some real protoss devastation.

when the enemy unit is out of sight

If you have watched a game of Steamhammer versus Stone, then you have seen Steamhammer’s zerglings chase SCVs all over the map. The lings don’t seem to have the idea that they should find the enemy base and tackle the problem at its source.

if I don’t see you, you’re not there

If Stone’s base has been found, then the zergling squad actually does have orders to go to the enemy base. Why doesn’t it happen? The weakness is in micro targeting: When the squad chooses targets for each zergling to attack, it only considers visible targets. Against Stone, some SCVs are almost always visible and the base rarely is, so the zerglings become infinitely distractible and run hither and yon, chasing whatever pops into view. Eventually some zergling stumbles into the terran base and makes it visible, and then the squad is able to assign things in the base as targets.

The fix is, of course, to choose targets from a longer list that includes the enemy command center or mineral line, even if it hasn’t been scouted yet. I’ve been planning this fix for months, and it has never risen to the top of the list. Steamhammer beats Stone in the end, even if it looks silly doing it. But I can’t put it off too long, because the weakness does lose games against other opponents.

Another curious behavior you may have seen is that, if the zerglings are chasing an SCV that disappears up a ramp, they instantly lose interest and switch to chasing another target. The reason is the same: As soon as the SCV is out of sight, even for a moment, it is not a target. Steamhammer has object permanence and knows that the SCV is still there; it has a system (inherited from UAlbertaBot) which remembers the last known location of each enemy unit. But it can’t use its memory for micro targeting.

if I once saw you, you’re still there

Steamhammer does use its memory to feed the combat simulator with remembered units. If it runs into sieged tanks, it is important to remember them after we retreat out of sight range, so that we don’t immediately turn around and run back into tank fire. There is a curious flaw, though. Steamhammer uses the remembered location of an enemy unit even if it can see that location and the unit is not there! It only updates the location of a unit if it sees the unit again; seeing an empty spot where the unit used to be tells Steamhammer nothing. This is the cause of some strange retreat behavior, where the bot seems to shy away from invisible dangers.

This is, of course, also on my list to fix. I’m not sure what the fix should be. Sometimes shying away from invisible dangers is good, because the enemy units have not moved far. I may add an “it’s gone!” flag to the record for each remembered unit, if I can figure out how to update the flag efficiently (looping through every remembered unit or every visible tile each frame doesn’t feel like a good use of cycles). Then I’ll experiment. I might end up ignoring units which are gone, or using them if they’ve only been gone a short time. Or something.

For now, I added a flag to each squad “fight visible only”. If the flag is false, the squad behaves as now. If the flag is true, the squad does not include remembered enemies in the combat simulation, except enemy static defense, but only visible enemies. Setting the flag makes the squad bolder and more inquisitive; it will also run back into tank fire as soon as the tanks go out of vision. I think it’s suitable for scouting squads. The change is one of my improvements to scouting for the upcoming version.

early experience with Steamhammer’s new enemy opening plan recognition

I’ve been testing out Steamhammer’s new opening plan recognition to get a feel for it. I can summarize my findings in 2 points:

  1. Recognizing the enemy opening plan works pretty well.
  2. The reaction to the enemy’s plan is not easy to get right.

Right now, Steamhammer (development version) recognizes a half dozen different enemy opening plans. I’m likely to add or remove or switch around the recognized plans before release; it is still in an experimental state. The set of plans is not supposed to be exhaustive, because if Steamhammer’s usual behavior will do fine against some plan, then there is no need to recognize that plan. I may change my mind about that the next time I rewrite the strategy boss.

Plan recognition makes few mistakes of commission. I mean that, once it has decided what the enemy is doing, in my tests so far it seems to rarely change its mind (which it’s allowed to do as much as it wants) and rarely be wrong. On the other hand, it easily makes mistakes of omission, leaving the plan as Unknown because it doesn’t have enough information to draw a firm conclusion. I think it will take experience to learn whether that is a good tradeoff. I may want to relax conditions or add smarts.

Reacting to the enemy’s plan is a different story. So far, Steamhammer has a special reaction to worker rushes only, not to any of the remaining 5 possible enemy plans.

Opening plan recognition has 2 points. One point is that it will (it doesn’t yet, but this step is easy) tie into the opponent model, so that an opponent which usually follows the same plan will face openings intended to counter it. Stone, starting from the second game, will face Steamhammer’s anti-worker-rush opening. The other point is that, if the enemy plays unpredictably, Steamhammer will try to react when it recognizes the plan. PurpleWave and Tscmoo have been sometimes playing worker rushes that Steamhammer loses to, because the live version reacts poorly.

I think I have it working well now, pending more tests, but I found it hard to optimize and debug the worker rush reaction. Only zerg tries to react specially, for now. When Steamhammer recognizes the worker rush, it checks its build order to see whether it is playing an opening that does the right thing. That way, if it is already playing an anti-worker-rush opening or one that behaves similarly for the moment, it will keep calm and carry on. If the build order does something else, like make too many drones, then Steamhammer breaks out of the book opening and falls back on the strategy boss’s idea of what to do. And the strategy boss now has a special idea of what to do about worker rushes, starting from whatever situation Steamhammer finds itself in.

It’s a complicated arrangement, and it was hard to get right. Reactions to other plans will work differently, but even so I doubt I’ll have time to implement more than 1 or 2 more before the SSCAIT deadline on 20 December.

The game info in the upper left corner of the screen includes a line “Opp Plan” with the recognized enemy opening plan, so that stream watchers will be able follow along when the version goes live. It starts out as “Unknown” and changes if and when Steamhammer recognizes the plan. I think “Opp Plan” is a poor description, but I haven’t found a short string that is better (so if you have an idea...).

one way to draw scouting inferences

I wrote a couple posts ago about dissatisfaction with Steamhammer’s primitive way of inferring the enemy’s opening plan from scouting information. What is the right way to draw inferences from scouting? One kind is the hard inference or deduction from what you have seen, like “I saw the lair start, so the earliest mutalisks can be out is lair completion time + spire morphing time + mutalisk morphing time.” You can also draw soft inferences or likely guesses about what the opponent is planning, based on your knowledge of good play. “The opponent is blocking its ramp with a probe, I bet something cheesy is coming.” Maybe the opponent is incompetent and left a probe there by mistake, or maybe it is trying to fool you into scouting for a proxy gate, but cheese is likely.

Well, drawing soft inferences based on good play is beyond the state of the art for bots, because bots have little knowledge of good play. But there is a theoretically sound way to make every possible deduction from scouting information. It could even be useful, if you have a theoretical computer with infinite speed and memory.

It’s simple: Brute force it. There are only a finite number of build orders, and you can enumerate them. Cross out the build orders which are inconsistent with your scouting information, the ones where the enemy has fewer workers than you saw or doesn’t have an academy yet or whatever. Counting up the minerals mined places a particularly strong constraint. You’re left with a much smaller set of build orders that the enemy might be following. If you have a question like “what’s the earliest mutalisks could be out?” or “how many dragoons do I have to be ready for at time t?” then you look through the consistent build orders and find the one with the earliest mutalisks or the most dragoons.

The idea goes back to precomputing a catalog of build orders, which I wrote about in April 2016.

Can this theory be made practical? I think it can, by cutting it down and dropping the theoretical promise of finding guaranteed correct answers for all possible questions. Instead of all builds, keep a catalog of a small number good openings for each race, maybe between 10 and 50. Instead of exact build orders, you could store ranges of variation, like “second gateway between frames x and y,” or store preferred values and check goodness of fit—or some other simple abstraction. When you have enough scouting information, it will rule out most openings from your catalog, and goodness of fit may narrow it down further. Also, you know what questions you want to ask, so you can store the answers with each build, so that when you know what builds match what you see, there’s not much computing to do. Well, it’s a vague idea, but I hope you can make it out.

LetaBot uses, or formerly used, a related idea with a catalog of build orders. See LetaBot’s build order inference (also April 2016). A weakness of LetaBot’s approach at the time is that, when it saw something that the build order expected, it increased the score of that build order—but when it saw something outside the build order, it did not decrease the score. It might see 3 hatcheries and conclude that the opponent was following a one-hatchery build, because the extra hatcheries did not cause a mismatch. If LetaBot still uses this method, then I imagine it has been improved since then.

Next: Early experience with opening plan recognition.

an implausible game

Today’s game Randomhammer vs Flash is unbelievable. What I mean is, if I didn’t know that the replay was generated automatically by bots playing, I would assume that it was a setup. That should not happen!

Randomhammer rolled protoss and opened with 1 gate and dragoons. Flash put down 2 gates and made zealots, so of course Flash had more units. Randomhammer had an easy defense in principle: Make a fighting withdrawal with the dragoons, to buy time and to put some bruises on the zealots. When and if the zealots reach its base, Randomhammer should have enough dragoons to outmicro the zealots, and it can run probes if necessary.

Randomhammer has no understanding of any of that. The only withdrawal it knows is headlong retreat, and instead of running probes it fought with them. When the surviving zealots were finally driven off, only 2 probes survived. Furthermore, the 2 probes were collecting gas and had no ability to switch to mining minerals, so Randomhammer had zero income for the rest of the game. “Game over,” I thought. It was 6 Randomhammer dragoons, versus an opponent that was briefly behind in units, but now had its own dragoons and 2 running bases.

Randomhammer loses probes

As I expected, Flash soon rivaled Randomhammer’s army size. But I could hardly trust my eyes when I saw the fight. Flash had just started dragoon range, and could not cope without it! The 5 ranged dragoons (1 froze in the middle of the map) outmicroed Flash’s dragoons and remaining zealots by an extreme margin, with Flash rarely getting shots off. Randomhammer smacked down the army and a long stream of reinforcements which came in piecemeal.

a battle of nearly equal armies

Then Flash showed that it is every bit as careless with probes as Randomhammer, and instead of mining safely in the main and building up a ramp defense force while the natural was slowly flattened, kept transferring probes. Randomhammer finished the game with 4 dragoons, having lost only 2 against a much larger number of enemies. Not plausible, only true.

The next Steamhammer version will turn off gas collection for terran and protoss when there is reason to, as it always has for zerg. It’s a simple feature, and I think it will make a difference.

Next: The theoretical right way to analyze the enemy’s build.

recognizing the enemy’s opening plan

I’ve been adding recognition of the enemy’s opening plan to Steamhammer, as part of the opponent model. Besides making the opponent model smarter, the OpponentPlan is directly valuable to the strategy boss. I’ve been concentrating on enemy plans that the strategy boss is clumsy in reacting to.

After writing recognition code for several plans, I already felt dissatisfied with how it works. It looks at buildings and timings, it counts bases, it notices if zerglings are out suspiciously early, all extremely basic stuff. “2 barracks and no gas, I know what’s coming next.” There is no “You should have a second pylon by now, where is it hiding?” and no “I see more zerglings than you can get from 1 hatchery, you must have 2.” Rich and complex inferences can be drawn from the game information, and the primitive code I wrote draws only simple ones.

So I looked at PurpleWave, which does opening recognition under the name of “fingerprinting”. PurpleWave tries to recognize specific openings for zerg and protoss: This is 4 pool, this is 12 pool, this is 10 hatch, etc. And the way it works is, at heart, the same as what I wrote in Steamhammer. It is written in a different style, but it checks almost exactly the same information.

The biggest difference is that Steamhammer does not try to recognize specific opening builds. I think there are too many, and some of the differences don’t matter. The OpponentPlan groups enemy openings into categories, like “this is a fast rush,” without distinguishing between 5 pool and other early pools, or even between 5 pool and 5 barracks and 5 gateway. 2 barracks no gas gets the same plan label as 2 gateways no gas. If you want to react differently to 2 barracks than to 2 gateways, that is for the strategy boss to figure out. I think the plan categories extract more information from the game and compress it into fewer labels for the rest of the code to handle.

Well, if PurpleWave gets away with it then I guess the primitive recognizers are good enough for now. Someday I hope to write a cleverer plan recognizer that draws the deep inferences, that (like a pro) knows when you’re trying to hide a base and triggers a goal to go look for it. Or that says “You’re proxying something and I don’t know what, but I don’t need to see it because the answer is to build turrets.”

SSCAIT Report 58

I just realized: The SSCAIT Report 57 broadcast came out on Sunday as usual, then Report 58 came out only 2 days later, not waiting until the next week. It’s about terran versus terran.

when do the first zerglings hatch?

I collected data to calibrate openings so that Steamhammer’s opponent model can make more sense of the opponent’s opening. I thought some of the data might be of interest.

Here are the frame times at which Steamhammer’s first zerglings hatched with different spawning pool timings. These were all measured on Heartbreak Ridge, since the numbers vary depending on the layout of minerals on each map. Also the numbers vary somewhat from game to game, but it’s close enough. Steamhammer has wasted movement, so optimal timing is probably a touch faster.

poolframes
4 pool2630
5 pool2750
6 pool2920
7 pool cutting drones2990
7 pool going to 9 drones3120
8 pool3160
9 pool3230

Making a spawning pool on 7 leaves you with 6 drones. It’s possible to make 3 drones and an overlord before the zerglings, but the lings have to wait for the overlord and are slightly delayed. Instead, you can cut 1, 2, or all 3 drones and get that many pairs of zerglings before the overlord, saving a sliver of time. It’s an interesting tradeoff.

I like that there is a nice spread in the timings. It seems as though each of these builds might have some use, depending on what you think your opponent’s timings are and on how you plan to follow up.

untraceable Steamhammer crash

Steamhammer has had its first crash loss on SSCAIT since May. Or it may have overstepped the time limit. Randomhammer protoss has sometimes broken the time limit, but this is the first for zerg in a long time.

The game is Steamhammer-UPStarcraftAI 2016 (a zerg rushbot), and it looked like a routine Steamhammer win until 5:19 in, when suddenly bam, the 0/0 supply that means crash. Steamhammer has won dozens of these rushbot games without incident.

  • SSCAIT did not record an exception log.
  • If it was a time limit loss, why did it happen in a short game with few units?
  • It didn’t seem like server maintenance either. The games before and after were closely spaced.

It’s a mystery, and there doesn’t seem to be any information to start from.

Steamhammer does still have crashing bugs despite my rigorous eradication campaign. AIIDE 2017 reported 4 crashes out of 2964 games, a rate of about one per 740 games. The current SSCAIT version now has 1 crash in 385 games, which is not statistically different. I found a crash yesterday with a stress test where I forced Steamhammer to play an opening that caused it to lose bases and struggle to recover. After many games, I got one crash. I think I fixed the cause, but the crash is rare and difficult to reproduce, so....

Pineapple Cactus

The new bot Pineapple Cactus is named after a nice kind of cactus that grows in the Mojave Desert. If you think any cactus is nice, that is. For a brand new bot, it has a surprising variety of skills.

  • Conduct fairly decent macro, especially later in the game.
  • Expand everywhere if left alone too long.
  • Make and use a variety of units, up to ultralisks.
  • Defend a ramp or choke with sunkens.
  • Cancel a building that is about to be destroyed.
  • Separate injured mutalisks and send them home to recuperate.
  • Recover after losing its main, rebuilding the tech elsewhere.

It also scouts the map with overlords in a careless way, so that the overlords die at a prodigious rate. The 45 minute long first game against terran turtle bot Johan Kayser shows all of these skills. Pineapple Cactus’s second game against Johan Kayser is its most successful game so far.

As I write, Pineapple Cactus has a score of 2 wins and 9 losses, and one of the wins is by crash. It has all those skills and it can barely make a dent in the opposition. 1. The bar is high: It’s tough to jump in with a new bot. 2. If you have weaknesses in basic skills, it doesn’t matter how many other skills you have.

mine-laying framework

What is a good framework for laying spider mines?

Steamhammer’s terran is much better with barracks units than with factory units. To catch up, it needs 2 skills. One is the ability to siege tanks non-ridiculously, and the other is the ability to lay spider mines in reasonable places. Right now it can’t lay mines at all.

It would be easy enough to code up a simple behavior like “lay mines along the path between the friendly and enemy main.” But I’m a little more ambitious. For terran and protoss, Steamhammer is primarily a starting point for authors to build their own bots. I want there to be enough structure that authors feel they can plug in their own mine-laying skills without having to figure out the details from scratch. I don’t think it would take much structure.

A brief reminder of some of the many uses of spider mines:

  • Provide map vision, so you can (for example) see incoming drops.
  • Obstruct paths so the enemy can’t move around as easily.
  • Catch fresh units just coming out of the gateway (say).
  • Deter cloaked units without needing detection.
  • Block expansion locations.
  • Directly attack sieged tanks or dragoons by being laid next to the target.

So what is a good framework for laying mines? I’m imagining something like a list of available behaviors and some way of telling when to use each, but I haven’t come up with a satisfying plan.

What would you do?

Steamhammer-Tyr game

A funny game, a comedy of errors: Steamhammer versus Tyr terran by Simon Prins, on the map Tau Cross. Steamhammer opened with 2 hatch mutalisks, and Tyr bunkered itself in and went with infantry on one base.

Phase 1: Steamhammer fiddled around with its mutalisk force, picking off several building SCVs but mostly wasting time.

Phase 2: Steamhammer happened to notice that the terran mineral line was also a possible target. “Oh, look, terran has SCVs mining. I didn’t know that!” Tyr didn’t defend but moved out to counter instead and lost all SCVs. Steamhammer had 3 mining bases to 0, and only had to survive Tyr’s attack to win. Terran could not reinforce, so that was easy, right?

Steamhammer finds the mineral line

Phase 3: Instead of defending itself, Steamhammer decided to sacrifice every mutalisk against the meaningless bunker. It also wasted units piecemeal against the terran ball. Tyr destroyed the zerg main and natural. Steamhammer lost many drones by sending them to mine gas at bases that were under attack. That makes 3 big mistakes, more than enough to lose.

Phase 4: Tyr spread out to find the zerg 3rd base, found it after a few tries, and then—decided to send its army home to rest. “No zerg anywhere! Not that I’ll admit, anyway.” The marines in the picture saw the base, and that is when Tyr started to send its troops home.

Tyr locates the zerg base

Phase 5: Steamhammer slowly recovered from 7 drones at its third base. It restarted its tech from zero, put down 4 sunkens because it knew there was a scary army out there, and belatedly switched to lurkers. Steamhammer made far too many drones before moving out, but finally sent a lurker and won easily because Tyr had no detection. The mutalisks had also killed the comsat.

In the picture, nothing can stop the lurker, and more lurkers will come. You can see in the minimap that Steamhammer has retaken its main and natural and a mineral only base as well.

one lurker can win

Both sides showed a lack of resilience. This time, Tyr turned out to be lacking a little more. Besides its opportunity to attack and win, Tyr had an unfinished science facility that it could have canceled (it’s in the upper right of the last picture). Then it would have had the resources to make an SCV and get back to mining.

strategy learning by solving the game matrix

Being unpredictable to your enemies has value. How can you do strategy learning and still remain unpredictable when you should? You can’t simply require randomness, because if one strategy dominates, then you should play it every time. At other times, you may benefit from playing 2 strategies equally, or by playing a normal strategy 95% of the time and otherwise rushing. It depends on what opponent strategies counter each of yours, and the n-arm bandit methods that bots use now don’t understand that. Here’s one way to do it. It’s a step up in complexity from UCB, but not a tall step.

You can record the results of your strategies and the enemy strategies in a zero-sum game matrix, and solve the strategy game (which is the subgame of Starcraft that involves choosing your strategy). In the first cut version, each cell of the matrix is “n times it happened that I played this and the enemy played that, and k of those were wins.” Take the observed probability of win for each cell of the game matrix as the payoff for that cell, and solve the game. The solution tells you how often you should play each of your strategies, assuming that the opponent chooses optimally.

There are a couple different algorithms to solve zero-sum game matrixes fast. I personally prefer the iterative approximate algorithm (here is a simple python implementation), but it doesn’t make much difference.

If you recognize a lot of strategies on both sides, you’ll have many matrix cells to fill in, each of which requires some number of game results to produce a useful probability. 10 strategies for each side already means that a big AIIDE length tournament won’t produce enough data. For a first cut, I recommend recognizing only 2 or 3 categories of enemy strategies, such as (example 1) rush, 1 base play, 2 base play, or (example 2 for zerg) lings and/or hydras, mutalisks, lurkers. Since you’re grouping enemy strategies into broad categories, you don’t need much smarts to recognize them.

You can group your own strategies in a completely different way, if you like. There’s no reason to stick to the same categories. Also, your bot presumably knows what it is doing and doesn’t need to recognize game events as signifying that it is following a given class of strategy.

In this method, you are assumed to choose your strategy before you scout, or at least ignoring scouting information. You can take your time to recognize the enemy strategy, and base the recognition decision on anything you see during the entire game.

How do you get started learning? You might want to start with a matrix of all zeroes and only use the game matrix for decisions after you’ve gathered enough data. Instead, I suggest keeping a global matrix alongside the ones for each opponent, with floating point game counts and win counts in each cell. The global matrix has the totals for all opponents. (Or maybe there’s a global matrix for each opponent race.) When you face a new opponent, initialize the new opponent’s matrix with scaled down game counts and win counts from the global matrix, as if only a small number of games had been played in total (I suggest 1 to 3 times the number of cells in the matrix as a try). You’ll start out playing a strategy mix that is good against the average opponent, and as you accumulate data the mix will shift to specifically counter this opponent.

There are tons of ways to fancy it up if you want to try harder. You could try a variant where you estimate the enemy’s choice probabilities instead of assuming the enemy plays optimally (you’ll need a different solution algorithm). You can keep a larger game matrix in parallel with the small one, and switch to it when you’ve accumulated enough data. Or use a hierarchical method that unfolds categories when there is enough data to distinguish them. You can try a more complicated Bayesian game solution algorithm, which realizes that the numbers in each cell are empirical approximations and takes that into account (“oh, this cell doesn’t have many games, better not rely too strongly on its value”). You can include scouting information in the strategy decision (“well, I can see it’s not a rush, so strike out that option for the opponent”). You can divide your notion of strategy into any fixed number of aspects, and keep independent matrixes for each aspect, so that your strategy choices are potentially random in many different dimensions. The sky is the limit.

Tscmoo and squad coherence

In my post about independent control for unit micro I mentioned that Tscmoo can “lose squad coherence” without explaining what that is. I meant that Tscmoo likes to spread its units out instead of keeping them in a bunch, and sometimes units that start out working together end up separated and unable to cooperate. Here are a couple games from today to illustrate. I think the behavior is especially clear with zerg, so these are games of Tscmoo zerg.

the good side

First a game to show what Tscmoo gains by scattering units over the map, Tscmoo zerg versus Wuli on Heartbreak Ridge. Tscmoo opened in a way that left itself vulnerable to Wuli’s zealot rush. When the first 4 zealots arrived, Tscmoo had 4 zerglings to try to keep its morphing natural alive. Wuli already had 2 more zealots on the way, so it was army supply 12 versus 2. It looked like the natural would fall for sure.

Well, the fight went on for a while, but Tscmoo’s basic method was to run away and lure zealots out of position, then mob any zealots that strayed and could be locally outnumbered. Wuli didn’t reinforce properly and let its units get distracted, so that its powerful army went on goose chases and accomplished little. In the picture, zealots are chasing a zergling away from the natural. Notice the yellow dots on the minimap; Tscmoo is scattered around.

Tscmoo leads goose chases

Eventually mutalisks came out and zerg won. Tscmoo prevailed because its willingness to run away in different directions confused Wuli, which did not know how to concentrate its forces on a vulnerable point like the natural hatchery. Goose chases confuse a lot of bots, including Steamhammer (so far), and they are responsible for a lot of Tscmoo’s resilience when facing defeat.

the bad side

The image I had in mind when I wrote “loses squad coherence” was a Tscmoo group coming under pressure and forced to retreat. Human players like to have lines of retreat if they are pressed back, so they can keep their units together. Tscmoo likes to form a giant concave and doesn’t seem to pay attention to lines of retreat. As the concave is forced farther back, different units may retreat through different exits so that what was once a group fighting together breaks up into subgroups that the enemy may be able to defeat in detail, or ignore and bypass. There is no longer one coherent squad.

The game Tscmoo zerg versus Krasi0 is not as clear an example as the last game, but it shows what I mean. Tscmoo went for a hydralisk all-in and laid on a punishing attack. The game was decided when Krasi0 held with strong tank placement. In the picture, Tscmoo’s retreating hydralisk group is forced off the central plateau on Jade and breaks up as I described above. The hydras took different exits and did not join up again.

Tscmoo’s forces retreat in different directions

Goose chases do not confuse Krasi0. Krasi0 goes for the throat.