PAXsims

Conflict simulation, peacebuilding, and development

Ace of Aces: or, why you should Do Maths as a game designer

Every now and again you come across something that stretches your brain in a new direction. Last week I stumbled on a magic trick of a Choose Your Own Adventure: Al Leonardi’s Ace of Aces, a paper computer running a first-person shooter, programmed in 1980—eleven years before Wolfenstein 3D, the “first” first-person shooter.

Wait what? A physical game can be a computer?

There are of course, all sorts of early “computers” of various flavours that predate what we generally mean when we talk about computer programs:

All of these devices share a common limitation: they may be programable to a degree, but they solve a singular problem: the Writer can only hand-write a message stored in his main cam “memory”, the Difference Engine and Curta perform particular mathematical operations, fire control computers perform only that calculation…the device is the program, in the same way that Wolfenstein 3D is a first-person shooter, not the computer or operating system or programming language used to make it run. And when you start to think of programming in these terms, all sorts of interesting “computer programs” are there to be explored:

Computer programs are just algorithms—often big and quite complex—but at their heart, just a list of mathematical instructions:

  • Add two numbers
  • Subtract two numbers

…and from there all mathematics is possible… (seriously. That’s what a slide rule does: “multiplication” is just adding the value several times.)

You can encode these operations in a (real) computer program by writing code. You can encode them mechanically. One of my favourite YouTubes of all time is the 1950s US Navy educational film explaining how mechanical computers perform maths:

And if you know a little about analogue electronics, you know that basic electrical circuits just do maths, and from there you can create all the complex logic of analogue and digital computing. Which is a long way of saying: if you can say something with maths, you can construct an algorithm that computes it.

Board games are doing this all the time and we just don’t think about it so much:

Sometimes the player performs operations to physically compute for the game: rolling a dice for a random number.

Sometimes the state of the board is the computation. You see this kind of trick used to modify player abilities directly inside game mechanics: when you “score” with pieces otherwise used to play the game, removing them from the board to track your score imposes a mechanical disadvantage: in the 2-player game Yinsh, you move one of your three rings to construct 5-in-a-row patterns—but when you connect five, one of your rings comes off the board to signal this, reducing the options you have to connect five again.

From a particular frame of reference, this is an algorithm encoding some pretty sophisticated maths.

Sometimes the computation is encoded in a look-up table. These can be simple conversion factors, like the 4:1 ratio to trade resources with the bank in Catan, or fairly complex range tables for weapon class vs armour class used in the Wargames Research Group games.

Choose Your Own Adventures are essentially a look-up table: after each page the player is presented with a list of options and the page to turn to if you choose that option—a look-up table that converts their choice into the next page number.

What’s so interesting about Ace of Aces?

First: what is Ace of Aces? It’s a two-player World War One dogfighting game. One of you is the Red Baron, one of you is Snoopy Biggles, and you attempt to line the other up in your sights for some dakka dakka dakka. So far so several other board games. What sets Ace of Aces apart is the ingenious interface: you play with a pair of picture books, one for the German pilot, one for the Allied pilot. Each page of the book shows you the view of your enemy given your current position.

Each page has a list of manoeuvres you can choose from and the page to turn to that “performs” the manoeuvre. I’ve put “performs” in quotes, but as we’ll see, the look-up table actually has this maths encoded into the page numbers, it’s some sneaky-clever design.

Your opponent tells you the page number for their move and you turn to that page. Then you look up your move in the look-up table you find there, and—by the Power Of Awesomeness it will take you to the same page number as your opponent gets to by turning to the page for your move and then looking up their move.

The entire game is encoded into these paired books:

  • No matter what manoeuvres you and your opponent pick, you always end up on the same page number.
  • For any given page number, the relative positions of the two planes are the same in both books. One shows the view from the German aircraft, the other shows the view looking back the other way.
Both players are on page 170. The Allied player sends the German player to page 64, the German player sends the Allied player to page 54:
…where we see the Allied player side-slips left, and the German player makes a stall-turn right…
Both players end up on page 15

There’s a lot of interesting stuff going on here! But before we dive into how the magic trick works (maybe your maths brain has an inkling of what may be involved ?), let’s take a minute to appreciate:

The sheer simplicity of play:

  • You look at a picture of the game state
  • You choose a move
  • You and your opponent turn to the page number for each-other’s moves
  • You look up your move on that intermediate page, and turn to that page number which is the new game state
  • Repeat.

There are no dice, no counters, no moving parts. You don’t even need to be in the same place as your opponent, you just need to be able to give each other page numbers. It takes less than a minute to learn how to play—even though you now have full control over a pretty sophisticated flying machine—and creates quick-fire play that makes total sense in the seat-of-your-pants early aviation era.

Error correction is effortlessly built in: if you don’t end up on matching page numbers, one of you goofed.

The framing is brilliant. The first-person view from the cockpit is so immersive, and it’s key to the simplicity of play. The state of the game and manoeuvre options (drawn as pictures of the manoeuvre) are intuitive—but that rare kind of intuitive that makes sense to subject matter experts who know how to fly a plane for real, and casual gamers who know nothing about flying or WW1.

One of the reasons the game works so well is the lever you’re given to pull is perfect. The game moves at the speed of your thoughts: you don’t have to pull the yoke and throttle and set the flaps correctly, you can’t “fail” to perform your action—the game is that your opponent isn’t sitting still while you do it.

You are in full control of this aircraft: it’s not like you pick “do you want to break left or right?” and then sit back and watch a cut scene of the dogfight where the next dozen decisions are made for you. There’s no system to beat your opponent at beating—and that is part of what makes this game endlessly re-playable.

When I talk about this game as a paper computer, it’s because you’re playing something much closer to a genuine flightsim than a board or card game.

And it turns out that the framing is the secret sauce to everything about this game.

It’s all about perspectives.

One of the big lessons to learn in programming for game design is that the visuals and the game state are not the same thing—the visuals at the front end isn’t necessarily driving how the back end works. Tetris has “falling” blocks but the game is not about gravity and “falling”, that’s just a visual representation of a time limit. (Not Tetris illustrates this point perfectly.)

Ace of Aces is doing something sneaky-clever in the background:

First of all, the game is secretly a hex-based game.

But Kit! You said this game was not like the other hex-based WW1 dogfighting games. And that’s true for the player 😉 and also true for the game, because yes, the game is using hexes, but not like Richtofen’s War or any other hex-based wargame.

In these games, the map is made of hexes. You have hex-based movement relative to a fixed point of reference—the topology of the map. The movement is absolute—the value itself matters.

Ace of Aces is using hexes, but there is no map. Movement is relative to your current position. The absolute value is irrelevant, the change in the value between one turn and the next is all that matters. This works because the game is first-person: the only thing that matters is where is the enemy relative to your current position. Not only is this the first-person perspective, but it’s what makes the system manageable in an analogue format—the first-person view of every possible relative position of the German aircraft from the Allied aircraft is 222…almost exactly the number of pages in the paired books (page 223 is the “ohnoes! You lost them” page).

If the German plane is dead ahead of you, it looks the same regardless of how you got here. If there were a map, the view of the aircraft would be the same whether the two aircraft where head-to-head over the field or the stand of trees or the country lane between them. If there was a map and the map actually mattered, the first-person perspective would require ~1,400 pages per map hex to show the appropriate landscape under both planes (223 unique relative positions of Allied and German aircraft, times the six unique orientations of the perspective aircraft relative to the map hex).

This trick of stationary player, moving world, is another reason why calling Ace of Aces a program feels right: this is how computer games work. Your monitor is a stationary window onto the game world that is moving relative to you. It’s an easy trick for the computer to pat its head and rub its stomach and have the dogfight happen in relative space—hexes that aren’t map hexes—while simultaneously moving the map beneath you as a separate calculation.

This relative frame of reference is also going to be familiar to anyone who has done old-school air-to-air lethality analysis: the endgame of a missile versus an aircraft doesn’t care about where they are in absolute space, just relative to each other—and in fact you especially don’t care about any permutation of endgame geometry where the missile isn’t on an intercept course with the aircraft (duh, it’s going to miss), so it was common to separate out the different computations of “do they intercept?” and “if they intercept, what’s the damage?”, the latter being stuffed into a lookup table that gives you the lethality that your six-degrees-of-freedom flightsim can call on. The frame of reference called GW372 is explicitly relative to the aircraft (or missile) being shot at. So, yes, Ace of Aces is a FORTRAN flightsim.

The other sneaky trick that Ace of Aces is doing comes back to the reciprocal perspectives again, but from another angle. Hold onto your hats, here comes the maths!

A Transformation Matrix is a magic number you can multiply by, to get from one position and rotation to another. It’s sort of like converting between degrees Celsius and Fahrenheit, or meters and kilometres—the transformation matrix is the “conversion factor” to teleport from a given position and rotation in the world to another.

Why that’s important is the magical property they have when our world position is not absolute, but relative:

Let’s say the Allied aircraft is at A, and the German aircraft is a G

And we say the transformation matrix of the Allied aircraft’s manoeuvre is a

And the transformation matrix of the German aircraft’s manoeuvre is g

Then Aga = Gag

That is, if we apply the enemy’s manoeuvre to ourselves, then do our manoeuvre, we end up at the correct position and rotation relative to the other aircraft, given our respective starting points and manoeuvres. And because the books are paired, that’s also the same page number: the books show the two aircraft in the same relative positions on any given page, just one book shows the view of that is from the German perspective and the other book is from the Allied perspective.

The clue to this is in that intermediate page: if you pay attention to the pictures, the page your opponent sends you to is literally showing you their aircraft’s movement relative to your current position, before you’ve taken your move.

You can tell because of another concept called the Identity Matrix: the transformation matrix that does no movement and no rotation—the “multiply by 1” or “add 0” equivalent. Because we’re not using the hexes for a map—because it’s relative movement, not absolute—there is a “no movement, no rotation” option, and if your opponent chooses it, they send you to…the page you’re currently on as the intermediate page, because no relative change in position or rotation! Remember the intermediate page shows you their movement relative to you while you’re not moving. And if you look up the Identity manoeuvre on any page it always says the page number that you’re currently on.

Ok but how on earth do you make a book that does this ?!?!

You can read the fairly obtuse patent here. It’s not particularly easy to parse, because of a lack of good diagrams and the generalisation to all possible interpretations of the IP, but I managed to unpick how it works and how to make my own paired-books. Hats off to Leonardi who did this (literally) with string, transparencies, and a banda machine. I ended up creating the tools to create my own paired-books as the by-product of trying to visualise the patent description.

The game takes place on a hex grid. Coordinate systems for hex grids are…interesting…but in this case we don’t need an x or y axis, we just need a notation system for each cell of the grid, and the six possible orientations an aircraft can have in any given cell. Leonardi’s system puts hex 0 at the centre, and winds the cell numbers clockwise from the top left. The orientations take a letter, and also wind clockwise from the top left.

Secretly, you start every turn at the centre of this grid in position 0A, the origin in this notation.

Plot showing a hex grid with the hexes numbered 0 to 6, wound clockwise, and each face of each hex labeled A to F also wound clockwise.

The enemy aircraft can be in any position and rotation on the grid, giving you all possible relative positions and rotations to each other. They have some relative position and rotation to you. Meanwhile they see themselves from position 0A and see you at the reciprocal of that relative position. That can make your brain ache a little.

The first thing to do is construct a list of the reciprocal positions: if you move the Allied aircraft to any given position and rotation on the grid, taking its frame of reference with, which cell position and rotation of the Allied aircraft’s grid is now at the “origin”. This is the kind of thing my brain finds extremely slippery, so I drew a picture—or, rather, I constructed the grid in Unity, wrote some code that let me set the position and rotation of the Allied aircraft, and asked Unity “hey, what cell number and letter is in that position now please?”

Screenshot of the above hex grid imposed on two vehicles with different positions and orientations.
(Well spotted: these are not aircraft 😉 more on that later.)

I did this initially so I could follow the example in the patent and set the Allied player to the position in the worked example and confirm what the obtuse language was even talking about. But, having written a script that lets me set the values by hand, it was a short step to writing a loop to iterate through all of them to read the result and write out the table to Excel. What you end up with is a somewhat symmetric result: when the enemy is in front of me, I am behind them. When they are to my east, I am to their west.

This is the key to determining the page number for any given relative position: you go through the list of all possible positions and rotations and assign each a unique page number for the Allied book. For each page in the Allied book, the reciprocal view in the German book shares that page number—so position 0B in the Allied book shares a page number with position 0F in the German book. This is easy to conceptualise if you iterate through the German positions and rotations in the same order as the Allied ones, but instead of copying the page number directly, you look up the Allied page number for the reciprocal position.

This has created you a lookup table for the correct page number for Allied and German relative positions on the hex grid. You can put it aside while we change gear to think about manoeuvring.

We know that the transformation matrices we need work independent of the other player, which is super-handy. It simplifies everything that follows to just thinking about one aircraft moving at a time.

How does a manoeuvre work ? You begin your turn at the origin. In purely mathematical terms, your available moves are to any other position and rotation on the grid, but in practical terms your aircraft is only so manoeuvrable. The allowed moves in Ace of Aces are:

Hex grid showing an aircraft and the hex position and direction destination for each of Ace of Ace's manoeuvre symbols.

This is how the manoeuvre symbols match the hex grid movement. You’ll notice it’s not entirely symmetric, because the torque of a rotary engine makes it much easier to turn and spin with the propeller, not against it. You can also tune “allowed” moves to match the capability of a particular aircraft (and that’s why there is a whole series of these books that you can use interchangeably in any Allied-German pair: the underlying reciprocal page numbers, hex grid and movement are the same, but some planes don’t have access to all the manoeuvres).

A particular manoeuvre will change your position and rotation by the same amount regardless of your starting position and rotation—the manoeuvre is a transformation matrix—and the Identity manoeuvre, that has zero change in position and rotation, is the clue to what happens next:

The intermediate page number for any given manoeuvre—the one you tell to your enemy—is the page number that corresponds to your destination taking that move from 0A. That destination encodes the movement of your aircraft relative to the origin in a transformation matrix that can be applied to your enemy to make it the movement relative to their current position and rotation. …if that makes your hair catch on fire, think about vectors and co-ordinates:

If you have a point (2, 4) that’s the same as having a vector—a line—that goes from position (0, 0) to position (2, 4). If I add another vector (3, 1) to this point, we’re taking the vector that goes from (0, 0) to (1, 3), moving it to put the (0, 0) at position (2, 4) and then drawing the line from (2, 4) to whatever position (2, 4) + (3, 1) is. The addition can happen in either order, we still end up at (5, 5).

Graph of the above vectors.

(This is literally the maths we’re doing to add an Allied aircraft manoeuvre to the German aircraft’s position. It is just 2D vectors, but because hex grid it’s ugly.)

What we need to do is construct a matrix of every possible position and rotation we could land at vs where the enemy could land at—this is easy to do in code by iterating through all combinations for each aircraft—and for each, reduce it to the corresponding unique situations in our first table. We only care about relative positions. This is what I mean when I say secretly the Allied aircraft starts every turn at 0A. That relative position is the intermediate page you’re going to send the enemy aircraft to, and you get the page number for it by looking it up in that first table.

What you end up with is this monster matrix of all possible intermediate destinations, and one strip of it is what you find at your intermediate destination: for a given actual manoeuvre your enemy chose, the row or column of your manoeuvres is the final destination for all the manoeuvres you could have chosen. If you go to the one for the manoeuvre you already told your enemy, then magically you both end up on the same page. Otherwise, the maths breaks, because you’re not applying the same transformation matrix to both aircraft.

Instead of Aga = Gag

You’ll have Agb =/= Gag

The page numbers won’t match because (in an absolute frame of reference) the Allied aircraft will be at 0A looking towards the German aircraft at (say) 5B, while the German aircraft will be at 9F looking towards the Allied aircraft at 0A. And if you both gave the other one manoeuvre and then performed a different one from your intermediate page, we’d have a situation where Agb =/= Gah.

In both these situations you get a view of the world (because that’s the nature of the book!) but it’s not reciprocal, which breaks everything about a relative frame of reference. Given this, isn’t it a brilliant idea to have the reciprocal positions have matching page numbers? The game contains its own parity check.

It would be entirely possible to make the paired-books where the relative positions don’t have matching page numbers, but you’d never know when the two hex positions were actually out of sync, you’d just be chasing your own tail with nonsense page turns.

This has made the manoeuvre table that’s common to both players. Leonardi did this by hand for all 222 permutations. Praise be for C#, which whips through all the combinations for me quicker than I can blink and writes them out to an Excel file.

This is all the possible moves; you can narrow it to only certain moves.

Certain permutations result in the two aircraft further apart than our little hex grid. These are the manoeuvres that will take you to that “ohnoes! You lost them” 223rd page. You’re out of range of the other aircraft.

A very large matix with some cells coloured red.
All possible moves for the Allied player across the top, German player down the side. Lost Contact at the red cells.

Next you need to convert the hex cell references (position and rotation) to the page numbers for the Allied player, and German player, using the first table as the look-up. That last bit using the reciprocal value for the German book is the thing that closes the loop on our transformation matrices, because remember we computed the whole table from the perspective of the Allied aircraft. Now with a reciprocal pair of tables, it works that you’re giving a page number to your enemy for your move, and they’re giving you a page number for their move. Honestly, the more I think about this, the more I’m blown away by Leonardi’s conception. It’s fiendishly clever.

The final step to make the books is to pair up the starting position page with the strip out of this matrix of possible intermediate pages. That’s where Leonardi had to put down the slide rule and start drawing pictures. 446 of them. But since I’m using Unity to move hex grids around to generate all these page numbers…why don’t I attach 3D objects to the grids and cameras and take a screenshot of each relative position while I’m working out its cell reference?

This is art: using a game engine to write a program to encode a program into paper computer. (I wonder if there’s a way to 3D print a game engine out of a paper computer…?)

Oh, and also: because I’ve automated this process, it takes…less than a second…to generate the pages of these books. And the same program can write the Excel spreadsheet that allows me to automate turning them into a hyperlinked pdf (it’s Turtles all the way down), which means I can easily generate more complicated grids than Ace of Aces. So I did.

Behold: Ace of U-boats:

The view from the deck of an Allied Corvette at night, with a surfaced U-boat on the starboard beam.
Open fire with the deck guns!
  • a 4-hex grid…
  • …with two layers for the U-boat—surfaced, or submerged
  • and (hold onto your hats) non-euclidean geometry: I cheated the hex grid scale at the different ranges because close-up you need to be working at a roughly-one-ships’-length scale (70 yards), but I want to play out to asdic ranges (3,500 yards) without having a gaziilion grid cells in between. Because we’re in relative geometry space, this totally works; the reciprocal distances are always self-consistent.

Also, I used minimap tricks to create the asdic screen for the screenshot, which feels like adding one more layer of inception: using a games engine to program a computer game to encode a program in a paper computer. If I can get Midjourney to play the game for me, I’m pretty sure there’ll be a phone call for Professor Falken.

The view from the deck of an Allied Corvette at night, nothing visible on the surface but an Asdic response on the starboard bow.
Contact! The Asdic always shows contacts relative to your ships’ orientation, but the look out view is looking in the direction of that contact. The indicator shows the relative bearing your looking towards, with 0deg being ahead of the ship (also, the stars are a fixed point of reference 😉)

But how can I apply this to games that aren’t 2-player first-person shooters?

A particularly rich vein of interesting maths for boardgames are nomograms: the paper version of cam-based mechanical computing. They are a close-cousin of slide rules (nomograms with moving parts) like the slide rule for general maths, the planimeter for integration (measuring the area under a graph), or for solving relative motion problems: the manoeuvring board, the Battenberg Course Indicator, and the U-boat Attack Disc.

They’re basically just a multi-dimensional look-up table—one that’s much easier to use than cross-referencing a bunch of look up tables (I’m looking at you, weapon vs armour class vs range charts!) Here’s a nice example from the Conduct of Anti-U-Boat operations in WW2:

Photo of a WW2 nomogram, titled "Search for submarine reported at a distance" and two graphs labelled approach diagram and sweeping diagram.
Suppose you are in command of an escort, and you get a report of a U-boat sighting. You want to steam over and then find the U-boat, obviously…but by the time you get there, the U-boat will have moved. The longer it takes you to arrive at its last-known location, the bigger the area you’ll need to search to find it. How big an area ? Well, that depends on how far away you are, how fast you travel, how long you wait before starting out…

Comments are closed.