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.
When you run diceroller.py, the output will look like this:
Dice Roller, by Al Sweigart [email protected]
--snip--
> 3d6
7 (3, 2, 2)
> 1d10+2
9 (7, +2)
> 2d38-1
32 (20, 13, -1)
> 100d6
364 (3, 3, 2, 4, 2, 1, 4, 2, 4, 6, 4, 5, 4, 3, 3, 3, 2, 5, 1, 5, 6, 6, 6, 4, 5, 5, 1, 5, 2, 2, 2, 5, 1, 1, 2, 1, 4, 5, 6, 2, 4, 3, 4, 3, 5, 2, 2, 1, 1, 5, 1, 3, 6, 6, 6, 6, 5, 2, 6, 5, 4, 4, 5, 1, 6, 6, 6, 4, 2, 6, 2, 6, 2, 2, 4, 3, 6, 4, 6, 4, 2, 4, 3, 3, 1, 6, 3, 3, 4, 4, 5, 5, 5, 6, 2, 3, 6, 1, 1, 1)
--snip--
Most of the code in this program is dedicated to ensuring that the input the user entered is properly formatted. The actual random dice rolls themselves are simple calls to random.randint()
. This function has no bias: each integer in the range passed to it is equally likely to be returned. This makes random.randint()
ideal for simulating dice rolls.
1. """Dice Roller, by Al Sweigart [email protected]
2. Simulates dice rolls using the Dungeons & Dragons dice roll notation.
3. This code is available at https://nostarch.com/big-book-small-python-programming
4. Tags: short, simulation"""
5.
6. import random, sys
7.
8. print('''Dice Roller, by Al Sweigart [email protected]
9.
10. Enter what kind and how many dice to roll. The format is the number of
11. dice, followed by "d", followed by the number of sides the dice have.
12. You can also add a plus or minus adjustment.
13.
14. Examples:
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.
21. while 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.
After entering the source code and running it a few times, try making experimental changes to it. On your own, you can also try to figure out how to do the following:
Try to find the answers to the following questions. Experiment with some modifications to the code and rerun the program to see what effect the changes have.
rolls.append(rollResult)
on line 69?rolls.append(rollResult)
on line 69 to rolls.append(-rollResult)
?print(', '.join(rolls), end='')
on line 77?