Risk Legacy is a campaign version of Risk. It plays like a house-rules version of Risk initially, but the game changes dramatically over time as players customize it. Not only do players write on the board and put terrain-altering stickers and notes on the board, but the various factions have special abilities that change as well. There are also a number of packets marked “open when [condition] occurs”, which include instructions to change the game even further (such as alterations to the rules). It’s a wild ride.
The basic rules for Risk Legacy combat go like this:
- The attacker may attack with 1, 2, or 3 troops (assuming they have that many available to move into the territory, should they succeed).
- The defender may defend with 1 or 2 troops (assuming they have that many in the territory).
- The attacker rolls 1-3 dice appropriately.
- The defender rolls 1 or 2 dice appropriately.
- Both the attacker and the defender line the dice up in order, from highest to lowest.
- Compare the two highest dice. If the attacker’s die is higher than the defender’s, the attacker wins. Otherwise, the defender wins (so defender wins on ties).
- (if applicable) Compare the second-highest dice. Same rules on winning.
- One troop is destroyed for each of the owner’s losses.
- If the defender has no troops left, the attacker wins.
- If the attacker hasn’t won, they may either rinse and repeat or back off.
While playing Risk Legacy on Sunday, I noticed that my friend would only use one troop to defend, even when they had more than one available. “What’s up with that?”
“If you only defend with one troop, you’re only risking one troop, so your chances are better.”
I was confident that my friend was wrong, but I couldn’t remember the formulas to prove it with the probabilities. (I also had the gut feeling that the game designers wouldn’t set you up to shoot yourself in the foot, since – in my friend’s scenario – there would never be a good reason to use two troops instead of one. But “It would be better game design if I’m right” is not a convincing argument. Even when “game designer” is on your business cards.)
I was still thinking about this when I got home. I could have looked up the math, and that might have been a more sensible approach – but instead, I wrote a program to demonstrate it through play.
I didn’t write this with Inform 7, but I certainly could have. Parser languages excel at modeling the physical world (it’s the heart of parser, after all!) My approach would have been something like (in a very broad overview):
- Dice are a kind of object. A die can be black or red (assigning it to the attacker or defender).
- Rolling is an action applying to nothing. “Roll” will roll all the dice in your inventory.
- The “carry out” for rolling does the battle math – put a random 1d6 on each die, separate dice by color and sort them in order, then compare highest to highest, compare second highest to second highest, etc, etc.
- The chalkboard is a thing. Examining the chalkboard shows how many troops are left. Update the chalkboard’s information at the end of rolling the dice.
- Roll-repeat is an action applying to one value. “Roll N times” will roll all the dice in your inventory N times, probably with some messaging suppression to avoid massive scroll.
The play experience here would be: pick up some dice, roll them a lot of times, then admire the results on the chalkboard.
I opted for C# over I7 because I wanted to iterate over thousands of rolls. I7 could do that, but it would take longer, since I7 would be handling the entire world model. (Also, I7 remains my strongest language, so I opt for C# whenever it’s reasonable. Carnegie Hall approach.)
My C# version is structured instead like this:
- A die (a Dice, actually) is an object. A die knows its last roll. A die can roll or be compared to a defending die to figure out which last roll was higher.
- A battle is an object. A battle can fight. When a battle fights, it runs the entire Risk Legacy combat process – pick the number of dice, create the dice, decide how many times to roll the dice, and then roll/compare/destroy troops that many times before reporting results.
Effectively, the program is handling some of the sequencing that the player would have been responsible for in the I7 version. So here, the user just enters the number of dice and the number of repetitions, and the program does the rest.
The C# source is up on GitHub, if you’d like to take a look. But if you’d rather just know the results…
(Datta and an incredibly small spoiler below the image.)
I set up these examples with 100,000 troops on each side at the beginning. The left result is “how many attackers were left at the end” and the right result is “how many defenders were left at the end”.
- Attack 1, Defend 1: none, 28769
- Attack 2, Defend 1: 26858, none
- Attack 3, Defend 1: 48447, none
- Attack 2, Defend 2: none, 35,657
- Attack 3, Defend 2: 15225, none
- Attack 3, Defend 2 with bunker (+1 to highest die, not to go above 6): none, 20505
- Attack 3, Defend 2 with ammo shortage (-1 to highest die, not to go below 1): 48817, none
If you rerun this, your mileage may vary a little – random seeds do, after all. But it’s clear that, while the lone troop standing against the horde is dramatic, it’s not as effective as two troops fighting together.
Also, ammo shortages are so much worse than I realized. And at this point in our campaign, the map is littered with ammo shortages, but the Enclave of the Bear is Well-Supplied, and therefore immune to ammo shortages. I think I know what faction I want next time….