RISK Statistics

Probabilities for a single round

The following table shows the probabilities related to throwing the dice for a single round of an attack (i.e. a single throw of the dice). The results are given in the form
defender loses / 1 each / attacker loses
Percentages are rounded to the nearest percent point.

3 Dice Attacking 2 Dice Attacking 1 Die Attacking
2 Dice Defending 37% / 34% / 29% 23% / 32% / 45% 25% / 75%
1 Die Defending 66% / 34% 58% / 42% 42% / 58%

Python code
import itertools
from enum import Enum


class Outcome(Enum):
    ATT_LOSES = 0
    DEF_LOSES = 1
    ONE_EACH = 2


def eval_roll(attack_dice, defense_dice):
    attack_dice_sorted = tuple(sorted(attack_dice, reverse=True))
    defense_dice_sorted = tuple(sorted(defense_dice, reverse=True))
    att_loses = def_loses = 0
    num_comparisons = min(len(attack_dice), len(defense_dice))
    for i in range(num_comparisons):
        if attack_dice_sorted[i] > defense_dice_sorted[i]:
            def_loses += 1
        else:
            att_loses += 1
    if att_loses == num_comparisons:
        return Outcome.ATT_LOSES
    elif def_loses == num_comparisons:
        return Outcome.DEF_LOSES
    else:
        return Outcome.ONE_EACH


def calculate_roll_probabilities(num_attack_dice, num_defense_dice):
    total_num_dice = num_attack_dice + num_defense_dice
    roll_combinations = list(itertools.product(range(1, 7), repeat=total_num_dice))
    num_rolls = len(roll_combinations)
    roll_results = {}
    for combination in roll_combinations:
        attack_dice = combination[:num_attack_dice]
        defense_dice = combination[num_attack_dice:]
        outcome = eval_roll(attack_dice, defense_dice)
        if outcome.name in roll_results:
            roll_results[outcome.name] += 1
        else:
            roll_results[outcome.name] = 1
    for outcome in roll_results:
        roll_results[outcome] = roll_results[outcome] / num_rolls * 100
    return roll_results


dice_num_combinations = list(itertools.product(range(1, 4), range(1, 3)))
for dice_combo in dice_num_combinations:
    results = calculate_roll_probabilities(dice_combo[0], dice_combo[1])
    print(f'A: {dice_combo[0]} - D: {dice_combo[1]} ==> {results}')
      

Probabilities for a battle

The following graph shows the probability of an attacker beating a defender given a certain number of attacking and defending units. Note that the table does not take into account the attacker that stays behind to hold the territory.

These values were not calculated theoretically but through simulation. A program ran 10000 battle simulations for each combination of attackers and defenders, and counted how many of them won. The built-in assumption is that every battle runs until one of the armies is wiped out. Of course, in the game, players often decide to break off battles before they reach the end if they turn out to be unfavorable, and that is not captured in these values.

The more the square is red, the more the attacker is favored. The more it is blue, the more the defender is favored.

Attacker win probability graph

Some interesting things to note are