4 min read

Running Total of a Die

Table of Contents

Problem

An ordinary die is rolled until the running total of the rolls first exceeds 1212. What is the most likely final total that will be obtained?

Solution 1

The first solution approach is quite straightforward. We just use Monte Carlo simulation to estimate the required probability. From the graph below we can see that the final total is most likely to be 1313 with a probability of ≈28%\approx 28\%.

import numpy as np
import matplotlib.pyplot as plt

def monte_carlo_simulation(n=100000):
    results = []
    for _ in range(n):
        sum_ = 0
        while sum_ <= 12:
            sum_ += np.random.randint(1, 7)  # Roll a die
        results.append(sum_)
    return results

def calculate_probabilities(results):
    probabilities = {i: results.count(i) / len(results) for i in range(13, 19)}
    return probabilities

def plot_probabilities(probabilities):
    labels = probabilities.keys()
    values = probabilities.values()

    fig, ax = plt.subplots()
    bars = ax.bar(labels, values, color='skyblue')

    ax.set_xlabel('Sum')
    ax.set_ylabel('Probability')
    ax.set_title('Probabilities of Getting Sums from 13 to 18')
    
    for bar in bars:
        height = bar.get_height()
        ax.annotate(f'{height:.2f}',
                    xy=(bar.get_x() + bar.get_width() / 2, height),
                    xytext=(0, 3),  # 3 points vertical offset
                    textcoords="offset points",
                    ha='center', va='bottom')

    plt.show()

n_simulations = 100000
results = monte_carlo_simulation(n=n_simulations)
probabilities = calculate_probabilities(results)
plot_probabilities(probabilities)

Solution 2

The second approach is much more interesting. We can count the number of ways of arriving at a total between 1313 and 1818 such that every number involved in the sum is less than or equal to six and the running total till the second last number is less than or equal to 1212. E.g. 8+4+28+4+2 is a valid way to reach 1414 but not 8+5+18+5+1 because once you have 8+58+5 you have exceed 1212 already. We make use of the concept of partitions (a partition of a non-negative integer nn, also called an integer partition, is a way of writing nn as a sum of positive integers). If we denote by p(n,k)p(n,k) the partition of nn where each number of the partition does not exceed kk, then the number of ways of reaching numbers 1313 to 1818 is given in the table below:

TotalCount
13p(13,6)
14p(8,6) + p(9,6) + p(10,6) + p(11,6) + p(12,6)
15p(9,6) + p(10,6) + p(11,6) + p(12,6)
16p(10,6) + p(11,6) + p(12,6)
17p(11,6) + p(12,6)
18p(12,6)

From the table it is easy to see that the probability of reaching 1414 is higher than the probability of reaching the numbers 1515 to 1818. We need to compare ∑i=812p(i,6)\sum_{i=8}^{12} p(i,6) with p(13,6)p(13,6) to confirm whether 1313 or 1414 is more likely. Using the code below we see that probability of reaching 1313 is ≈28%\approx 28\% and 1414 is ≈24%\approx 24\%.

def generate_partitions(number, max_part=6):
    def recurse(target, max_part, current_partition):
        # Base case: when the target number is 0, yield the current partition
        if target == 0:
            yield list(current_partition)
        else:
            # Start from the last part used or max_part, whichever is smaller
            start = min(max_part, target)
            for next_part in range(start, 0, -1):
                # Append next part and recurse
                yield from recurse(target - next_part, next_part, current_partition + [next_part])

    return list(recurse(number, max_part, []))

def calculate_probability(number):
    from collections import Counter
    from math import factorial
    def partition_probability(partition):
        counter = Counter(partition)
        l = len(partition)
        num = factorial(l)
        for _,cnt in counter.items():
            num = num * 1/factorial(cnt)
        return num/6**l

    partitions = generate_partitions(number)
    total_probability = sum(partition_probability(p)  for p in partitions)
    return round(total_probability, 2)

print(f"Total probability for 13:", calculate_probability(13))

prob = 0
for n in range(8,13):
    prob += calculate_probability(n)/6
print(f"Total probability for 14:", prob)