Dice Wars game

Dicewars

A simplified version of game DiceWars between two players goes such that each player is assigned a stack of 6-sided dice which equate to relative power. On a player’s turn, the player challenges other player. The challenge is resolved when each player rolls their dice, with the higher total winning.

Each player roll all of their dices and the value at the top of each dice is added to find the players score. Whoever has the higher score wins and the equal score is a tie. The goal is to find the probability that, in a game between two players with and dice respectively, any player wins over the other or there is a tie.

Before we calculate the probability of win or a draw, lets calculate the probability that a player with dices rolls a total of . Since for a standard dice the number on each face is one of . When the player rolls dices the minimum sum is when each dice rolls to be and a maximum of when each one rolls to be thus .

The total exhaustive cases of rolling dice is . The total possible ways we can get a sum of (subject to above constraint) when we roll dice is the same as the total number of ways we can write as a sum of integers such that each integer is between . The order of integers that we break the number is important too.

Lets us define a function such that it gives the total number of ways we can break into integers where each integer is one of

Because of the constraint we can immediately write

It is not hard to see the constraint

These are the edge cases we can identify because of constraints in hand. Before trying to find the function for general and lets try a special case.

For a special case of , i.e., the number of ways we can express as a sum of integers between and

We can write as a sum of integers as

or or or or or There are a total of ways we can do it. But if we want to express it as sum of integers then we can write the second integer as a sum of integer. Then the number of ways we can express as a sum of three integers becomes the sum of the number of ways we can express 6 as sum of 2 integers plus the number of ways we can write 5 as a sum of 2 integers and so on.

This leads us to write

This suggests us a general expression for

This is a recursive function the general expression for all then is

Below is a python function that calculates this function

def F(k,n,minno=1,maxno=6):
    if n < 1 or n < k:
        return 0
    if k == 1:
        return 0 if n > maxno else 1
    else:
        return sum([F(k-1,n-i) for i in np.arange(minno,maxno+1,1)])

The probability that we get a total of when we roll dice can then simply becomes

Where the denominator is the number of all possible ways of rolling dice.

Below is a python function that calculates this probability

def p(k,n,dice_op=np.arange(1,6+1,1)):
    return F(k,n)/len(dice_op)** k #len (dice_op) is just 6

Before we go to the game of win an draw lets see graphically how do the number look like. The plot below shows the count (left) and probability(right) of the sum (x-axis) when dice (inset) are rolled

def plot_counts(ms,dice_op=np.arange(1,6+1,1),plpr=False,ax=None):
    for m in ms:
        total_op = len(dice_op)**int(m)
        ns = np.arange(m,6*m+1,1)
        cnts = [F(m,n) for n in ns]
            
        pvl = np.array(cnts)/total_op if plpr else cnts
        ax.plot(pvl,'-o',label=f'm={m}')

    ax.legend()
fig,ax = plt.subplots(1,2,figsize=(18,6),sharex=True)
plot_counts([1,2,3,4],plpr=False,ax=ax[0])
plot_counts([1,2,3,4],plpr=True,ax=ax[1])
ax[0].set_xlabel('Sum'); ax[0].set_ylabel('Count')
ax[1].set_xlabel('Sum'); ax[1].set_ylabel('pmf');
plt.tight_layout()
plt.savefig('Prob_count',dpi=120,bbox_inches='tight')

image

Probability of tie

The pobability of tie in a game of two players throwing and die respectively is simply the probability that they roll the same sum. The set of possible sum of player with k die is

𝑁1={𝑛𝑖|𝑘𝑛𝑖6𝑘}

Similarly for other player

𝑁2={𝑛𝑖|𝑚𝑛𝑖6𝑚}

Which can be easily written as

𝑝(tie)=𝑛=𝑁1𝑁2𝑝(𝑘,𝑛)𝑝(𝑚,𝑛)

The python function for this written as

def get_tie_prob(m,k):
    n1 = np.arange(m,6*m+1,1)
    n2 = np.arange(k,6*k+1,1)
    return sum([p(m,n)*p(k,n) for n in n1 if n in n2])

I have this helper function that calculates generates the table of values.

def generate_table(ms,ks,func=get_tie_prob):
    prob_table = np.zeros(shape=(len(ms),len(ks)))
    for m in ms:
        for k in ks:
            prob_table[m-1][k-1] = func(m,k)
    df = pd.DataFrame(prob_table,columns=ms,index=ks)
    return df

Lets say 𝑚𝑠 is the set of number of dice player1 has and 𝑘𝑠 be the number of dice playe 2 has then

maxn=6
ms = ks = np.arange(1,maxn+1,1)
%time tie_prob_table = generate_table(ms,ks,get_tie_prob)
CPU times: user 2.29 s, sys: 18.3 ms, total: 2.31 s
Wall time: 2.29 s
tie_prob_table
1 2 3 4 5 6
1 0.166667 0.069444 0.015432 0.001929 0.000129 0.000004
2 0.069444 0.112654 0.069444 0.024884 0.005955 0.001017
3 0.015432 0.069444 0.092850 0.065469 0.029940 0.009822
4 0.001929 0.024884 0.065469 0.080944 0.061479 0.032624
5 0.000129 0.005955 0.029940 0.061479 0.072693 0.057935
6 0.000004 0.001017 0.009822 0.032624 0.057935 0.066539

The probability of tie when players have (𝑚,𝑘) dice respectively corresponds to the cell (𝑚,𝑘) in the table above.

The probability for win

Similarly the probability of win for player with 𝑚 dice is the probability that the player 𝑘 throws a sum 𝑖 times the sum of probabilities of ways player 𝑚 throws 𝑗 dice such 𝑗 >𝑖

𝑜(win)=𝑖=𝑁2𝑝(𝑘,𝑖)(𝑗𝑁1;𝑗>𝑖𝑝(𝑚,𝑗))

The python function implementing this function is

def get_win_prob(m,k):
    if m > k:
        wkm = get_win_prob(k,m)
        tkm = get_tie_prob(k,m)
        return  1 - wkm - tkm
    n1s = np.arange(m,6*m+1,1)
    n2s = np.arange(k,6*k+1,1)
    
    win_prob = sum([p(k,i) * sum([p(m,j) for j in n1s if j > i]) for i in n2s])
    
    return win_prob

Generating the table

%time win_prob_table = generate_table(ms,ks,get_win_prob)
CPU times: user 18.9 s, sys: 152 ms, total: 19 s
Wall time: 18.9 s
win_prob_table
1 2 3 4 5 6
1 0.416667 0.092593 0.011574 0.000772 0.000021 0.000000
2 0.837963 0.443673 0.152006 0.035880 0.006105 0.000766
3 0.972994 0.778549 0.453575 0.191701 0.060713 0.014879
4 0.997299 0.939236 0.742831 0.459528 0.220442 0.083423
5 0.999850 0.987940 0.909347 0.718078 0.463654 0.242449
6 0.999996 0.998217 0.975300 0.883953 0.699616 0.466731

The probability of win for player 𝑚 when players have (𝑚,𝑘) dice respectively corresponds to the cell (𝑚,𝑘) in the table above.