Simply call roll(string)
where string
is a dice combination with addition and multiplier modifiers.
The string can take the form:
(nds+a)*m
where n
is the number of dice, s
is the number of sides the dice has, a
is an addition modifier and m
is a multiplier. Note that the parenthesis are optional (and multiplication always happens last, regardless of their presence). The addition and multiplier are also optional. The d
may be capital and the *
may be x
or X
.
The code calculates statistics and presents a plot with probability information.
See the examples following the code.
%matplotlib inline
import numpy as np
import itertools
import matplotlib.pyplot as plt
import re
import sys
# Copyright (c) 2014, Casey Webster.
# All rights reserved.
# Licensed under BSD 3-clause license.
# get a copy at http://opensource.org/licenses/BSD-3-Clause
def roll(dicestr):
p = re.compile(r"""
\(?
(?P<ndice>\d+)?
[dD]
(?P<dtype>\d+)
(?:\+
(?P<add>\d+)
)?
\)?
(?:[xX*]
(?P<mult>\d+)
)?
""", re.VERBOSE)
m = p.match(dicestr)
if not m:
raise ValueError("Invalid string contents")
if m.group('ndice') == None:
ndice = 1
else:
ndice = int(m.group('ndice'))
dtype = int(m.group('dtype'))
if m.group('add') == None:
add = 0
else:
add = int(m.group('add'))
if m.group('mult') == None:
mult = 1
else:
mult = int(m.group('mult'))
rollinfo(ndice,dtype,add,mult)
def rollinfo(ndice,nsides,add,mult):
min = (ndice+add)*mult
max = ((ndice*nsides)+add)*mult
n = max-min+1
rolls = list(itertools.product(range(1,nsides+1),repeat=ndice))
outcomes = len(rolls)
rolls = [(sum(x)+add)*mult for x in rolls]
counts = list(np.zeros(n))
for i in rolls:
counts[i-min] += 1
sums = list(range(min,max+1,mult))
# remove 0-valued elements
counts = list(filter((0.).__ne__,counts))
#calc probability stuff
p = [float(x/outcomes)*100 for x in counts]
ap = np.cumsum(p)
mean = np.mean(rolls)
std = np.std(rolls)
plt.plot(sums,p)
plt.fill_between(sums,p,0,where=[(x > mean-std) and (x < mean+std) for x in sums], color='0.75')
plt.plot([mean,mean],[0,np.max(p)], color='k')
plt.xlim(min,max)
plt.ylim(0,np.max(p))
ax2 = plt.twinx()
ax2.plot(sums,ap)
ax2.set_ylim(0,100)
ax2.set_xlim(min,max)
title="{0}d{1}".format(ndice,nsides)
if add > 0: title +="+{0}".format(add)
if mult > 1: title +="*{0}".format(mult)
plt.text(0.05,0.90,title, size='x-large', transform=ax2.transAxes)
plt.text(0.05,0.85,r"$\mu$ = {0}".format(mean), transform=ax2.transAxes)
plt.text(0.05,0.80,r"$\sigma$ = {0:1.2f}".format(std), transform=ax2.transAxes)
plt.text(0.05,0.75,r"range = [{0}-{1}]".format(min,max), transform=ax2.transAxes)
#plt.xticks([np.arange(min,mean+1,1),np.arange(mean,max,1)])
roll("2d6")
roll("(3d6+6)*2")
roll("4d6")
roll("4d6+6")
roll("5d8")
roll("d20")
roll("4d10*10")