Well, my Dungeons and Dragon’s character, Ollie Oxenfree, was killed over the weekend. A blood golumn got him. We were all very sad.
Anyhow, I got to roll a new character. D&D characters are based on 6 numerical values that are randomly generated by adding together the numbers on three dice. Thus the mimimum score is 3 and the maximum score is 18. There are other ways of getting random numbers between 3 and 18 — for example you could roll a four sided die five times and subtract two. Or you could roll a sixteen sided die and add two. Here is a graph of how likely different rolls are depending on which die/dice you used:
Notice how the more dice you use, the tighter the bell curve appears. You have less than a 1% chance of rolling an 18 (or a 3) and a 12.5% chance of rolling a 10 or 11. For the kind of profession I wanted for my new character (two professions: “Ranger” and “Druid”), I needed at a minimum to roll these scores or higher: 3, 13, 13, 14, 14, 15.
But before I got my hopes up that my character would be able to take on these two professions, I wondered just how likely I was to be able to roll such high scores. I tackled this problem two ways: with a random “monte carlo” simulation, and using statistical analysis.
For the monte carlo simulation, I wrote a perl script that randomly generated scores using a simulated die. It then determined if the rolls met my minimum criteria. After 1000 rolls, it reported the fraction of rolls that were adequate. I had it calculate scores for Ranger+Druid, Ranger only, Druid only, all 3s and all 18s. I know that all 3s or better should be probability of 1 (you always roll a 3 or better). Also, the all 18s should be pretty unlikely (it might not even roll a single one). For those of you following along at home, here is the perl script for this:
@scores = (
[ 3, 13, 13, 14, 14, 15 ],
[ 3, 3, 13, 13, 14, 14 ],
[ 3, 3, 3, 12, 13, 15 ],
[ 3, 3, 3, 3, 3, 3 ],
[ 18, 18, 18, 18, 18, 18 ],
[ 3, 3, 3, 3, 3, 18 ],
);
foreach $scoresRef (@scores) {
$right = 0;
foreach $i (1..10000) {
my @guess = ();
foreach $b (0..5) {
$guess[$b] = 0;
foreach $a (1..3) {
$guess[$b] += int(1+rand(5.9999999));
}
}
@guess = sort(@guess);
my $itsright = 1;
foreach $b (0..5) {
$z = $guess[$b];
if ($z < $$scoresRef[ $b ]) {
$itsright = 0;
}
}
$right++ if $itsright;
}
$total = 1 - ( 1 - $right / 10000 ) ** 6;
print join(", ", @$scoresRef) . " = $total \n";
}
On Mac OS X, launch Terminal.app, type “perl” and press return. Then copy and paste the code above and press control-D. After a little while it will print out something like this:
3, 13, 13, 14, 14, 15 = 0.0107515164826495 3, 3, 13, 13, 14, 14 = 0.0596604624564983 3, 3, 3, 12, 13, 15 = 0.16341479899658 3, 3, 3, 3, 3, 3 = 1 18, 18, 18, 18, 18, 18 = 0 3, 3, 3, 3, 3, 18 = 0.0214065306042021
Notice the use of the sort function to remove any order issues, also the bit about **6 is because we get 6 tries to roll it right. If we had to roll the scores in the correct order it would be a lot lower probability. What I see is that rolling scores high enough for my ideal character happens about 1% of the time. While this seems pretty unlikely, there are a few things going in my favor. First of all, I get 6 tries to roll (increasing my chances by 6 fold). Furthermore, my montycarlo simulation can easily have some error. Finally, its only 1/2 as likely as rolling an 18 — and I know several of my fellow D&D players have characters with 18s, so shooting for my goal seems perfectly reasonable.
I mentioned that there is a second way to calculate how likely I am to roll my needed scores. The first step will be calculating how likely each sum is. Here is some more perl code for doing that:
foreach $a (1..18) { $p1[$a] = 0; $p2[$a] = 0; $p3[$a] = 0; } foreach $a (1..6) { $p1[$a] = 1/6; } foreach $a (2..12) { $p2[$a] = 0; $start = $a-6; if ($start < 1) { $start = 1; } foreach $b ($start..($a-1)) { $p2[$a] += $p1[$b]/6; } } foreach $a (1..18) { print "$a : $p2[$a]\n"; } foreach $a (3..18) { $p3[$a] = 0; $start = $a-6; if ($start < 2) { $start = 2; } foreach $b ($start..($a-1)) { $p3[$a] += $p2[$b]/6; } } $sum = 0; foreach $a (3..18) { print "$a : $p3[$a]\n"; $sum += $p3[$a]; } print "-" x 32; print "\n$sum\n\n";
This will print out something like this:
1 : 0 2 : 0.0277777777777778 3 : 0.0555555555555556 4 : 0.0833333333333333 5 : 0.111111111111111 6 : 0.138888888888889 7 : 0.166666666666667 8 : 0.138888888888889 9 : 0.111111111111111 10 : 0.0833333333333333 11 : 0.0555555555555556 12 : 0.0277777777777778 13 : 0 14 : 0 15 : 0 16 : 0 17 : 0 18 : 0 3 : 0.00462962962962963 4 : 0.0138888888888889 5 : 0.0277777777777778 6 : 0.0462962962962963 7 : 0.0694444444444444 8 : 0.0972222222222222 9 : 0.115740740740741 10 : 0.125 11 : 0.125 12 : 0.115740740740741 13 : 0.0972222222222222 14 : 0.0694444444444444 15 : 0.0462962962962963 16 : 0.0277777777777778 17 : 0.0138888888888889 18 : 0.00462962962962963 -------------------------------- 1
The first 18 values show the probability that a sum of two dice would be the given value. The second 18 show the values for three dice. Thus rolling three dice and getting a sum of 18 has a P=0.0046. Getting a 10 has P=0.125.
The real complication with calculating the scores for my Ranger/Druid using statistics has to do with figuring out the combinations. Essentially, you need to figure out how likely that *one* of the rolls is 15 or better, but it doesn't matter which. After getting bogged down for quite a while puzzling this out, I decided I would simply trust my monte carlo simulation results 🙂
So I had my dog blow on the dice, and my wife roll them, and sure enough.... I got my scores!