Probabilities in the game of Risk

In the game of risk you have to make decisions whether to attack and whether to just save your armies in case someone attacks you. It would be helpful to know what the probability of winning or losing is in various situations.

Step 1. One dice roll

Click here to open a code that will make one dice roll per second

Step 2. Look at the code

Here is the code. Familiarize yourself with it.

Ntrials = 0;
Nwin = 0.0;

function draw() { 
  background(240); // light gray
  frameRate(1); // per second
  
  diceval1 = rollDie(); // random integers between 1 and 6
  
  print(diceval1);  
  drawText("Dice1 value = " + diceval1,0.05*width,0.9*height);

  Ntrials += 1.0; 
  
  if (1 > 0) { // Note: 1 > 0 is always true
     Nwin += 1.0;
  }
  winfrac = Nwin/Ntrials;
  print(winfrac);
  
  graph1.addPoint(100*winfrac);
  graph1.display();
  drawText("Ntrials = " + Ntrials,0.25*width,0.8*height);
}

Here is what this code will do when you run it. As you can see it's not that interesting because the "win" condition is 1 > 0 which is always true. As a result the probability of winning (100*winfrac) is 100%

Note: If you were wondering why it says diceval1 instead of just diceval it is because later we will introduce more dice and there will be variables diceval2, diceval3, etc.

Step 3. Show a 50% win probability

If you add the code below to your code it will draw a horizontal line to indicate a 50% win probability

  graph2.addPoint(50);
  graph2.display();

Now change the if statement to this:

if (diceval1 > 3) {
   Nwin += 1.0;
}

If you make these changes your code should behave like this. As you can see, the gray line is our best guess at what the win fraction is from the trials that we have done so far.

Explain why diceval1 > 3 should be true exactly 50% of the time?

Step 4. Impatience is a virtue!

Instead of rolling a dice once per second you can get the program to roll the dice 60 times a second by changing this line of code:

Change this:

frameRate(1); // per second

to this:

frameRate(60); 

If you make this change your code should behave like this

Note: This change causes the draw() function to run 60 times per second. It turns out that this is about as fast as it can go. If you put a number significantly above 60 in frameRate you will find that it doesn't really go any faster.

Run the program a few times! and notice that sometimes the win fraction starts at 100% and moves towards 50% and sometimes it starts at 0% and moves towards 50%. Why is this?

Step 5. Let's get tricky

Let's make a change to the if statement so the win fraction is something other than 50%.

For example, change diceval1 > 3 to something else like diceval1 < 2 or diceval1 > 4.

Or perhaps change the if statement so that the dice value is equal to some number (example: diceval1 == 6). Sometimes in a board game you get in situations where you have to roll a 6 or a 1 or something else in order to win.

Make this change, then do a calculation to figure out what the true win fraction should be! Then modify the graph2.addPoint(50) line of code so that it draws a line at the correct probability for whatever you modified the if statement to do.

Answers will vary, but the result might look something like this.

Do not just change the number for the horizontal line until it looks right! Think about the answer that you should get!

Step 6. The game of Risk, finally

The simplest scenario in the game of risk is when one player attacks another player and each player only has one army. According to the rules, the attacking player gets one dice and the defending player gets one dice. Whoever rolls the highest value will win the battle. If there is a tie, then the defender wins the battle.

Step 6a. Add a second dice to the program

Our program only has one dice. Go ahead and add another dice with this code:

  diceval2 = rollDie(); // random integers between 1 and 6
  print(diceval2);  
  drawText('Dice2 value = ' + diceval2,0.55*width,0.9*height);

Let's think of diceval1 as the attacking dice, and diceval2 as the defending dice.

Step 6b. Modify the if statement

Now modify the if statement so that if diceval1 is larger than diceval2 then it will be a "win", but if diceval1 is less than diceval2 or if they are equal it will not be a win.

Your code should behave like this if modify the if statement correctly

It would be nice to add a horizontal line to the screen so we can see how long it takes to produce the "true" probability. We could do this by trial and error, but instead lets think about the combinations.

Step 6c. Think about the combinations

When you roll two, six-sided dice there will be $6^2 = 36$ combinations. Unless the dice are weighted (in other words if someone is cheating) all 36 combinations are equally likely to occur. The question is how many of these combinations result in the attacking dice winning.

Note: Remember that if the dice are the same value then the defender wins!

Fill in this table for whether the attacker or defender wins. Write A if the attacker wins and D if the defender wins

Of the 36 combinations how many of these would the attacking die wien?

Step 6d. Show this probability in the code

Take the number of combinations where the attacker wins and divide it by 36 to get the win fraction. Then multiply by 100 to get the percentage. Then modify this line of code:

  graph2.addPoint(50);
  graph2.display();

So that instead of showing the 50% probability as a horizontal line it shows whatever percentage you just determined.

If you make this change your code should behave like this

Step 7. Should you attack?

Based on what you found, would you go ahead with the 1 dice versus 1 dice attack? Why?

Step 8. Two dice vs. one dice

You can increase your probability of winning by attacking the one die (one army) with two dice instead of one. If the defending dice is greater than or equal to the larger of the two attacking dice, then the defender wins. But if the defending dice is less than the larger of the two attacking dice, then it is a win for the attacker.

Note: In the real game, you can do two dice versus one dice, lose the first round and then do 1v1 and potentially win. Here we will just consider this first round. In the real game, if you lose the first round of 2 vs 1, you will probably be reluctant to do 1 vs 1 because the probability of winning is less than 50%.

Modify your code so that there are two attacking dice and one defending dice. This will involve adding another line with the function rollDie();. This function (rollDie()) should now appear three times in the program because there are a total three dice being thrown.

Advice #1: The function max(val1,val2) will return the larger of the two values. Use this to find the value

Advice #2: Set the horizontal line back to 50%. We want to know if two dice vs one dice is more than 50% likely to win.

If you do this correctly your code might behave like this

In this link we have re-labeled dice 1 and dice 2 as attacking die and dice 3 is the defending dice.

Optional Challenge: Step 9. Think about the combinations!

With three dice there are now $6^3 = 216$ combinations. How many of these have the attacking die winning? What does the win percentage work out to?

Step 10. Three dice vs. one dice

Modify the code so that there are three attacking dice and one defending dice. What is the probability of winning now?

Advice: With four dice involved this becomes nearly impossible to map out by hand, but if you want you can look at this nerdy write up about the probabilities in Risk to double check your answer.

Step 11. Reflection

Now that you know the probability of winning an attack with one two and three dice versus one dice defending, do you have any thoughts on how you might play the game differently? Attack less? Attack more? Use more dice to attack? Less dice? Is the 3rd dice worth it? In a complex game like this there are no definitively right answers to this question but think about what you've learned might affect the way you play the game.