Download as pdf or txt
Download as pdf or txt
You are on page 1of 17

Roll xdy!

+z, roll library

September 22, 2020

[28]: NAME = "Tynan Gacy"


Troubleshooters = "Laurence Ruberl"

[29]: # Import from 'random'


import random
import statistics
import math
import matplotlib
import matplotlib.mlab as mlab
import matplotlib.pyplot as plt
stdev=statistics.stdev
roll_result=0

[30]: # convert numeral to ordinal (e.g., 1 to 1st, 2 to 2nd, etc.)


# (taken from so: https://stackoverflow.com/questions/9647202/
,→ordinal-numbers-replacement)

def make_ordinal(n):
'''
Convert an integer into its ordinal representation::

make_ordinal(0) => '0th'


make_ordinal(3) => '3rd'
make_ordinal(122) => '122nd'
make_ordinal(213) => '213th'
'''
n = int(n)
suffix = ['th', 'st', 'nd', 'rd', 'th'][min(n % 10, 4)]
if 11 <= (n % 100) <= 13:
suffix = 'th'
return str(n) + suffix

[31]: # roll one die with t sides (e.g., roll_die("d4") for t=4)
def roll_die(o):
# convert user input from string to list
t=o.split("d")
# convert list to integer
t=t[1]

1
t=int(t)
# generate a random number between 1 and t
ir=random.randint(1,t)
#print output
print("roll was", ir)

[32]: # same at roll_die but returns instead of prints


def roll(t):
# generate a random number between 1 and t
ir=random.randint(1,t)
return ir

[33]: # roll one die with t sides, if highest number is rolled the die is rolled␣
,→again and added to the result

# (e.g., exploding_die("d4") for t=4)


def exploding_die(o):
# convert user input from string to list
t=o.split("d")
# convert list to integer
t=t[1]
t=int(t)
if t<=1 or type(t) is not int:
print("die must be an integer of 2 or higher")
else:
# set bank of rolls to empty
result=[]
# roll die once
current_roll=roll(t)
# check if die roll is the highest number on the die (divisible by t)
while current_roll % t==0:
# if roll is the highest, add to bank and roll again
result.append(current_roll)
current_roll=roll(t)
else:
# if roll is not highest, add to bank
result.append(current_roll)
# rewrite results as string
s=", "
s=s.join(map(str,result))
# print output
print("the die rolled", s, "for a total of", sum(result))

[34]: # same as exploding_die but returns instead of prints


def exploding(t):
if t<=1 or type(t) is not int:
print("die must be an integer of 2 or higher")
else:

2
# set bank of rolls to empty
result=[]
# roll die once
current_roll=roll(t)
# check if die roll is the highest number on the die (divisible by t)
while current_roll % t==0:
# if roll is the highest, add to bank and roll again
result.append(current_roll)
current_roll=roll(t)
else:
# if roll is not highest, add to bank
result.append(current_roll)
return result

[35]: # same as exploding_die but returns instead of prints


def exploding1(t):
if t<=1 or type(t) is not int:
print("die must be an integer of 2 or higher")
else:
# set bank of rolls to empty
result=[]
# roll die once
current_roll=roll(t)
# check if die roll is the highest number on the die (divisible by t)
while current_roll % t==0:
# if roll is the highest, add to bank and roll again
result.append(current_roll)
current_roll=roll(t)
else:
# if roll is not highest, add to bank
result.append(current_roll)
result=sum(result)
return result

[36]: # roll n exploding dice with t sides with a bonus (e.g., roll_the_dice("3d4+2")␣
,→-> n=3, t=4, b=2)

def roll_the_dice(o):
# split user input (e.g., 3d4+2 -> 3, 4, +, 2)
# split user input down d (3d4+2 -> 3, 4+2)
split=o.split("d")
# if first value is empty (meaning user left n blank) assume n=1
if split[0]=="":
n=1
else:
n=split[0]
# create split_no_n (3, 4+2 -> 4+2)
split_no_n=split[1]

3
# check for +/-
if "+" in split_no_n or "-" in split_no_n:
# split across +/1 (4+2 -> 4, 2)
if "+" in split_no_n:
final_split=split_no_n.split("+")
# add or subtract value (used later)
addsub_val="+"
else:
final_split=split_no_n.split("-")
addsub_val="-"
# whether bonus is present or not
addsub=True
# final split (4, 2 -> 4)
t=final_split[0]
b=final_split[1]
# convert bonus into float
bonus=float(b)
if bonus % 1 ==0:
# convert float into integer if bonus can be an integer (used to␣
,→get rid of .0)

bonus=int(bonus)
else:
addsub=False
final_split=split_no_n
# write t with no bonus
t=split_no_n
# create die type variable from input (4 -> d4)
d=["d",t]
die="".join(d)
# convert user input into floats
t=float(t)
n=float(n)
# check if inputs are able to be converted into integers, spits error if not
if t<=1 or t % 1 != 0:
print("die must be an integer of 2 or higher")
else:
if n<=0 or n % 1 != 0:
print ("number of dice must be a natural number (no entry reads as␣
,→1 die)")

else:
# convert inputs to actual integer type
t=int(t)
n=int(n)
# set initial value of rolls to 0
final_rolls=[]
# roll n times
for i in range(n):

4
# add result to final_rolls
final_rolls.append(exploding(t))
# set roll_count and total_sum to 0
roll_count=0
total_sum=0
# split and print each roll individually
for roll_count in range (n):
current_roll=final_rolls[roll_count]
comma=", then "
series=comma.join(map(str,current_roll))
total_sum+=sum(current_roll)
ord_roll_count=make_ordinal(roll_count+1)
# if only one die, skip ordinal assignment
if n==1:
one_die = True
else:
one_die = False
# print output for number of dice, die type, and sum for each␣
die
,→

if one_die is True:
print("the", die, "rolled", series, "for a total of",␣
,→sum(current_roll))

else:
print("the", ord_roll_count, die, "rolled", series, "for a␣
,→total of", sum(current_roll))

roll_count+=1
# print bonus if necessary
if addsub is True:
if addsub_val=="+":
total_sum+=bonus
print ("plus an additional", b)
else:
b=["-", b]
b="".join(b)
total_sum-=bonus
print ("with a", b, "penalty")
# add up all totals, add period
total_sum_str=str(total_sum)
sum_with_prd=[total_sum_str,"."]
sum_final="".join(sum_with_prd)
global total
total=total_sum
print ("for a total of", sum_final)

[37]: def splitter(o):


# split user input (e.g., 3d4+2 -> 3, 4, +, 2)
# split user input down d (3d4+2 -> 3, 4+2)

5
split=o.split("d")
# if first value is empty (meaning user left n blank) assume n=1
if split[0]=="":
n=1
else:
n=split[0]
# create split_no_n (3, 4+2 -> 4+2)
split_no_n=split[1]
# check for +/-
if "+" in split_no_n or "-" in split_no_n:
# split across +/1 (4+2 -> 4, 2)
if "+" in split_no_n:
final_split=split_no_n.split("+")
# add or subtract value (used later)
addsub_val="+"
else:
final_split=split_no_n.split("-")
addsub_val="-"
# whether bonus is present or not
addsub=True
# final split (4, 2 -> 4)
t=final_split[0]
b=final_split[1]
# convert bonus into float
bonus=float(b)
# convert float into integer if bonus can be an integer (used to␣
,→get rid of .0)

else:
addsub=False
final_split=split_no_n
b=float(0)
# write t with no bonus
t=split_no_n
if addsub is True:
if addsub_val=="+":
b=b
else:
b=-1*b
t=float(t)
n=float(n)
split_list=[n,t,b]
return split_list

[38]: # roll n exploding dice with t sides with a bonus (e.g., roll_the_dice("3d4+2")␣
,→-> n=3, t=4, b=2)

def roll_the_dice_return(o):
splitter(o)

6
n=splitter(o)[0]
t=splitter(o)[1]
b=splitter(o)[2]
# check if inputs are able to be converted into integers, spits error if not
if t<=1 or t % 1 != 0:
print("die must be an integer of 2 or higher")
else:
if n<=0 or n % 1 != 0:
print ("number of dice must be a natural number (no entry reads as␣
,→1 die)")

else:
# convert inputs to actual integer type
t=int(t)
n=int(n)
b=int(b)
# set initial value of rolls to 0
final_rolls=[]
# roll n times
for i in range(n):
# add result to final_rolls
final_rolls.append(exploding(t))
# set roll_count and total_sum to 0
roll_count=0
total_sum=0
# split and print each roll individually
for roll_count in range (n):
current_roll=final_rolls[roll_count]
total_sum+=sum(current_roll)
ord_roll_count=make_ordinal(roll_count+1)
total_sum+=b
return total_sum

[39]: def exploding_ave(t):


# citation: https://eric22222.wordpress.com/2009/03/22/
,→a-mathematical-analysis-of-exploding-dice/

ave=0.5*(t+1)*(t/(t-1))
return ave

[40]: def mult_exploding_ave_b(n,t,b):


avesum=0
n=int(n)
b=int(b)
for i in range(n):
avesum+=exploding_ave(t)
avesum+=b
return avesum

7
def mult_exploding_ave_no_b(n,t):
avesum=0
n=int(n)
for i in range(n):
avesum+=exploding_ave(t)
return avesum

[41]: def average_calc(o):


# split user input (e.g., 3d4+2 -> 3, 4, +, 2)
# split user input down d (3d4+2 -> 3, 4+2)
split=o.split("d")
# if first value is empty (meaning user left n blank) assume n=1
if split[0]=="":
n=1
else:
n=split[0]
# create split_no_n (3, 4+2 -> 4+2)
split_no_n=split[1]
# check for +/-
if "+" in split_no_n or "-" in split_no_n:
# split across +/1 (4+2 -> 4, 2)
if "+" in split_no_n:
final_split=split_no_n.split("+")
# add or subtract value (used later)
addsub_val="+"
else:
final_split=split_no_n.split("-")
addsub_val="-"
# whether bonus is present or not
addsub=True
# final split (4, 2 -> 4)
t=final_split[0]
b=final_split[1]
# convert bonus into float
bonus=float(b)
if bonus % 1 ==0:
# convert float into integer if bonus can be an integer (used to␣
,→get rid of .0)

bonus=int(bonus)
else:
addsub=False
final_split=split_no_n
# write t with no bonus
t=split_no_n
# create die type variable from input (4 -> d4)
d=["d",t]
die="".join(d)

8
# convert user input into floats
t=float(t)
n=float(n)
# check if inputs are able to be converted into integers, spits error if not
if t<=1 or t % 1 != 0:
print("die must be an integer of 2 or higher")
else:
if n<=0 or n % 1 != 0:
print ("number of dice must be a natural number (no entry reads as␣
,→1 die)")

else:
print ("Average of a single exploding", die, "roll:",␣
,→exploding_ave(t))

print()
if addsub==False:
print ("Average of your roll:", mult_exploding_ave_no_b(n,t))
if addsub==True:
print ("Average of your roll:", mult_exploding_ave_b(n,t,b))

[42]: def standev_one_die(o):


print("Please wait... Generating standard deviation of one die...")
print()
sumlist=[]
splitter(o)
n=splitter(o)[0]
t=splitter(o)[1]
b=splitter(o)[2]
t=float(t)
t=int(t)
type=str(t)
d=["d",type]
die="".join(d)
avesum=mult_exploding_ave_no_b(n,t)
for i in range (1,200000):
sumlist.append(exploding1(t))
bloop=stdev(sumlist,avesum)
print("Standard deviation of one", die, "roll is", bloop)

[43]: def standev_full(o):


print("Please wait... Generating standard deviation of",o,"...")
print()
sumlist=[]
splitter(o)
n=splitter(o)[0]
t=splitter(o)[1]
b=splitter(o)[2]
if b==0:

9
avesum=mult_exploding_ave_no_b(n,t)
else:
avesum=mult_exploding_ave_b(n,t,b)
for i in range (1,200000):
sumlist.append(roll_the_dice_return(o))
stdev1=stdev(sumlist,avesum)
print("Standard deviation of", o, "is", stdev1)

[44]: def standev_z(o):


print("Please wait... Generating standard deviation of",o,"...")
print()
sumlist=[]
splitter(o)
n=splitter(o)[0]
t=splitter(o)[1]
b=splitter(o)[2]
if b==0:
avesum=mult_exploding_ave_no_b(n,t)
else:
avesum=mult_exploding_ave_b(n,t,b)
for i in range (1,200000):
sumlist.append(roll_the_dice_return(o))
global stdev1
stdev1=stdev(sumlist,avesum)
print("Standard deviation of", o, "is", stdev1)
return stdev1

[45]: def stats_no_print(o):


sumlist=[]
splitter(o)
n=splitter(o)[0]
t=splitter(o)[1]
b=splitter(o)[2]
if b==0:
avesum=mult_exploding_ave_no_b(n,t)
else:
avesum=mult_exploding_ave_b(n,t,b)
for i in range (1,200000):
sumlist.append(roll_the_dice_return(o))
global stdev1
stdev1=stdev(sumlist,avesum)
return (avesum,stdev1,sumlist)

[46]: def graph_time(o):


print("Please wait... Generating graph 1/2...")
sumlist=[]
splitter(o)

10
n=splitter(o)[0]
t=splitter(o)[1]
b=splitter(o)[2]
b=int(b)
x = stats_no_print(o)[2]
limited=[]
for i in x:
if i<=int((1.5+(9/(n*t)))*n*t+b):
limited.append(i)
num_bins = max(limited)-min(limited)+1
fig,ax = plt.subplots(figsize=(15, 5))
n, bins, patches = plt.hist(limited, bins=num_bins, density=1,␣
,→cumulative=-1, facecolor='green', histtype='step')

if roll_result==1:
ax.scatter(total,.5)
ax.annotate("roll", xy=(total,.5))
ax.yaxis.set_major_formatter(matplotlib.ticker.PercentFormatter(1.0))
plt.hist
total_title=("Histogram for rolls of " + o)
ax.grid(True)
ax.set_xlabel('Total')
ax.set_ylabel('Probability')
ax.set_title(total_title)
plt.show()

[47]: def cumu_graph_time(o):


print("Please wait... Generating graph 2/2...")
sumlist=[]
splitter(o)
n=splitter(o)[0]
t=splitter(o)[1]
b=splitter(o)[2]
b=int(b)
x = stats_no_print(o)[2]
limited=[]
for i in x:
if i<=int((1.5+(9/(n*t)))*n*t+b):
limited.append(i)
num_bins = max(limited)-min(limited)+1
fig,ax = plt.subplots(figsize=(15, 5))
n, bins, patches = plt.hist(limited, bins=num_bins, density=1,␣
,→facecolor='green', histtype='step')

if roll_result==1:
ax.scatter(total,.5)
ax.annotate("roll", xy=(total,.5))
ax.yaxis.set_major_formatter(matplotlib.ticker.PercentFormatter(1.0))
total_title=("Histogram for rolls of " + o)

11
ax.grid(True)
ax.set_xlabel('Total')
ax.set_ylabel('Probability')
ax.set_title(total_title)
plt.show()

[48]: def grade(o):


''' sumlist=[]
splitter(o)
n=splitter(o)[0]
t=splitter(o)[1]
b=splitter(o)[2]
t=float(t)
t=int(t)
if b==0:
avesum=mult_exploding_ave_no_b(n,t)
else:
avesum=mult_exploding_ave_b(n,t,b)
zscore=((total-avesum)/(stdev1/math.sqrt(200000)))
percentile = 1
percentile_string = "erfgetf"
print("Your roll of", o, "is in the", percentile_string, "percentile.")
if percentile <= 25:
print("Oops.")
elif percentile >25 and percentile <= 75:
print("Cool!")
elif percentile >75:
print("Nice roll!")
print()
return zscore'''

[49]: def statistics(o):


average_calc(o)
print()
standev_one_die(o)
print()
standev_full(o)
print()
graph_time(o)
print()
cumu_graph_time(o)

[50]: def load_roll_library():


with open("roll_library.txt") as f:
f=str(f.read())
f=f.split("\n")
f2=[]

12
for i in range(len(f)):
f2.append(f[i].split(", "))
global roll_dict
roll_dict={}
for i in range(len(f2)):
roll_dict[f2[i][0]] = f2[i][2]
global print_dict
print_dict={}
for i in range(len(f2)):
print_dict[f2[i][0]] = str([' - '.join(f2[i][1:3])])
print_dict[f2[i][0]] = print_dict[f2[i][0]][2:-2]
global dict_str
dict_str=""
for i in range(len(f2)):
dict_str += ' - '.join(f2[i][0:3])
dict_str+="\n"
load_roll_library()

[51]: def lib_to_output():


print (dict_str)
selection=input("Which roll would you like to make? - ")
print ()
print ("You've selected:", print_dict[selection])
roll=roll_dict[selection]
return roll

[52]: def add_to_lib():


check = False
while check is False:
roll=input("What are the dice of the roll that you would like to add? -␣
,→")

print()
name=input("What is the name of the roll that you would like to add? -␣
,→")

print()
z=input('New roll is "' + str(name) + " - " + str(roll) + '". Is that␣
,→correct? y/n - ')

if z=="y":
check = True
with open("roll_library.txt","a+") as f:
new_key=int(max(print_dict, key=int))
new_key+=1
new_roll="\n"+str(new_key)+", "+name+", "+roll
f.write(new_roll)
load_roll_library()

13
[53]: def Start_Die_Roller():
load_roll_library()
print ("Hello! select an option below.")
print ()
global roll_result
roll_result=0
user=""
while user!="n" and user!="5":
print ("1 - Run statistics")
print ("2 - Roll the dice")
print ("3 - Both")
print ("4 - Save new roll")
print ("5 - End program")
print ()
user=input("What would you like to do? - ")
print ()
if user=="1":
print ("You've selected to run statistics.")
print()
user=input("Would you like to use a preset roll? y/n - ")
print()
if user=="y":
user=lib_to_output()
else:
user=input("Enter the dice you would like to run statistics on.␣
,→")

print()
statistics(user)
print()
user=input("Run again? y/n - ")
print()
if user=="2":
print ("You've selected the dice roller.")
print()
user=input("Would you like to use a preset roll? y/n - ")
print()
if user=="y":
user=lib_to_output()
else:
user=input("Enter the dice you would like to roll. ")
print()
roll_the_dice(user)
print()
user=input("Run again? y/n - ")
print()
if user=="3":
roll_result=1

14
print ("You've selected to roll and run statistics.")
print()
user=input("Would you like to use a preset roll? y/n - ")
print()
if user=="y":
user=lib_to_output()
else:
user=input("Enter the dice you would like to use. ")
print()
roll_the_dice(user)
print()
statistics(user)
print()
user=input("Run again? y/n - ")
print()
roll_result=0
if user=="4":
print("You've selected to write a new roll to the library.")
print()
add_to_lib()
print()
else:
print ("Goodbye!")

Start_Die_Roller()

Hello! select an option below.

1 - Run statistics
2 - Roll the dice
3 - Both
4 - Save new roll
5 - End program

What would you like to do? - 2

You've selected the dice roller.

Would you like to use a preset roll? y/n - y

1 - Bolt - 2d6
2 - Blast - 3d6
3 - Cannon - 2d10+4
4 - Damage Field - 2d4
5 - Tickle - 5d2

Which roll would you like to make? - 1

15
You've selected: Bolt - 2d6

the 1st d6 rolled 2 for a total of 2


the 2nd d6 rolled 5 for a total of 5
for a total of 7.

Run again? y/n - y

1 - Run statistics
2 - Roll the dice
3 - Both
4 - Save new roll
5 - End program

What would you like to do? - 4

You've selected to write a new roll to the library.

What are the dice of the roll that you would like to add? - 2d8+2

What is the name of the roll that you would like to add? - Last-Minute Report

New roll is "Last-Minute Report - 2d8+2". Is that correct? y/n - y

1 - Run statistics
2 - Roll the dice
3 - Both
4 - Save new roll
5 - End program

What would you like to do? - 2

You've selected the dice roller.

Would you like to use a preset roll? y/n - y

1 - Bolt - 2d6
2 - Blast - 3d6
3 - Cannon - 2d10+4
4 - Damage Field - 2d4
5 - Tickle - 5d2
6 - Last-Minute Report - 2d8+2

Which roll would you like to make? - 6

You've selected: Last-Minute Report - 2d8+2

16
the 1st d8 rolled 8, then 5 for a total of 13
the 2nd d8 rolled 2 for a total of 2
plus an additional 2
for a total of 17.

Run again? y/n - n

Goodbye!

[ ]:

[ ]:

17

You might also like