First some basics about probabilities. The probability for a specific condition is the number of possible positive events for this condition divided by the total number of possible events. For example the probability to throw a with one 6-sided die is: one positive condition divided by six possible conditions, or 1/6 = 16.67%.

Calculating by Iteration

So if you want to calculate for example the chances of 2 attacking dice winning over 1 defending dice. You have 3 dice taking part. The total number of possible conditions that can happen are 6 possible events per dice for 3 dice. That are 6 * 6 * 6 = 216 possible events. Listing the events might look like this:

wins over a
wins over a
wins over a
...
wins over a
wins over a
wins over a
...
loses over a
wins over a
wins over a
...

For this situation, in 181 cases the attacker wins and in 35 cases the defender wins. Giving the attacker a winning chance of 181 / (181 + 35) = 83.8%

The following python script will use this iteration technique to calculate the table. This is the simple way without much brain power but using a lot of CPU power. In fact I don't think it will finish during a humans lifetime :-).

#!/usr/bin/pythondef add(x,y): return x+y;def iterate(dice, n):
win =0;# number of win conditions
los =0;# number of lose conditionswhile1:
if(reduce(add, dice[0:n])>reduce(add, dice[n:])): # add the left n dice as attackers, the remaining as defenders
win+=1;# if the attackers win, increment the winning conditionselse: # otherwise the lose conditions
los+=1;# now get the next possible die combination
dice[-1] +=1;# add one to the right most dietry: # we need to check if this die would be a "7"while1:
i = dice.index(7);# is there a 7 among the dice array?if(i ==0): # if the left most die is 7, we are finished with this iterationreturn100.0 * win / (win + los);# and can return the result.
dice[i]=1;# otherwise set the 7 to a 1
dice[i - 1] +=1;# and increment the dice left to it. keep checking for sevens.exceptValueError: # if index() does not find a 7 it raises this errorpass;# which can be ignored, go on with the next dice combination.for a inrange(2,9): # iterate through attacking number of dicefor d inrange(1,9): # iterate through defending number of diceprint a,"attackers", d,"defenders:",;
dice =[1] * (a + d);# create an array of dice to be thrown: attacker + defenderprint iterate(dice, a);# iterate through all possibilities of this array (1..6), add win / lose# conditions -> where wins divided by total possibilities is the result.

Note that from step to step it gets significantly slower as more dice are involved. You can press Ctrl+C now to interrupt it. There is a better way.

Calculating by Sums

Lets look at the example with 2 attacking dice and 1 defending die again. What are the possibilities of values the attacker can throw? We can write the 2 dice in a table. The sum of both dice are written in the fields.

2

3

4

5

6

7

3

4

5

6

7

8

4

5

6

7

8

9

5

6

7

8

9

10

6

7

8

9

10

11

7

8

9

10

11

12

You will notice that the attacker throwing a total of 7 is far more likely than throwing for example a total of 2. In fact there are 6 conditions for 7 with 36 possible conditions yielding a chance of 6/36 ... 16.67% throwing a seven. While there is only one possible condition to throw a 2, by two s yielding a chance of 1/36 ... 2.78%.

The number of conditions for the attacker to throw following sums can be easily counted on the table above. They are:

Total

Conditions

2

1

3

2

4

3

5

4

6

5

7

6

8

5

9

4

10

3

11

2

12

1

The defender still has only 6 possibilities. The conditions of attacker and defender can be illustrated by yet another table.

Defender

1

2

3

4

5

6

Conditions

1

1

1

1

1

1

Attacker

Conditions

Winner

2

1

attacker

defender

defender

defender

defender

defender

3

2

attacker

attacker

defender

defender

defender

defender

4

3

attacker

attacker

attacker

defender

defender

defender

5

4

attacker

attacker

attacker

attacker

defender

defender

6

5

attacker

attacker

attacker

attacker

attacker

defender

7

6

attacker

attacker

attacker

attacker

attacker

attacker

8

5

attacker

attacker

attacker

attacker

attacker

attacker

9

4

attacker

attacker

attacker

attacker

attacker

attacker

10

3

attacker

attacker

attacker

attacker

attacker

attacker

11

2

attacker

attacker

attacker

attacker

attacker

attacker

12

1

attacker

attacker

attacker

attacker

attacker

attacker

If the number of conditions is taken into account yielding each result and they are added, they will give 181 winning cases and 35 losing cases, just like before.

Similar table of attacker totals and defender totals for different number of dice can be constructed using the formula (8) from Weisstein, Eric W. (mathworld.wolfram.com):

Where: c is the total number of dice combinations that give a specific total p s is the number of sides of the dice, 6 in this case n is the number of dice thrown k is an iteration variable going from 0 to "floor" of (p - n)/s (floor means the next lower integer value)

With this formula all that has to be done, is the iterate over the possible defender totals, calculating how many combinations yield all possible totals while iterating over all possible defender totals. In each step look if the attacker wins (the attacker total > defender total) and add the number of combinations to either the count of winning or losing conditions. Number of winning conditions divided by total possible conditions yields the probability of an attacker success.

The following python script will calculate all the probabilities on a 2GHz machine in 1.9 seconds.

#!/usr/bin/pythonimportmath;
precision =1;# you can change this: number of decimals shown after commadef comb(n, k):
""" returns the number of combination of n elements taken k time. """global fact;return fact[n] / (fact[k] * fact[n - k]);def coef(n, p):
""" returns the number of rolls which sum is p of n 6-sided dice. """
kmax =int(math.floor((1.0 * p - n) / 6));
x =0;for k inrange(0, kmax + 1):
x +=pow(-1, k)* comb(n, k) * comb(p - 6 * k - 1, n - 1);return x;def chance(d, a):
""" returns the chance a attacking dice win over d defending dice. """
win =0;# number of attacker win conditions
los =0;# number of atracker lose conditionsfor ds inrange(d, d*6 + 1): # iterate over possible defender sumsforasinrange(a, a*6 + 1): # iterate over possible attacker sumsifas> ds:
win += coef(d, ds) * coef(a,as);# number of attack conditions winningelse:
los += coef(d, ds) * coef(a,as);# number of attack conditions losingreturn100.0 * win / (win + los);# precalculate factorials until 50 (higher bases are not going to be used)
fact =[0] * 50;
fact[0]=1;for i inrange(1,50):
fact[i]= fact[i-1]*i;# display the table head.print"def/att".rjust(8),;for a inrange(2,9):
printrepr(a).rjust(precision+4),;print;# iterate through the number of defender dicefor d inrange(1,9):
printrepr(d).rjust(8),;for a inrange(2,9): # iterate through the number of attacker diceprint('%'+str(4+precision)+'.'+str(precision)+'f')%(chance(d, a)),;print;

## Table of Contents

## Probabilities Basics

First some basics about probabilities. The probability for a specific condition is the number of possible positive events for this condition divided by the total number of possible events. For example the probability to throw a with one 6-sided die is: one positive condition divided by six possible conditions, or 1/6 = 16.67%.## Calculating by Iteration

So if you want to calculate for example the chances of 2 attacking dice winning over 1 defending dice. You have 3 dice taking part. The total number of possible conditions that can happen are 6 possible events per dice for 3 dice. That are 6 * 6 * 6 = 216 possible events. Listing the events might look like this:wins over a

wins over a

wins over a

...

wins over a

wins over a

wins over a

...

loses over a

wins over a

wins over a

...

For this situation, in 181 cases the attacker wins and in 35 cases the defender wins. Giving the attacker a winning chance of 181 / (181 + 35) = 83.8%

The following python script will use this iteration technique to calculate the table. This is the simple way without much brain power but using a lot of CPU power. In fact I don't think it will finish during a humans lifetime :-).

After some minutes following output can be seen:

Note that from step to step it gets significantly slower as more dice are involved. You can press Ctrl+C now to interrupt it. There is a better way.

## Calculating by Sums

Lets look at the example with 2 attacking dice and 1 defending die again. What are the possibilities of values the attacker can throw? We can write the 2 dice in a table. The sum of both dice are written in the fields.

The number of conditions for the attacker to throw following sums can be easily counted on the table above. They are:

TotalConditionsDefender123456Conditions111111AttackerConditionsWinner2132435465768594103112121Similar table of attacker totals and defender totals for different number of dice can be constructed using the formula (8) from Weisstein, Eric W. (mathworld.wolfram.com):

Where:

is the total number of dice combinations that give a specific totalcpis the number of sides of the dice, 6 in this casesis the number of dice thrownnis an iteration variable going from 0 to "floor" ofk(floor means the next lower integer value)(p - n)/sWith this formula all that has to be done, is the iterate over the possible defender totals, calculating how many combinations yield all possible totals while iterating over all possible defender totals. In each step look if the attacker wins (the attacker total > defender total) and add the number of combinations to either the count of winning or losing conditions. Number of winning conditions divided by total possible conditions yields the probability of an attacker success.

The following python script will calculate all the probabilities on a 2GHz machine in 1.9 seconds.

The output will look like this:

Or, if you are interested in more precision: