In this post, we will examine the effect of rerolls on some of the algorithms mentioned in the previous three posts:

• Algorithm 27- Roll 2d6, Reroll 1s, Add 6, Take the Sum, Repeat 6 Times
• Algorithm 28- Roll 2d6, Reroll 1s and 2s, Add 6, Take the Sum, Repeat 6 Times
• Algorithm 29- Roll 2d6, Reroll 1s, Add 6, Take the Sum, Repeat 7 Times, Drop Lowest
• Algorithm 30- Roll 2d6, Reroll 1s and 2s, Add 6, Take the Sum, Repeat 7 Times, Drop Lowest
• Algorithm 31- Roll 3d6, Reroll 1s, Take the Sum, Repeat 6 Times
• Algorithm 32- Roll 3d6, Reroll 1s and 2s, Take the Sum, Repeat 6 Times
• Algorithm 33- Roll 3d6, Reroll 1s, Take the Sum, Repeat 7 Times, Drop Lowest
• Algorithm 34- Roll 3d6, Reroll 1s and 2s, Take the Sum, Repeat 7 Times, Drop Lowest
• Algorithm 35- Roll 4d6, Reroll 1s, Drop Lowest, Take the Sum, Repeat 6 Times
• Algorithm 36- Roll 4d6, Reroll 1s and 2s, Drop Lowest, Take the Sum, Repeat 6 Times
• Algorithm 37- Roll 4d6, Reroll 1s, Drop Lowest, Take the Sum, Repeat 7 Times, Drop Lowest
• Algorithm 38- Roll 4d6, Reroll 1s and 2s, Drop Lowest, Take the Sum, Repeat 7 Times, Drop Lowest

Also, the "pbe" algorithm in the code should be in a final, usable form, so that you can import it into your own Python code to run. It will be able to solve any of the algorithms in all four posts. Refer to the docstring for help with parameters.



In [1]:

import numpy as np
import seaborn as sns
from random import randint
from scipy.stats import norm
from heapq import nlargest
import matplotlib.pyplot as plt
from tabulate import tabulate
vmap = {3:-16, 4:-12, 5:-9, 6:-6, 7:-4, 8:-2,
9:-1, 10:0, 11:1, 12:2, 13:3, 14:5,
15:7, 16:10, 17:13, 18:17}
% matplotlib inline

def pbe(num_hist, num_dice, dice_type, num_reps, num_nest=1,
drop_low_rep=False):
"""
pbe
~~~~~~~~~~~~~~~~~~~~
Runs a Monte Carlo simulation to determine the equivalent
Point Buy of a dice rolling algorithm.

:param num_hist- The number of Monte Carlo histories to
run. Suggest at least 10**5.
:param num_dice- The number of dice to roll (i.e. this is
the "3" in "3d6")
:param dice_type- The type of dice to roll (i.e. six-sided,
eight-sided, etc. This is the "6" in "3d6")
:param num_reps- The number of times to repeat the dice
roll. If you select more than 6, suggest that you
also select drop_low_rep=True
:param num_nest- The number of times to repeat the entire
algorithm. This is usually "1".
this is the "8" in "1d10+8")
:param reroll- Which dice should be rerolled, cumulatively.
E.g. "0" is no rerolls, "1" is rerolls 1s, and "2" is
rerolls 1s and 2s.
:param drop_low_dice- If you select more than 3 dice to roll
for the six-sided dice, this will drop down the number
of dice so they equal 3.
:param drop_low_rep- This will drop the total number of
repetitions so that they equal 6.

:returns the raw value array, the point buy equivalent array
"""

raw_res = []
val_res = []
for _ in range(num_hist):
inst_raw = []
inst_val = []
for _ in range(num_nest):
roll_sums = []
# Repeat the dice rolling [num_reps] time (Part D)
for _ in range(num_reps):
# Part A- Roll [num_dice] dice
rolls = [randint(reroll+1,dice_type)
for _ in range(num_dice)]
# Part B- Modify the dice roll
if drop_low_dice:
rolls = nlargest(3,rolls)
# Part C- Sum the values
# Part E- Modify the repetitions
if drop_low_rep:
roll_sums = nlargest(6,roll_sums)
# Part Fa- Find the average raw value and save to the raw_res
avg_roll_sums = np.median(roll_sums)
inst_raw.append(avg_roll_sums)
# Part Fb- Find the Point Buy value and save to the val_res
point_buy_sum = np.sum([vmap[value] for value in roll_sums])
ind = np.argmax(inst_val)
raw_res.append(inst_raw[ind])
val_res.append(inst_val[ind])
return raw_res, val_res

def plot_hist(raw_data, val_data, title, bins):
f,(ax1,ax2) = plt.subplots(1, 2, figsize=(8,5))
props = dict(boxstyle='round', facecolor='wheat', alpha=0.5)
plt.suptitle(title, fontsize=14)
sns.distplot(raw_data, kde=False, bins=bins, fit=norm, ax=ax1)
ax1.text(0.05, 0.95, build_text(raw_data), transform=ax1.transAxes,
fontsize=12, verticalalignment='top', bbox=props)
ax1.set_xlabel('Raw Results')
ax1.set_ylabel('Probability')
ax1.set_xlim([3,18])
sns.distplot(val_data, kde=False, fit=norm, ax=ax2)
ax2.text(0.05, 0.95, build_text(val_data), transform=ax2.transAxes,
fontsize=12, verticalalignment='top', bbox=props)

def build_text(data):
ret_string = '$\mu$={:.1f}\n$\sigma$={:.2f}\n95%={:.0f}\n5%={:.0f}'.format(
np.mean(data), np.std(data), np.percentile(data,95),
np.percentile(data,5))
return ret_string




In [2]:

num_hist = 10**6
alg3_raw, alg3_val = pbe(num_hist,2,6,7,drop_low_rep=True,
alg4_raw, alg4_val = pbe(num_hist,2,6,7,drop_low_rep=True,
alg5_raw, alg5_val = pbe(num_hist,3,6,6,reroll=1)
alg6_raw, alg6_val = pbe(num_hist,3,6,6,reroll=2)
alg7_raw, alg7_val = pbe(num_hist,3,6,7,reroll=1,drop_low_rep=True)
alg8_raw, alg8_val = pbe(num_hist,3,6,7,reroll=2,drop_low_rep=True)
alg9_raw, alg9_val = pbe(num_hist,4,6,6,reroll=1,drop_low_dice=True)
alg10_raw, alg10_val = pbe(num_hist,4,6,6,reroll=2,drop_low_dice=True)
alg11_raw, alg11_val = pbe(num_hist,4,6,7,reroll=1,
drop_low_dice=True,drop_low_rep=True)
alg12_raw, alg12_val = pbe(num_hist,4,6,7,reroll=2,
drop_low_dice=True,drop_low_rep=True)
plot_hist(alg1_raw, alg1_val,"Algorithm 27- Sum of 2d6+6, Reroll 1s, "+
"Repeat 6 Times", 16)
plot_hist(alg2_raw, alg2_val,"Algorithm 28- Sum of 2d6+6, Reroll 1s and 2s, "+
"Repeat 6 Times", 16)
plot_hist(alg3_raw, alg3_val,"Algorithm 29- Sum of 2d6+6, Reroll 1s, "+
"Repeat 7 Times, Drop Lowest", 16)
plot_hist(alg4_raw, alg4_val,"Algorithm 30- Sum of 2d6+6, Reroll 1s and 2s, "+
"Repeat 7 Times, Drop Lowest", 16)
plot_hist(alg5_raw, alg5_val,"Algorithm 31- Sum of 3d6, Reroll 1s, "+
"Repeat 6 Times", 18)
plot_hist(alg6_raw, alg6_val,"Algorithm 32- Sum of 3d6, Reroll 1s and 2s, "+
"Repeat 6 Times", 18)
plot_hist(alg7_raw, alg7_val,"Algorithm 33- Sum of 3d6, Reroll 1s, "+
"Repeat 7 Times, Drop Lowest", 18)
plot_hist(alg8_raw, alg8_val,"Algorithm 34- Sum of 3d6, Reroll 1s and 2s, "+
"Repeat 7 Times, Drop Lowest", 18)
plot_hist(alg9_raw, alg9_val,"Algorithm 35- Sum of 4d6, Reroll 1s, "+
"Drop Lowest, Repeat 6 Times", 18)
plot_hist(alg10_raw, alg10_val,"Algorithm 36- Sum of 4d6, Reroll 1s and 2s, "+
"Drop Lowest, Repeat 6 Times", 18)
plot_hist(alg11_raw, alg11_val,"Algorithm 37- Sum of 4d6, Reroll 1s, "+
"Drop Lowest, Repeat 7 Times, Drop Lowest", 18)
plot_hist(alg12_raw, alg12_val,"Algorithm 38- Sum of 4d6, Reroll 1s and 2s, "+
"Drop Lowest, Repeat 7 Times, Drop Lowest", 18)







In [3]:

from tabulate import tabulate
def br(data, description):
return [description, round(np.mean(data),1), round(np.std(data),2),
int(np.percentile(data,5)), int(np.percentile(data,95))]
raw_res = [["Description","Mean","Std","5%","95%"],
br(alg1_raw, "27. Sum 2d6+6, RR 1s, Repeat 6"),
br(alg2_raw, "28. Sum 2d6+6, RR 1s/2s, Repeat 6"),
br(alg3_raw, "29. Sum 2d6+6, RR 1s, Repeat 7, Drop 1"),
br(alg4_raw, "30. Sum 2d6+6, RR 1s/2s, Repeat 7, Drop 1"),
br(alg5_raw, "31. Sum 3d6, RR 1s, Repeat 6"),
br(alg6_raw, "32. Sum 3d6, RR 1s/2s, Repeat 6"),
br(alg7_raw, "33. Sum 3d6, RR 1s, Repeat 7, Drop 1"),
br(alg8_raw, "34. Sum 3d6, RR 1s/2s, Repeat 7, Drop 1"),
br(alg9_raw, "35. Sum 4d6, Drop 1, RR 1s, Repeat 6"),
br(alg10_raw, "36. Sum 4d6, Drop 1, RR 1s/2s, Repeat 6"),
br(alg11_raw, "37. Sum 4d6, Drop 1, RR 1s, Repeat 7, Drop 1"),
br(alg12_raw, "38. Sum 4d6, Drop 1, RR 1s/2s, Repeat 7, Drop 1")]
print("Raw Results")
print(tabulate(raw_res))
val_res = [["Description","Mean","Std","5%","95%"],
br(alg1_val, "27. Sum 2d6+6, RR 1s, Repeat 6"),
br(alg2_val, "28. Sum 2d6+6, RR 1s/2s, Repeat 6"),
br(alg3_val, "29. Sum 2d6+6, RR 1s, Repeat 7, Drop 1"),
br(alg4_val, "30. Sum 2d6+6, RR 1s/2s, Repeat 7, Drop 1"),
br(alg5_val, "31. Sum 3d6, RR 1s, Repeat 6"),
br(alg6_val, "32. Sum 3d6, RR 1s/2s, Repeat 6"),
br(alg7_val, "33. Sum 3d6, RR 1s, Repeat 7, Drop 1"),
br(alg8_val, "34. Sum 3d6, RR 1s/2s, Repeat 7, Drop 1"),
br(alg9_val, "35. Sum 4d6, Drop 1, RR 1s, Repeat 6"),
br(alg10_val, "36. Sum 4d6, Drop 1, RR 1s/2s, Repeat 6"),
br(alg11_val, "37. Sum 4d6, Drop 1, RR 1s, Repeat 7, Drop 1"),
br(alg12_val, "38. Sum 4d6, Drop 1, RR 1s/2s, Repeat 7, Drop 1")]
print(tabulate(val_res))




Raw Results
-----------------------------------------------  ----  ----  --  ---
Description                                      Mean  Std   5%  95%
27. Sum 2d6+6, RR 1s, Repeat 6                   14.0  0.99  12  15
28. Sum 2d6+6, RR 1s/2s, Repeat 6                15.0  0.79  13  16
29. Sum 2d6+6, RR 1s, Repeat 7, Drop 1           14.4  0.94  13  16
30. Sum 2d6+6, RR 1s/2s, Repeat 7, Drop 1        15.3  0.75  14  16
31. Sum 3d6, RR 1s, Repeat 6                     12.0  1.19  10  14
32. Sum 3d6, RR 1s/2s, Repeat 6                  13.5  0.95  12  15
33. Sum 3d6, RR 1s, Repeat 7, Drop 1             12.4  1.13  10  14
34. Sum 3d6, RR 1s/2s, Repeat 7, Drop 1          13.9  0.9   12  15
35. Sum 4d6, Drop 1, RR 1s, Repeat 6             13.5  1.16  11  15
36. Sum 4d6, Drop 1, RR 1s/2s, Repeat 6          14.7  0.93  13  16
37. Sum 4d6, Drop 1, RR 1s, Repeat 7, Drop 1     14.0  1.07  12  15
38. Sum 4d6, Drop 1, RR 1s/2s, Repeat 7, Drop 1  15.0  0.86  13  16
-----------------------------------------------  ----  ----  --  ---

-----------------------------------------------  ----  -----  --  ---
Description                                      Mean  Std    5%  95%
27. Sum 2d6+6, RR 1s, Repeat 6                   35.0  10.33  19  53
28. Sum 2d6+6, RR 1s/2s, Repeat 6                46.5  9.86   31  63
29. Sum 2d6+6, RR 1s, Repeat 7, Drop 1           39.5  10.7   23  58
30. Sum 2d6+6, RR 1s/2s, Repeat 7, Drop 1        51.1  10.06  35  68
31. Sum 3d6, RR 1s, Repeat 6                     15.9  9.19   2   32
32. Sum 3d6, RR 1s/2s, Repeat 6                  28.8  9.02   15  45
33. Sum 3d6, RR 1s, Repeat 7, Drop 1             20.1  9.18   6   36
34. Sum 3d6, RR 1s/2s, Repeat 7, Drop 1          32.7  9.3    19  49
35. Sum 4d6, Drop 1, RR 1s, Repeat 6             29.8  10.68  13  48
36. Sum 4d6, Drop 1, RR 1s/2s, Repeat 6          42.4  10.46  26  60
37. Sum 4d6, Drop 1, RR 1s, Repeat 7, Drop 1     34.7  10.81  18  53
38. Sum 4d6, Drop 1, RR 1s/2s, Repeat 7, Drop 1  47.4  10.6   30  65
-----------------------------------------------  ----  -----  --  ---



### Interpretation

Accumulating the results from all 3 previous blog posts, we end up with:

• Sum of 3d6, Repeat 6

• Sum of 3d6, Repeat 7, Drop 1
• (Low Variance) [Sum of 3d6, Repeat 6], Repeat 3
• (High Variance) Sum of 2d8+2, Repeat 6

• Sum of 3d6, Repeat 9, Drop 3
• (Low Variance) Sum of 4d4+2, Repeat 6
• (Low Variance) [Sum of 3d6, Repeat 6], Repeat 6
• (Low Variance) [Sum of 3d6, Repeat 7, Drop 1], Repeat 3
• (Low Variance) Sum of 3d6, Reroll 1s, Repeat 6
• (High Variance) Sum of 2d8+2, Repeat 7, Drop 1

• Sum of 4d6, Drop 1, Repeat 6
• (Low Variance) Sum of 4d4+2, Repeat 7, Drop 1
• (Low Variance) [Sum of 3d6, Repeat 7, Drop 1], Repeat 6
• (Low Variance) Sum of 3d6, Reroll 1s, Repeat 7, Drop 1

• Sum of 4d6, Drop 1, Repeat 7, Drop 1
• Sum of 2d6, Add 6, Repeat 6
• (High Variance) Sum of 1d12+6, Repeat 6

• Sum of 5d6, Drop 2, Repeat 6
• (Low Variance) Sum of 3d4+6, Repeat 6
• (Low Variance) [Sum of 4d6, Drop 1, Repeat 6], Repeat 3
• (Low Variance) Sum of 3d6, Reroll 1s/2s, Repeat 6
• (Low Variance) Sum of 4d6, Drop 1, Reroll 1s, Repeat 6

• (Low Variance) [Sum of 4d6, Drop 1, Repeat 6], Repeat 6
• (Low Variance) [Sum of 4d6, Drop 1, Repeat 7, Drop 1], Repeat 3
• (Low Variance) Sum of 2d6+6, Reroll 1s, Repeat 6
• (Low Variance) Sum of 3d6, Reroll 1s/2s, Repeat 7, Drop 1
• (Low Variance) Sum of 4d6, Drop 1, Reroll 1s, Repeat 6
• (High Variance) Sum of 1d10+8, Repeat 6

• (Low Variance) [Sum of 4d6, Drop 1, Repeat 7, Drop 1], Repeat 6
• (Low Variance) [Sum of 5d6, Drop 2, Repeat 6], Repeat 3
• (Low Variance) Sum of 2d6+6, Reroll 1s, Repeat 7, Drop 1
• (Low Variance) Sum of 4d6, Drop 1, Reroll 1s/2s, Repeat 6

• (Low Variance) Sum of 2d4+10, Repeat 6
• (Low Variance) [Sum of 5d6, Drop 2, Repeat 6], Repeat 6
• (Low Variance) Sum of 2d6+6, Reroll 1s/2s, Repeat 6
• (High Variance) Sum of 1d8+10, Repeat 6