### About

Date: 2017-08-19### Contents

# Risk Analysis for Risk¶

## Motivation¶

In 2011 I was on vacation with friends, we played a lot of Risk. Somehow we ended up having fights of hundreds of armies against each other. Since with every dice rolling you can only eliminate up to three armies, you need a lot of rounds until a battle is settled. While my friends were occupied in a battle of 200 against 150, I used my freshly acquired Python skills to write a program to do the dice rolling, risk-auto-dice.

The program does exactly what the players do until one player runs out of armies:

- The attacker rolls up to three dice, the defender up to two. The number of dice cannot exceed the number of armies. In the game a player can choose to use less dice, the program uses the maximum amount.
- The results are ordered descending and paired up. For every pair which is unequal, the person with the lower number loses one unit.

At first, the program would only output the end result. The result turned out to be extremely unstable, a 100 vs 100 fight could end with either side having 50 armies left. If one re-ran the program, the result was completely different. At the time, we just accepted this as an intrinsic quirk of the game that gave it its name.

## Revisiting the Problem¶

Now, six years later, I learned more about statistics. So I looked at this
again. For this article, I have implemented the dice rolling function in R
because I currently learn that language. The `fight`

function is not very
complicated:

```
sorted.roll <- function(number) {
sort(sample(1:6, number, replace = TRUE), decreasing = TRUE)
}
fight <- function(attacking, defending) {
armies.att <- attacking
armies.def <- defending
# Risk has “last man standing” fights, therefore
while (armies.att > 0 && armies.def > 0) {
# The number of dice that can be used is capped to 3 and 2.
dice.att <- min(armies.att, 3)
dice.def <- min(armies.def, 2, dice.att)
dice.both <- min(dice.att, dice.def)
# Roll the dice.
roll.att <- sorted.roll(dice.att)
roll.def <- sorted.roll(dice.def)
# Match the pairs and adjust the number of armies left.
for (i in 1:dice.both) {
# The attacker has won a single battle, therefore the defender
# loses a die.
if (roll.att[i] > roll.def[i]) {
armies.def <- armies.def - 1
}
# The defender has scored.
else if (roll.att[i] < roll.def[i]) {
armies.att <- armies.att - 1
}
}
}
return (list(attacker = armies.att,
defender = armies.def,
diff = armies.att - armies.def))
}
```

## Analysis¶

I have run it 300 times for each configuration of up to 25 armies. The whole implementation is not really fast, therefore this already took several minutes to run through. For a more sophisticated analysis one should probably re-implement this in C++ and use OpenMP to get some more speed. The amount of data generated seems to sufficiently see the trend, there is no indication that beyond 25 armies something qualitatively different will happen.

### Winning Chance¶

The mean number of armies that the attacker has left after the battle, is plotted here:

Qualitatively, this is not too surprising. The bigger the advantage was before, the more armies will be left afterwards. However, the sides are not equal. Take a look at the point 10–10 for instance. It has the same color as 6–1. This suggests that the chance of winning is skewed towards the attacker.

We can just have a look at the ratio of battles which are won:

The slope of the boundary is rather step, the attacker clearly is in advantage. In the 10– 10 case, the change of winning is rather high, one can be pretty certain to win. When the same number of armies fight against each other, usually the attacker wins.

One can have a look at the surviving armies of the attacker normalized by armies put into the battle, this is a survival rate:

Interestingly, the 50% line has unit slope, so when both players have the same amounts of armies, the survival rate of the attacker’s armies is still 50%. Of course to win one only needs to have a single unit left, therefore the ratio of won battles has a larger slope.

### Fluctuations¶

But there were those great fluctuations. If we look at the standard deviation of armies left, we see the following:

On the bottom and on the left, there are no fluctuations. This is no surprise because these situations correspond to a near-certain victory or defeat. The fluctuations look rather symmetric. But that does not really tell much about the risk that one is taking in each battle.

So let’s have a look at the 1% quantile of the attacker’s armies that are left after the battle. I have chosen 1% instead of 0% because that should be somewhat stable against outliers whereas 0% will by definition be the most extreme outlier.

Most of the chart corresponds to a defeat, zero armies left. For low numbers it is skewed towards the defender, it you want to be almost completely certain to win, you will need to have at least four armies to defeat a single one. For large number of armies, it seems to become more even again. One could draw the line such that the chance of losing is very low. One would need more statistics here in order to get a better resolution because 300 samples are not going to give a very good 1% quantile.

In a game called “Risk”, one cannot be that conservative. Therefore let’s have a look at the 30% quantile:

For very low numbers, the defender has the advantage. This changes at around 5–5, where the attacker has the advantage again.

The median (50% quantile) looks pretty good for the attacker:

If you want to hedge your bets on something that will work out worse in 70% of the cases, you can have a look at the following chart:

The best cases that could happen (only 1% even better) look like this:

With three armies, one has a slim chance of winning against a defender with 17 armies. In the best case scenario, the number of defending armies only has weak impact on the result. This can be seen through the pretty vertical slope of the color boundaries in the plots. That should be compared to the worst case, where the slopes are only down to unity.