Dice Roller
Dungeons & Dragons and other tabletop role-playing games use special dice that can have 4, 8, 10, 12, or even 20 sides. These games also have a specific notation for indicating which dice to roll. For example, 3d6 means rolling three six-sided dice, while 1d10+2 means rolling one ten-sided die and adding a two-point bonus to the roll. This program simulates this dice rolling, in case you forgot to bring your own. It can also simulate rolling dice that don’t physically exist, such as a 38-sided die.
dice_roller.py
1"""Dice Roller, by Al Sweigart al@inventwithpython.com
2Simulates dice rolls using the Dungeons & Dragons dice roll notation.
3This code is available at https://nostarch.com/big-book-small-python-programming
4Tags: short, simulation"""
5
6import random, sys
7
8print('''Dice Roller, by Al Sweigart al@inventwithpython.com
9
10Enter what kind and how many dice to roll. The format is the number of
11dice, followed by "d", followed by the number of sides the dice have.
12You can also add a plus or minus adjustment.
13
14Examples:
15 3d6 rolls three 6-sided dice
16 1d10+2 rolls one 10-sided die, and adds 2
17 2d38-1 rolls two 38-sided die, and subtracts 1
18 QUIT quits the program
19''')
20
21while True: # Main program loop:
22 try:
23 diceStr = input('> ') # The prompt to enter the dice string.
24 if diceStr.upper() == 'QUIT':
25 print('Thanks for playing!')
26 sys.exit()
27
28 # Clean up the dice string:
29 diceStr = diceStr.lower().replace(' ', '')
30
31 # Find the "d" in the dice string input:
32 dIndex = diceStr.find('d')
33 if dIndex == -1:
34 raise Exception('Missing the "d" character.')
35
36 # Get the number of dice. (The "3" in "3d6+1"):
37 numberOfDice = diceStr[:dIndex]
38 if not numberOfDice.isdecimal():
39 raise Exception('Missing the number of dice.')
40 numberOfDice = int(numberOfDice)
41
42 # Find if there is a plus or minus sign for a modifier:
43 modIndex = diceStr.find('+')
44 if modIndex == -1:
45 modIndex = diceStr.find('-')
46
47 # Find the number of sides. (The "6" in "3d6+1"):
48 if modIndex == -1:
49 numberOfSides = diceStr[dIndex + 1 :]
50 else:
51 numberOfSides = diceStr[dIndex + 1 : modIndex]
52 if not numberOfSides.isdecimal():
53 raise Exception('Missing the number of sides.')
54 numberOfSides = int(numberOfSides)
55
56 # Find the modifier amount. (The "1" in "3d6+1"):
57 if modIndex == -1:
58 modAmount = 0
59 else:
60 modAmount = int(diceStr[modIndex + 1 :])
61 if diceStr[modIndex] == '-':
62 # Change the modification amount to negative:
63 modAmount = -modAmount
64
65 # Simulate the dice rolls:
66 rolls = []
67 for i in range(numberOfDice):
68 rollResult = random.randint(1, numberOfSides)
69 rolls.append(rollResult)
70
71 # Display the total:
72 print('Total:', sum(rolls) + modAmount, '(Each die:', end='')
73
74 # Display the individual rolls:
75 for i, roll in enumerate(rolls):
76 rolls[i] = str(roll)
77 print(', '.join(rolls), end='')
78
79 # Display the modifier amount:
80 if modAmount != 0:
81 modSign = diceStr[modIndex]
82 print(', {}{}'.format(modSign, abs(modAmount)), end='')
83 print(')')
84
85 except Exception as exc:
86 # Catch any exceptions and display the message to the user:
87 print('Invalid input. Enter something like "3d6" or "1d10+2".')
88 print('Input was invalid because: ' + str(exc))
89 continue # Go back to the dice string prompt.