archive by month
Skip to content

confused game Steamhammer-Tyr

Steamhammer and Tyr terran by Simon Prins played a hilarious game on Moon Glaive. I think that Steamhammer decided on a 3 hatchery before spawning pool build (it’s not entirely clear), but the zerg build became confused because Tyr’s scouting SCV delayed the natural hatchery, and because Steamhammer has an issue on this map where it sometimes sets its bases down unexpectedly far away. The build as executed was hatchery-pool-hatchery, with the third hatchery in Tyr’s natural because zerg hadn’t located the enemy yet. Something similar happened almost exactly a year ago in a game versus Krasi0.

Tyr reacted differently than Krasi0: Tyr ignored the zerg base in its natural!

Tyr is unworried by the zerg base

The marines fired at the zerglings, but the hatchery and drones were in plain sight, and they just didn’t care. Their job, I gather, was to guard the natural against zerg attack, and the functioning zerg base was not an attack. They took their orders literally! Steamhammer was also unworried, and mined minerals contentedly.

Tyr was bright enough to figure out that it had to expand somewhere else, and planted a command center at what would normally be its 3rd base position. The zerg play was disorganized, but the terran play was more disorganized, and Steamhammer won effortlessly.

Arkanoid and BWTA

Regularly scheduled real world events are taking up some of my days.

I wanted to run a test on the map Arkanoid. It’s a concept map from 2006 with many destructible neutral buildings in blocking positions. Some of Steamhammer’s new code for the AIST maps should kick in, so I thought it would be a good test.

But the map crashed BWTA. I have to finish removing BWTA before I can test my own map code on Arkanoid. There is a disadvantage after all to my step by step replacement procedure.

bizarre bug

I was making changes to squad membership updating and tactical targeting, which happens once every 8 frames. And I hit a bug which had these symptoms: Steamhammer appeared to run normally, but extremely slowly. Each frame took a second or more. Not each eighth frame, each single frame. Also Steamhammer was unable to recognize its slowness; its timer said that the mean frame took 0.1 milliseconds, normal for the very early game which was as far as I let it run. What could cause such bizarre behavior?

It took a long time to debug. I finally traced it to a misplaced } character which included too much in an if, with the result that an important value was never initialized. It was not easy to see in the code. How this caused a slowdown and how the slowdown stayed outside the timed code (or otherwise broke the timer's behavior) I do not know, and don't expect to find out....

It is worth it to use a prickly language like C++? One wrong touch and you get glochids in your skin for who knows how long. Some days I think about recoding Steamhammer in a pleasant language like Haskell, where new code more often than not works the first time. But that also comes with big disadvantages.

tricky point with MapPartitions

If you use the MapPartitions code that I posted, here’s a tricky point that I ran into.

Units can’t walk on a geyser, so MapPartitions puts the walk tiles of the geyser in partition 0, the unwalkable partition. It stays unwalkable if there is a refinery building on it. So if you check reachability like so, the.partitions.connected(this unit’s position, that geyser’s position) (to build on it), or the.partitions.connected(this unit’s position, that refinery’s position) (perhaps to mine from it, or to attack it), then the answer will always come back—no, you can’t walk there. It’s correct, you can’t walk on top of the refinery!

The correct check is: Can the unit reach any position adjacent to the geyser? The geyser blocks paths, so in principle it might be reachable from more than one partition. Maybe you can get to it from your side and the enemy from theirs, but there is no path between your bases because the geyser is in the way. Weird maps happen. To always get the right answer, you have to check each adjacent tile.

There’s no issue with checking reachability between 2 units, or between a unit and any building other than a refinery building. The ground underneath is walkable, and that is what counts. Only refineries cause extra complexity.

how to specify island openings

By the way, I decided to implement this opening requires that map feature without defaults, like this: If the opening specifies a feature, like "island": "yes", then the feature value is required. If it doesn’t specify, then there is no default value; the map may have the feature or not, the opening doesn’t care. So far it’s as described before, and now I add one more idea: Island openings are playable on non-island maps. They are unlikely to be a good idea, but it will happen against some opponents (I proved it by test). Simply give them a low probability of being played. On an island map, everything else is disallowed, and you get an island opening. On a non-island map, you usually get a usual opening, but occasionally Steamhammer will try out an island opening to see if the opponent is weak to it.

Steamhammer and Sparkle

I’m still preparing for AIST, so expect Steamhammer to participate. The bot is going to struggle, though. There is not enough time to prepare it fully for the maps. Steamhammer will do well only if the other competitors are equally unprepared.

Sparkle is a genuinely difficult map. It requires specialized builds that are not right for any other map, which means that in the proper course of events I ought to delay work on it until Steamhammer can develop its own openings, which won’t be for a time yet. And the map has unique features that require special code. No matter how general I make the code, in practice it will apply to this map alone.

The high ground expansion on the island has zerg buildings that create creep. The creep is an issue for map analysis if you’re not zerg, because BWAPI doesn’t provide a way to find static creep on the map; you have to see it to know where it is, or figure out for yourself how it spreads. The high ground base also has a large crystal on top of the geyser. Any race can built a refinery of its type on the geyser, but the crystal blocks mining from anything other than a zerg extractor (well, you can mine if you glitch each worker through; a bot might be able to do it regularly, but it’s definitely not intended by the map design). Steamhammer is confused by the confusing features and isn’t able to take the base, even as zerg. The low ground expansion has a psi disruptor building on top of the geyser. To my surprise, on the AIST map version it’s also possible to build a refinery underneath the psi disruptor (I tested it by hand with the 3 races). I haven’t seen that in pro games, and assumed the building had to be torn down first. Steamhammer can build an extractor there. But no race can mine from the geyser until the psi disruptor is destroyed.

Yesterday I started on the skill of clearing the neutral buildings that clog up the second and third bases on each starting island. As matters stand, Steamhammer can mine only 1 of the 3 geysers that it should have access to, which leaves it ridiculously weak. The map analysis creates for each base a list of “blockers” that ought to be destroyed, which it outlines on the map in red if map info is turned on. Almost all maps have none. Fortunately the coding and testing only took a couple hours.

Only then did I think through the rest of the steps to implement the skill. There is updating the list of blockers as they are destroyed, of course. Before that is sending a squad to do the work... but hmm, the usual tactical getAttackLocation() only returns a location, not a unit to attack. In fact, Steamhammer doesn’t have any way to order a squad to destroy a unit! I have to create a new kind of squad order, implement it in the squad, and add the tactical analysis to decide when to use the order. It’s likely a day’s work to write and test and finish, more if I hit a snag.

Well, that’s too much effort to support a single map. On the other hand, most of the code is reusable for destroying buildings that block paths, a more common skill though low on my list. I’m still thinking about it. In the meantime, I’ll work on other skills. There’s not exactly a shortage.

ground connectivity code to share

Here is Steamhammer's new C++ MapPartitions class, which calculates ground connectivity. This is a donation to the community. Feel free to borrow it for your own bot, if you like. The download is a zip which contains 4 files: MapPartitions.cpp, MapPartitions.h, and 2 license files. The class contains some code derived from UAlbertaBot, so there is a UAlbertaBot license plus Steamhammer’s license. They are both MIT style licenses, which basically make no requirement beyond including the license file. (It’s irritating that the licensing considerations are as complex as the code, but that’s the world we live in.)

I’ll quote the comment describing it:

// Partition the map into connected walkable areas.
// The grain size is the walk tile, 8x8 pixels, the granularity the map provides.
// Unwalkable walk tiles are partition ID 0.
// Walkable partitions get partition IDs 1 and up.

// This class provides two features:
// 1. Walkability for all walk tiles, taking into account the immobile neutral
//    units at the start of the game.
// 2. Ground connectivity: What points are reachable by ground?

// If two walk tiles are in the same partition, it MIGHT be possible for a unit
// to walk between them. To know for sure, you have to find a path and verify
// that it is wide enough at every point for the unit to pass.
// If two walk tiles are not in the same partition, no unit can walk between them.

Concretely, the interface lets you directly test the walkability of a position, find the partition ID of a position, or check whether 2 positions are connected by ground. You can find out the total number of partitions (some maps have hundreds due to small holes), and you can draw partitions on the screen for debugging. There’s not that much to it.

A few notes:

  • There is a separate initialize() method that is not called by the constructor. You have to call it yourself, in or after your main onStart(). Depending on your use case, this is sometimes necessary to avoid making BWAPI calls before BWAPI is initialized itself.
  • Maps often have little side bits attached by a single walk tile. No unit is small enough to walk there, but this class doesn’t know it.
  • The little side bits are not important, at least not in Steamhammer’s play. Units don’t want to go there.
  • The class does not update when neutral units are destroyed, opening paths that used to be closed. But the walkability data structure is designed to be easy to update in that case.
  • This version is slightly different from Steamhammer’s code. I changed the error handling so that I could remove one last dependency and make it completely standalone (except for BWAPI, of course). Only a handful of lines are different.

I’ve suggested before that authors should package up reusable code as libraries. BWEM, BWEB, and FAP are great examples. MapPartitions is more modest. When I’ve looked at breaking out Steamhammer code, until now I’ve always felt that the parts were too integrated with each other, with too many dependencies. MapPartitions is the first exception. I hope some people find it useful.

3 brief Steamhammer notes

1. Today I removed a bunch of unneeded header includes from various source files. In some cases, I moved an include from the .h to the .cpp file, and dropped in a forward declaration instead. I’m hoping it will speed up compilation.

3. Also today I made several small changes to improve play on island maps like Sparkle, and maps with large inaccessible areas like Third World. I gave Steamhammer the skill to avoid sending a squad to a place the squad can’t reach, basic stuff like that. There’s more to do. The fundamental skills need adjustments to fit situations that Steamhammer has never been tuned for.

3. Steamhammer today played a hell-for-leather test game on Third World. Its mutalisks left the terran main in tatters while its own bases were under marine attack, then the flyers returned home barely in time to save the last zerg building, the spawning pool. Steamhammer won the game with a single bleeding building. Unfortunately the replay seems to be corrupt, so I can’t show it.

Steamhammer’s opening selection surprised me

Steamhammer lost a game to XIMP by Tomas Vajda, for the first time since December. When I saw the result listing I thought “That has to be due to a new bug.” But no, it is actually an unplanned effect of a deliberate feature.

After Steamhammer finishes the exploration phase of opening learning (the first 5 games), it does one extra check that I didn’t mention in my post on the topic (you can insert this as step 1.5 in that post’s list). If all games so far are wins, or if all games with the current expected enemy plan are wins and the enemy is believed to always follow the same plan (even if we don’t always recognize it), then Steamhammer takes a “business as usual” shortcut and bypasses the rest of its analysis. “So far I’ve been playing openings for this matchup, or openings to counter the enemy plan,” it thinks. “And it worked perfectly. All I have to do is more of the same.”

But since I carried over the old game record files, it wasn’t playing its standard openings against XIMP. Before this version, Steamhammer was hand-configured to play a specific counter that always wins. That opening is the only one to appear in the game records before this. Now the hand configuration is gone, and the business-as-usual shortcut applied, so Steamhammer chose a different opening to counter XIMP’s cannons, a 3 hatch ling bust. But XIMP makes too many cannons for that to work, and zerg lost.

Hmm... I have 3 different thoughts. First, this should be the only loss. In the next game, Steamhammer will notice “Hey, I know an opening that always wins. Play that!”

Second, retaining the old game records has been an interesting test. And I think I want to keep it up for a while, because I’m still learning from it. But I also need to delete the old game records and do a blank slate test, because that is how the system was designed to work. It will behave differently when learning from scratch. For one thing, it will likely take several tries to hit on its XIMP-beating opening, doing worse at first. For another, it should discover quickly that it knows a way to put up a fight against Iron, and start doing better in that matchup. I was originally planning to do a blank slate test on SAIL, but SAIL remains down.

Third, I think the opening selection has a lot of room for improvement. It barely takes the predicted plan into account, it is not skilled at taking the map into account, the 5 game exploration phase is sometimes too long and sometimes too short, the exploration that happens after the exploration phase is not tuned correctly, and the whole system is rather ad hoc. I should drop in a proper machine learning algorithm and figure out a correct exploration policy. Those steps will make the rest of the opening selection apparatus structurally simpler.

Still a lot do to!

this opening requires that map feature

Before the 1.4.x series is finished, Steamhammer will adapt its opening choices to the maps by experience, even when it faces an unknown opponent. In a tournament, it may also want to adapt immediately to an unfamiliar map, which means it will have to analyze the map for features that influence play, and it will need prior knowledge of which openings work for a map with those features. At first, hand coding will be the way to connect map features to opening choices. That will also make it reasonable to compete in AIST. It’s no fun to play on an island map like Sparkle without specialized island openings.

The topic came up in the comments to the post chokes and regions from February. Antiga proposed 3 map features he wanted to be able to take into account.

Here’s what I’m considering for the design.

  • Code the map feature preferences in the configuration file, where they are easy to change.
  • Attach preferences to the openings directly, not to the strategy mixes. The island openings will be marked good for islands on the opening, along with Race and OpeningGroup. Then they are included in the strategy mixes without further marks.
  • It needs to be kept simple. Something like “Require” : { “feature” : “value” }, where you can put any number of features between the braces. Each gets only one value, though, unless I make it possible for the value to be a list. Maybe “Avoid” instead of or in addition to “Require”.
  • Require would mean that all the given features are required. Avoid would mean that all the given features are to be avoided.
  • There should be at least one default value: Most openings are not suitable to play on an island map, and should be silently marked for no islands. Maybe there should be more defaults.

I may start with only a map feature, or only an island feature. Here are possible feature names and values for some features, including Antiga’s 3 features.

featurevaluesmeaning
map[map name]this string is in the map name
islandyes, nono 2 starting positions are connected by ground
main rampup, down, levelentrance to each main base
main choke width[number]main entrance must be no wider than this, in tiles
natural choke width[number]natural entrance must be no wider than this, in tiles

A lot more feature values might make sense. To cover all island maps, there should be features for the number of bases and the number of gases at each starting positition, and probably more features beyond that. There are a bunch of different kinds of semi-island maps, and maybe each kind should have its own value. Some are specialized: For example, Iron Curtain (designed as a 2v2 map) has 4 bases with a divider that (initially) separates it into 2 islands, each with 2 starting locations—in 1v1, you might start on the same island as your opponent, or you might not. The main ramp feature might have a value “multiple” for maps which have more than one entrance to the main. And of course there are always irregular Blizzard maps where each starting base may have entirely different features. These things are complications that should be minimized on a first pass.

To be concrete, you might declare an island opening like this. (Beware: I edited this up in less than a minute and didn’t test it. It is not a tuned opening.)

    "Island 2HatchMuta" : { "Race" : "Zerg", "Require" : { "island" : "yes" },
        "OpeningBuildOrder" : ["4 x drone", "overlord", "4 x drone", "hatchery", "spawning pool", "extractor", "7 x drone", "Lair", "drone", "metabolic boost", "2 x drone", "spire", "3 x drone", "hatchery", "drone", "extractor", "2 x overlord", "12 x mutalisk"] },

The 80-20 rule applies. Does this plan meet 80% of needs? What do you think?

Microwave beats Iron

Locutus is doing great. What I find more interesting is that Microwave is also doing great since its update yesterday. In particular, Microwave seems to have improved enough to beat Iron consistently. I thought the most interesting game was the most recent one.

Furthermore, Microwave played more than one opening against Iron in its recent winning streak. Its favorite, though, seems to be 9 pool with a fast 2nd hatchery. The game plan has not changed much, only the execution is improved. Early zerglings hammer on the terran wall, occasionally breaking it down but usually only sapping the terran income. The lings don’t care if the wall is open, or if they come under fire, they only want to hit those supply depots. Microwave defends against the vulture runby with sunkens up front plus a sunken in the main. Iron usually appears surprised by the sunken in the main and fails to cope with it. Microwave follows up with hydralisks and later mutalisks, switching flexibly between hydras and mutas and preventing Iron from gathering its forces—especially targeting tanks so that they don’t build up to large numbers. Eventually Microwave reaches a critical mass of hydras and wins.

Even if you are as good as Iron, that is what happens if you always play the same and don’t update for a long time.

Locutus and Microwave are both Steamhammer forks. I’m pleased that they’re doing well. I see it as partly my success, too.

a cosmetic code improvement

Steamhammer inherits UAlbertaBot’s architecture: It is a collection of singletons which communicate by directly calling each other. Each provides a method Instance() which defines its instance as a static and returns a reference. It’s a standard C++ trick. The cross-calls look like this:

    return BuildingManager::Instance().isBeingBuilt(unitType);

It works, but I find it wordy and ugly. It repeats implementation details that are irrelevant to the caller. I plan to change the syntax to this:

    return the.building.isBeingBuilt(unitType);

With a local instance variable the, a reference to the The singleton which will centralize access to the other singletons. So far I have done this only for the newly-written MapPartition class which does connectivity analysis. It was a test to make sure I could see in the dark, because of the C++ Needlessly Obscure Initialization Rules (NOIR).

The code changes are not too much, and when I feel less time pressure I intend to implement the idea throughout. I think it’s an improvement. More concise and readable code will make the codebase more fun to work with.

Steamhammer priorities in light of AIST

Should Steamhammer compete in the AIST competition? I’m still thinking about it. It’s not an easy decision. On the one hand, I love the idea behind the competition. It places demands on bots that I have always intended to meet eventually. On the other hand, “eventually” is a key word. The skills a bot needs to compete in AIST are not needed in any other competition, and working on them now will delay other things that I want to do.

Progress so far: I fixed the crash on Transistor. Crashes first! At the top center expansion, some mineral patches overlap the terrain in a way that fooled Steamhammer’s map analysis into believing that they are inaccessible, which indirectly caused a “should never happen” condition because of how base placement works, which caused the fatal bug, a use-after-free error. It’s good now, and Steamhammer can play games on Transistor. I fixed the endless stream of exceptions on Sparkle and Third World caused by the bot’s inability to figure out how to move a scout around the enemy base. I diagnosed Steamhammer’s inability to expand on Third World. The bot believes that the narrow ramp from the main is not passable, because the path analysis is simplified. I’m testing the fix now. It is a feature that will also be necessary on Sparkle, a partition map at walk tile resolution which says which ground areas are connected.

The topic is priorities. So:

What will improve Steamhammer the most in the short run? Tactics and micro. Steamhammer is not well-rounded. I’ve been concentrating on strategy and macro, and by now Steamhammer’s strategy and macro skills are relatively much stronger than its tactics and micro. There are weaknesses everywhere, but tactical blunders and awkward micro lose a lot more games. Throwing away overlords like they’re free, ignoring cloaked units, running an army into the enemy forces without fighting—there’s all kinds of horrible stuff.

What does my plan call for? More work on the opponent model, for multiple reasons. One, I feel the need to make at least basic progress on the machine learning part. It helps keep the goal in sight. Two, it will give Steamhammer a kind of adaptivity that bots desperately need. Three, it fits with my overall top-down development plan: Strategy first, then tactics, then micro.

What needs doing for the AIST? Mostly map skills.

  • Sparkle: Basic island skills. Choose an island build order, take island bases, defend them, transfer workers, scout for enemy islands. Many regular skills need to work differently on islands.
  • Sparkle: Fix the bug that prevented Steamhammer from expanding on its own starting island.
  • Sparkle: Destroy the neutral building on the low-ground expansion geyser. This is the only map I know with that feature, so it’s a very specialized skill (though simple enough).
  • Third World: Pathing. Understand the narrow ramp from the main. Understand the gate between the “first world” and the “third world,” which workers can mineral-walk through though it is impassible to other ground units.
  • Third World: Semi-island skills. Not quite the same as island skills, though maybe I can find a way to treat them as the same.
  • Transistor: Place defenses at the twin ramps, not at the natural hatchery.

I think I can probably get everything working in time, at least at a basic level. If I spend the time to do that, Steamhammer will definitely perform worse in AIIDE. Also, some of these features I was planning to delay until more infrastructure was in place, and there won’t be time to add that infrastructure for AIST. There is a risk of having to redo work later, slowing down overall progress.

So far I’m proceeding on the assumption that Steamhammer will compete. But I haven’t decided firmly.

Steamhammer finally tries its AntiFactory opening

Steamhammer-Iron is the first game in which Steamhammer played its AntiFactory opening, which counters Iron’s vulture runby skill (as well as other stuff that opponents could try with a mech opening, and some opponents do try). If Steamhammer started with no history, it would counter Iron on the second game. In fact it started with all its past game records on SSCAIT since version 1.4, so it thought AntiFactory was just another opening to explore, more important than the average opening because it counters the predicted enemy plan, but still just another opening and not worth special attention. Since it lost, it probably won’t try the opening again for a while (though there is a lot of randomness in the decision).

If you’re familiar other Steamhammer-Iron games, like that one, you’ll notice that in this game the AntiFactory opening stops Iron’s early vulture pressure more or less neatly and gets mutalisks in time to break up the next attack, the followup that adds marines and 1 tank. Then Steamhammer starts to flounder. The mutalisks neither defend efficiently nor attack the enemy base efficiently, and zerg desperately wants a 3rd base and sends drone after drone to die. Still, it was a tough fight and Iron only gradually took the upper hand. With this opening, Steamhammer has a moderate chance to beat Iron.

Steamhammer needs more skills to beat Iron regularly.

  • Place the initial sunken correctly. It makes a surprisingly big difference.
  • Don’t send drones directly into enemy forces. If you can’t expand safely, make a macro hatchery in your base instead.
  • Once another base is up, defend it. Steamhammer tends to lose all the drones there.
  • Play more incisively with the mutalisks. Don’t hesitate in front of defenses, immediately switch to another target. Be more eager to pick off tanks and less willing to chase fleeing vultures and SCVs.

I think those 4 skills would be enough to win most games against Iron, and only 1 of them is a complex skill. Likely even 2 of them, any 2, would put the win rate over 50%. Tilt the game a tiny bit, and it rolls your way over time. More skills would help more. For example:

  • Don’t lose overlords like an idiot from Idiot City, even if you are one. Steamhammer regularly flies into turrets.
  • When it’s time to expand, coordinate actions: Clear any blocking spider mine, push attackers away, if necessary escort the drone to the expansion site.
  • Use scourge properly.
  • Clear spider mines systematically. Steamhammer has the infrastructure to track spider mines that it has seen once, but doesn’t use it; units ignore mines that are not detected at that moment.

Am I going to actually work on any of these skills soon? Maybe. Overlord safety is high on my list, because it is a critical weakness in all matchups. For the more complex skills, I am waiting for the revamp of squad structure, which won’t start for months yet. Priorities are hard.

Next: Priorities in light of the AIST competition.

Steamhammer 1.4.2 opening selection by the opponent model

The previous Steamhammer version chose its openings solely based on the enemy’s predicted plan, if there was one, or based on the matchup default openings if no plan was predicted. The new version 1.4.2 can still do that, but once it has played a given opponent enough times it prefers to choose openings that have won in past games. It has always stored the data in its game records; now it is using it.

At heart, the selection algorithm is epsilon-greedy, but there are a few wrinkles.

1. The first 5 games against each opponent, in each matchup, are the initial exploration phase. Choose openings the old way, according to the matchup or the enemy plan.

2. If any opening has a 100% win rate, play it again. This bypasses the exploration phase. If any opening has a 100% win rate on this map, play it again. It does this even if the opening has only been tried once before, so that we can’t much trust in another win. If more than one opening has a 100% win rate on the map, choose among them randomly without regard to how many times each has been played. The idea is to encourage map specialization. Also it usually ensures that a surprise win opening is tried at least a couple more times—once because it always wins, and once because it always wins on this map—to find out whether it was a fluke.

3. Decide randomly whether to explore for new openings, or try to play a known good opening. The exploration rate (“epsilon” in “epsilon-greedy”) varies from 5% if we always win to 15% if we always lose. (I don’t have any reason to think that those are good numbers, it’s just a try. Likely it should grow toward 100% if we keep losing, because there are so many openings to explore. I think I should do some math....) The form of exploration varies according to the total number of games played against this opponent. If there are few games, Steamhammer prefers to try an opening that responds to the enemy plan. With more, it increasingly chooses from the wider variety of openings for the matchup, ignoring the plan. If there are many games, over 30, it starts to choose openings at random from its entire universe of known openings. (Steamhammer doesn’t have game records for that many games against any opponent on SSCAIT yet, but it will happen in long tournaments.)

4. Try to choose the best known opening, the “greedy” in “epsilon-greedy.” Steamhammer combines the win numbers of each opening on the current map with the win numbers across all maps (a much larger number of games, but each is less informative because the map is different) in an ad hoc way to get a “weighted” win rate. It takes that as an estimate of the chance of winning this game if it chooses that opening, and picks the biggest number. In case of ties, it chooses randomly among the tied openings.

The weighted win rates are a crude attempt to adapt to the map without restricting the input to data about that map only. In some future version, I’ll switch to a more general context-aware algorithm that can take more information into account. Steps 2, 3, and 4 should collapse into one.

On the SSCAIT server, I left the existing learning files in place to see how Steamhammer would make use of the old information. So far, the data doesn’t seem too helpful. Some of the files have systematic mispredictions that the new Steamhammer version doesn’t make, and yet still believes (“there it is in writing!”). In the case of Iron, new Steamhammer can recognize and respond to the terran plan, but old Steamhammer recorded a lot of data in which it could not. Steamhammer is choosing openings against Iron according to its old data, when it would do better to ignore it. Well, I know what to do to fix that, and it’s on the list.

Randomhammer needs a lot of data to get anywhere. Even with the old data included, there is not enough. If it has played games against an opponent as protoss, that tells it nothing about what openings it should choose as terran.