This is part 3 of a series of articles about my upcoming Combat Commander: Adversary game module—a solitaire system that lets one player duke it out with an automated opponent on the storied battlefields of GMT's classic wargame.
In my first article about Horizon values, I explored the surprising realization that we human wargamers instantly know how well our units can see around them from any given hex on a tactical map, but that it was a skill I needed to transform into usable data for consumption by an automated opponent.
One thing hindering me was that I had problems keeping my "publication hat" on. I was still thinking like the guy tinkering with a homemade engine in his basement, when Director of Game Development Jason Carr said, "You know we can PRINT a Horizon chart for every map, right? So go wild, nobody will need to compute that stuff in their heads."
(Hearing this reminded me of junior college, where my brethren and I had learned calculus by hand until we were handed the "magic formula" at the end of the semester. What a relief.)
Freed from that mental lock, I started experimenting with an ever-widening definition of Horizon. What if I expanded the concept to 12 directions instead of just six? This would mean looking through the six hexsides as well as the six vertexes (counting the edge beyond a vertex as 'one' in terms of range), and recording the number of these 12 directions in which the unit has LOS of 3.
Of course, this would ratchet up the Horizon values—from "up to 6" to "up to 12"!—but I figured legibility wouldn't suffer in any significant way: the number 12 wasn't liable to show up in more than a handful of situations, except on those desert maps where almost every hex would turn into a 12 anyway.
Long story short: it worked and it gave me much more precise Horizon charts. The old charts didn't take into account LOS along a vertex that peered between two buildings, but the new ones did. And that provided the bot with a much better tool for evaluating the effectiveness of a unit standing in this hex rather than that one.
![]() |
| Section of map 6, six directions |
![]() |
| Same section of map 6, twelve directions |
Emboldened by my renumbering success, I also explored the idea that Horizon charts could be unidirectional. Up to that point, I had built them to be omnidirectional; that is, the values they displayed took into account all directions from any given hex. So yes, the bot could consult that tool the way it was and position some unit in a building hex with a solid Horizon value (say, 6) but the chart didn't specify the directions in which that value applied. So what happens if all 6 clear LOSs look to the east, when the bot's really just concerned about units advancing from the south?
(I wasn't looking for a solution: omnidirectional charts worked like a charm and the bot was able to make effective use of them, with an entire array of situations eventually evening out to create a satisfying experience. But I wanted to see how far I could push the concept.)
This fool's errand (spoiler alert ...) would have had me coming up with four unidirectional charts for each of the game's maps—one for each cardinal direction—plus the regular omnidirectional one. And since I wanted to keep everything on one page, this meant stuffing five values inside of each hex, asking the human player to feed the bot only one set of values, as warranted by the situation. In short, the adversary needed to use the global value (omnidirectional) UNLESS all of its enemies (i.e. the player's units) stood on one side of the hex under consideration: north, south, east or west. In such a case, the adversary would refer to the relevant unidirectional set of values.
Interesting in theory, right?
In practice, it required displaying the different sets of values in a way that made everything legible. I tried color-coding the whole thing (red for southern values, blue for northern values, etc.) and using different orientations for the numbers themselves—so you'd physically rotate the chart and only consider the values that appeared right-side up—but the endeavor turned into a catastrophe of biblical proportions. The fact that I had recently decided to inject additional information in each chart beyond Horizon values only served to compound the problem. This resulted in my not even completing one of those misguided charts: it was clear nothing good would come of it.
![]() |
| Welcome to Hell |
Oh, and that new stuff I'd started adding to the charts? They were markings meant to speed up setup as well as some in-game computations. Red highlights indicate objective hexes; red Horizon values signify hexes with cover > 0; and black circles single out the hex (or hexes) with the single highest Horizon value on the entire map.
![]() |
| Ain't that a beaut? |
(Side note: At some point during the exploration process I had considered switching my definition of Horizon value to be "the number of hexes a unit can see into within a range-3 radius," but quickly discarded the idea. The values stamped inside each hex would have been anything from 6 to 36, and the resulting mess would have turned attempting to scan the chart—looking for the best Horizon value out of a few select hexes—into quite the ordeal. [I have some Tylenol handy.] I could have cut the range back from 3 to 2 in order to bring down the number of hexes a player would need to evaluate ("only" 18 instead of 36 ...) but a range of 2 wasn't sufficient to provide the bot with useful information.
Nevertheless, keep this notion in mind: we'll snap back to it before too long.)
Whenever I had some free time, I'd sit down with a map I wanted to test and create the corresponding Horizon chart. They proved challenging to put together, to say the least: the process was quite error-prone and, dare I say it, rather mind-numbing after a few rows. (Said numbness then spawning even more errors, of course!). Coding a piece of software to perform the required task is deceptively complex, so I tried to automate the process using AI. Alas, the systems never performed satisfactorily and even introduced new sorts of mistakes, such as looking straight through a building—"You're right, Francis, there is indeed a building in the way"—trying to determine the odds of a LOS being clear (to be fair, I've encountered one or two human players who seemed to play that way ...) or else making things up out of thin air.
Jason offered to take the AI by the horns, as it were, and was initially met with encouraging success; but try as he might, he couldn't prevent his automated helpers from biting their own tails in the end, especially when it came time to size up a LOS across a vertex.
That's when co-developer Marco Poutré came to the rescue: "What if the Horizon value was the number of hexes you can see into at a range of EXACTLY 3 hexes?"
Note the crucial difference: my quickly-dismissed notion back in the day had been to count up all of the hexes inside of a 3-hex radius, whereas Marco was suggesting we take into account only the ring of hexes at a range of exactly 3.
And you know what? It solved everything.
It makes it possible for AIs to crunch their way through map after map without injecting human errors, while also making it easier for me, the guy who needs to write the rules, to explain the concept on paper. And best of all, at the end of the day, this new Horizon value still does everything it needs to do, and works perfectly inside the rest of the system, with no further alterations required.
Now there are a few things I find especially interesting in this dénouement.
First of all, I love to look back and realize that the original Horizon definition evolved from the idea that players would have to compute those values in their heads. I needed a "simple" way for them to do it: From a specific hex, can you see up to 3 spaces in this direction? How about in that one? And so on. Even when Jason said we'd be printing the charts (freeing the minds of everyone, everywhere!), Horizon was still doing its job just fine, which meant that the absence of any friction in that department never led me to re-evaluate the way it was designed. It just worked.
Second of all, it's only when we tried to automate the creation of Horizon charts that we figured we might need to rethink the definition itself. Had our digital tools blazed through the task we set them, the status quo might have endured; but that was not to be the case. And the redefinition proved to be a boon all around.
Last of all, this resolution took place as I was writing this very article, providing a glorious example of real-life game development, laid bare for all to see.
(Also exposing the joys of working with a crack team of developers.)
(Next time, we'll look at Outliers and how they come into play when the adversary decides—or not—to use the Initiative card.)
# # #



