31 Aug 2019

# The Average of 4d6 Drop lowest

The outside sky was dark; a cold wind blew in under the door, making me pull my jacket across my chest and wish that I hadn't taken my coat off when I came into my friend's house. "Roll four six sided dice and add up the highest 3. Do that 6 times and they're your stats" my friend told me. As I did what he asked I couldn't help but wonder what that was likely to give me. The average of 3d6 (three six sided dice) is $$3.5 \times 3 = 10.5$$ so we settled on "Probably about 13ish?" and didn't think about it.

But that approximation never really sat right with me. The average is higher than the average of 3d6 (denoted $$\overline{3d6}$$) as the lowest result is always removed, it's also obviously lower than $$\overline{4d6}$$ so our result must be $$\overline{3d6} < x < \overline{4d6}$$.

I spent some time wondering if I could sample a normal distribution of dice and somehow calculate the lowest average roll of a set of 4 dice and subtract that from $$\overline{4d6}$$. Then I remembered I'm not a mathematician and I didn't really understand half of the words in the last sentence. I decided to play to my strengths and take a brute force approach.

## Brute Force and Ignorance

I wrote the following code that simulates 4d6 drop lowest 100,000 times and calculates the average. It can be run in the Rust playground here

use rand::Rng;

fn roll() -> u64 {
let mut rolls: Vec<_> = (0..4).map(|_| rng.gen_range(1, 7)).collect();
rolls.sort();
rolls.into_iter().skip(1).sum()
}

/// Count occurances of each roll in the results
fn count(vec: &Vec<u64>) -> Vec<(u8, usize)> {
let mut count = [0usize; 19];

for item in vec.iter() {
count[*item as usize] += 1;
}

count
.into_iter()
.enumerate()
.skip(3)
.map(|(num, count)| (num as u8, *count))
.collect()
}

fn main() {
let amount = 100_000;

let rolls: Vec<_> = (0..amount).map(|_| roll()).collect();

let total = rolls.iter().sum::<u64>();
let average = total as f64 / amount as f64;

println!("Average {}", average);
for (no, count) in count(&rolls) {
println!("{}:{}", no, count);
}
}


Average 12.23731
3:64
4:334
5:810
6:1629
7:2948
8:4777
9:7017
10:9495
11:11410
12:12835
13:13322
14:12158
15:10122
16:7270
17:4216
18:1593


According to this the average is just over 12 with the most common result being 13.

## The Hard Way

total rolls = 6 ^ 4 = 1296