rec.puzzles Archive

What are the odds when tossing dice in Risk?

competition/games/risk

Problem

What are the odds when tossing dice in Risk?
Show solution
Odds calculated with program by David Karr (karr@cs.cornell.edu):

Attacker rolls 3 dice, defender rolls 2 dice:

Attacker   Defender   Probability
  loses      loses
    0          2       2890/7776  =  0.3716563786
    1          1       2611/7776  =  0.3357767490
    2          0       2275/7776  =  0.2925668724


Attacker rolls 3 dice, defender rolls 1 dice:

Attacker   Defender   Probability
  loses      loses
    0          1        855/1296  =  0.6597222222
    1          0        441/1296  =  0.3402777778


Attacker rolls 2 dice, defender rolls 2 dice:

Attacker   Defender   Probability
  loses      loses
    0          2        295/1296  =  0.2276234568
    1          1        420/1296  =  0.3240740741
    2          0        581/1296  =  0.4483024691


Attacker rolls 2 dice, defender rolls 1 dice:

Attacker   Defender   Probability
  loses      loses
    0          1        125/216  =  0.5787037037
    1          0         91/216  =  0.4212962963


Attacker rolls 1 dice, defender rolls 2 dice:

Attacker   Defender   Probability
  loses      loses
    0          1         55/216  =  0.2546296296
    1          0        161/216  =  0.7453703704


Attacker rolls 1 dice, defender rolls 1 dice:

Attacker   Defender   Probability
  loses      loses
    0          1         15/36  =  0.4166666667
    1          0         21/36  =  0.5833333333


---------------------8<------snip here--------8<--------------------
/*
 * riskdice.c  --  prints Risk dice odds
 *
 * This program calculates probabilities for one roll of the dice in Risk.
 * For each possible number of dice that the attacker might roll, for each
 * possible number of dice that the defender might roll, this program
 * lists all the possible outcomes (number of armies lost by attacker
 * and defender) and the probability of each outcome.
 *
 * Copyright 1993 by David A. Karr.
 */

#define MAX_ATTACK        3        /* max # of dice attacker may roll */
#define MAX_DEFEND        2        /* max # of dice defender may roll */
#define MAX_DICE        MAX_ATTACK + MAX_DEFEND

void main()
{
    int a;        /* number of dice rolled by attacker */
    int d;        /* number of dice rolled by defender */
    void calc();

    for (a = MAX_ATTACK; a > 0; --a) {
            for (d = MAX_DEFEND; d > 0; --d) {
            calc( a, d );
        }
    }
}

void calc( a_dice, d_dice )
/*
 * Purpose:  Print odds for the given numbers of dice rolled
 */
int a_dice;        /* number of dice rolled by attacker */
int d_dice;        /* number of dice rolled by defender */
{
    int num_dice;        /* total number of dice rolled */
    int num_armies;        /* # armies that will be lost by both sides, total */
    int kill_count[MAX_DEFEND + 1];
                /* entry [i] counts # of times attacker loses i armies */
    int roll[MAX_DICE + 1];        /* holds one roll of the dice */
    int a_roll[MAX_ATTACK];        /* holds attacker's dice */
    int d_roll[MAX_DEFEND];        /* holds defender's dice */
    int n;                /* cursor into the arrays */
    int num_lost;        /* # of armies lost by the attacker */
    int cases;                /* total # of events counted */
    void dsort();

    /*
     * The method is pure brute force.  roll[] is set successively to
     * all possible rolls of the total number of dice; for each roll
     * the number of armies lost by the attacker (the outcome) is
     * computed and the event is counted.
     * Since all the counted events are equiprobable, the count of each
     * outcome merely needs to be scaled down by the total count to
     * obtain the probability of that outcome.
     */
    /* The number of armies at stake is  min(a_dice, d_dice) */
    num_armies = a_dice < d_dice ? a_dice : d_dice;
    /* initialize event counters */
    for (n = 0; n <= num_armies; ++n)
            kill_count[n] = 0;
    /*
     * The roll[] array is treated as a funny odometer whose wheels each
     * go from 1 to 6.  Each roll of the dice appears in roll[0] through
     * roll[num_dice - 1], starting with all 1s and counting up to all 6s.
     * roll[num_dice] is used to detect when the other digits have
     * finished a complete cycle (it is tripped when they go back to 1s).
     */
    num_dice = a_dice + d_dice;
    for (n = 0; n <= num_dice; ++n)
            roll[n] = 1;
    while (roll[num_dice] == 1) {
            /* examine a new possible roll of the dice */
        /*
         * copy attacker's and defender's dice so as not to disturb
         * the "odometer" reading.
         */
        for (n = 0; n < a_dice; ++n)
            a_roll[n] = roll[n];
        for (n = 0; n < d_dice; ++n)
            d_roll[n] = roll[n + a_dice];
        /*
         * sort attacker's and defender's dice, highest first.
         */
        dsort(a_roll, a_dice);
        dsort(d_roll, d_dice);
        /*
         * compare attacker's and defender's dice, count attacker's loss
         */
        num_lost = 0;
        for (n = 0; n < num_armies; ++n)
            if (d_roll[n] >= a_roll[n]) 
                    ++num_lost;
        ++kill_count[num_lost];
            /*
         * Find next roll values (bump the "odometer" up one tick).
         */
        n = 0;
        roll[0] += 1;
        while (roll[n] > 6) {
            /* place [n] rolled over */
            roll[n] = 1;
            /* Carry 1 into the next place (which may in turn roll over) */
            ++n;
            roll[n] += 1;
        }
    }
    cases = 0;
    for (n = 0; n <= num_armies; ++n)
        cases += kill_count[n];
    printf( "Attacker rolls %d dice, defender rolls %d dice:\n\n",
                a_dice, d_dice );
    printf( "Attacker   Defender   Probability\n" );
    printf( "  loses      loses\n" );
    for (n = 0; n <= num_armies; ++n)
        printf( "%5d      %5d      %5d/%d  =  %12.10lf\n",
                n, num_armies - n, kill_count[n], cases,
                ((double) kill_count[n]) / ((double) cases) );
    printf( "\n\n" );
}


void dsort( array, length )
/*
 * Sort the given array in descending order.
 */
int *array;
int length;        /* number of slots in the array */
{
    int level, n, tmp;

    /* Use bubble sort since the array will be tiny in this application */
    for (level = 0; level < length - 1; ++level) {
        /*
         * Slots [0] through [level - 1] are already "stable."
         * Bubble up the value that belongs in the [level] slot.
         */
        for (n = length - 1; n > level; --n) {
            if (array[n - 1] < array[n]) {
                /* swap them */
                tmp = array[n - 1];
                array[n - 1] = array[n];
                array[n] = tmp;
            }
        }
    }
}