In this push-your-luck game, you roll dice to collect stars. The more you roll, the more stars you can get, but if you get three skulls you lose everything! This quick multiplayer game can support as many players as you want, making it ideal for parties.
On your turn, you pull three random dice from the dice cup and roll them. You can roll Stars, Skulls, and Question Marks. If you end your turn, you get one point per Star. If you choose to roll again, you keep the Question Marks and pull new dice to replace the Stars and Skulls. If you collect three Skulls, you lose all your Stars and end your turn.
When a player gets 13 points, everyone else gets one more turn before the game ends. Whoever has the most points wins.
There are six gold dice, four silver dice, and three bronze dice in the cup. Gold dice have more Stars, bronze dice have more Skulls, and silver is even.
When you run luckystars.py, the output will look like this:
Lucky Stars, by Al Sweigart [email protected]
--snip--
SCORES: Alice=0, Bob=0
It is Alice's turn.
+-----------+ +-----------+ +-----------+
| | | . | | |
| | | ,O, | | |
| ? | | 'ooOOOoo' | | ? |
| | | `OOO` | | |
| | | O' 'O | | |
+-----------+ +-----------+ +-----------+
GOLD GOLD BRONZE
Stars collected: 1 Skulls collected: 0
Do you want to roll again? Y/N
> y
+-----------+ +-----------+ +-----------+
| . | | ___ | | |
| ,O, | | / \ | | |
| 'ooOOOoo' | | |() ()| | | ? |
| `OOO` | | \ ^ / | | |
| O' 'O | | VVV | | |
+-----------+ +-----------+ +-----------+
GOLD BRONZE BRONZE
Stars collected: 2 Skulls collected: 1
Do you want to roll again? Y/N
--snip--
The text-based graphics in this program are stored as strings in a list in the STAR_FACE
, SKULL_FACE
, and QUESTION_FACE
variables. This format makes them easy to write in a code editor, while the code in lines 154 to 157 display them on the screen. Note that because three dice are shown together, this code must print each horizontal row of text on a die face at a time. Simply running code like print(STAR_FACE)
would result in each of the three dice appearing on top of each other, instead of side by side.
1. """Lucky Stars, by Al Sweigart [email protected]
2. A "press your luck" game where you roll dice to gather as many stars
3. as possible. You can roll as many times as you want, but if you roll
4. three skulls you lose all your stars.
5.
6. Inspired by the Zombie Dice game from Steve Jackson Games.
7. This code is available at https://nostarch.com/big-book-small-python-programming
8. Tags: large, game, multiplayer"""
9.
10. import random
11.
12. # Set up the constants:
13. GOLD = 'GOLD'
14. SILVER = 'SILVER'
15. BRONZE = 'BRONZE'
16.
17. STAR_FACE = ["+-----------+",
18. "| . |",
19. "| ,O, |",
20. "| 'ooOOOoo' |",
21. "| `OOO` |",
22. "| O' 'O |",
23. "+-----------+"]
24. SKULL_FACE = ['+-----------+',
25. '| ___ |',
26. '| / \\ |',
27. '| |() ()| |',
28. '| \\ ^ / |',
29. '| VVV |',
30. '+-----------+']
31. QUESTION_FACE = ['+-----------+',
32. '| |',
33. '| |',
34. '| ? |',
35. '| |',
36. '| |',
37. '+-----------+']
38. FACE_WIDTH = 13
39. FACE_HEIGHT = 7
40.
41. print("""Lucky Stars, by Al Sweigart [email protected]
42.
43. A "press your luck" game where you roll dice with Stars, Skulls, and
44. Question Marks.
45.
46. On your turn, you pull three random dice from the dice cup and roll
47. them. You can roll Stars, Skulls, and Question Marks. You can end your
48. turn and get one point per Star. If you choose to roll again, you keep
49. the Question Marks and pull new dice to replace the Stars and Skulls.
50. If you collect three Skulls, you lose all your Stars and end your turn.
51.
52. When a player gets 13 points, everyone else gets one more turn before
53. the game ends. Whoever has the most points wins.
54.
55. There are 6 Gold dice, 4 Silver dice, and 3 Bronze dice in the cup.
56. Gold dice have more Stars, Bronze dice have more Skulls, and Silver is
57. even.
58. """)
59.
60. print('How many players are there?')
61. while True: # Loop until the user enters a number.
62. response = input('> ')
63. if response.isdecimal() and int(response) > 1:
64. numPlayers = int(response)
65. break
66. print('Please enter a number larger than 1.')
67.
68. playerNames = [] # List of strings of player names.
69. playerScores = {} # Keys are player names, values are integer scores.
70. for i in range(numPlayers):
71. while True: # Keep looping until a name is entered.
72. print('What is player #' + str(i + 1) + '\'s name?')
73. response = input('> ')
74. if response != '' and response not in playerNames:
75. playerNames.append(response)
76. playerScores[response] = 0
77. break
78. print('Please enter a name.')
79. print()
80.
81. turn = 0 # The player at playerNames[0] will go first.
82. # (!) Uncomment to let a player named 'Al' start with three points:
83. #playerScores['Al'] = 3
84. endGameWith = None
85. while True: # Main game loop.
86. # Display everyone's score:
87. print()
88. print('SCORES: ', end='')
89. for i, name in enumerate(playerNames):
90. print(name + ' = ' + str(playerScores[name]), end='')
91. if i != len(playerNames) - 1:
92. # All but the last player have commas separating their names.
93. print(', ', end='')
94. print('\n')
95.
96. # Start the number of collected stars and skulls at 0.
97. stars = 0
98. skulls = 0
99. # A cup has 6 gold, 4 silver, and 3 bronze dice:
100. cup = ([GOLD] * 6) + ([SILVER] * 4) + ([BRONZE] * 3)
101. hand = [] # Your hand starts with no dice.
102. print('It is ' + playerNames[turn] + '\'s turn.')
103. while True: # Each iteration of this loop is rolling the dice.
104. print()
105.
106. # Check that there's enough dice left in the cup:
107. if (3 - len(hand)) > len(cup):
108. # End this turn because there are not enough dice:
109. print('There aren\'t enough dice left in the cup to '
110. + 'continue ' + playerNames[turn] + '\'s turn.')
111. break
112.
113. # Pull dice from the cup until you have 3 in your hand:
114. random.shuffle(cup) # Shuffle the dice in the cup.
115. while len(hand) < 3:
116. hand.append(cup.pop())
117.
118. # Roll the dice:
119. rollResults = []
120. for dice in hand:
121. roll = random.randint(1, 6)
122. if dice == GOLD:
123. # Roll a gold die (3 stars, 2 questions, 1 skull):
124. if 1 <= roll <= 3:
125. rollResults.append(STAR_FACE)
126. stars += 1
127. elif 4 <= roll <= 5:
128. rollResults.append(QUESTION_FACE)
129. else:
130. rollResults.append(SKULL_FACE)
131. skulls += 1
132. if dice == SILVER:
133. # Roll a silver die (2 stars, 2 questions, 2 skulls):
134. if 1 <= roll <= 2:
135. rollResults.append(STAR_FACE)
136. stars += 1
137. elif 3 <= roll <= 4:
138. rollResults.append(QUESTION_FACE)
139. else:
140. rollResults.append(SKULL_FACE)
141. skulls += 1
142. if dice == BRONZE:
143. # Roll a bronze die (1 star, 2 questions, 3 skulls):
144. if roll == 1:
145. rollResults.append(STAR_FACE)
146. stars += 1
147. elif 2 <= roll <= 4:
148. rollResults.append(QUESTION_FACE)
149. else:
150. rollResults.append(SKULL_FACE)
151. skulls += 1
152.
153. # Display roll results:
154. for lineNum in range(FACE_HEIGHT):
155. for diceNum in range(3):
156. print(rollResults[diceNum][lineNum] + ' ', end='')
157. print() # Print a newline.
158.
159. # Display the type of dice each one is (gold, silver, bronze):
160. for diceType in hand:
161. print(diceType.center(FACE_WIDTH) + ' ', end='')
162. print() # Print a newline.
163.
164. print('Stars collected:', stars, ' Skulls collected:', skulls)
165.
166. # Check if they've collected 3 or more skulls:
167. if skulls >= 3:
168. print('3 or more skulls means you\'ve lost your stars!')
169. input('Press Enter to continue...')
170. break
171.
172. print(playerNames[turn] + ', do you want to roll again? Y/N')
173. while True: # Keep asking the player until they enter Y or N:
174. response = input('> ').upper()
175. if response != '' and response[0] in ('Y', 'N'):
176. break
177. print('Please enter Yes or No.')
178.
179. if response.startswith('N'):
180. print(playerNames[turn], 'got', stars, 'stars!')
181. # Add stars to this player's point total:
182. playerScores[playerNames[turn]] += stars
183.
184. # Check if they've reached 13 or more points:
185. # (!) Try changing this to 5 or 50 points.
186. if (endGameWith == None
187. and playerScores[playerNames[turn]] >= 13):
188. # Since this player reached 13 points, play one more
189. # round for all other players:
190. print('\n\n' + ('!' * 60))
191. print(playerNames[turn] + ' has reached 13 points!!!')
192. print('Everyone else will get one more turn!')
193. print(('!' * 60) + '\n\n')
194. endGameWith = playerNames[turn]
195. input('Press Enter to continue...')
196. break
197.
198. # Discard the stars and skulls, but keep the question marks:
199. nextHand = []
200. for i in range(3):
201. if rollResults[i] == QUESTION_FACE:
202. nextHand.append(hand[i]) # Keep the question marks.
203. hand = nextHand
204.
205. # Move on to the next player's turn:
206. turn = (turn + 1) % numPlayers
207.
208. # If the game has ended, break out of this loop:
209. if endGameWith == playerNames[turn]:
210. break # End the game.
211.
212. print('The game has ended...')
213.
214. # Display everyone's score:
215. print()
216. print('SCORES: ', end='')
217. for i, name in enumerate(playerNames):
218. print(name + ' = ' + str(playerScores[name]), end='')
219. if i != len(playerNames) - 1:
220. # All but the last player have commas separating their names.
221. print(', ', end='')
222. print('\n')
223.
224. # Find out who the winners are:
225. highestScore = 0
226. winners = []
227. for name, score in playerScores.items():
228. if score > highestScore:
229. # This player has the highest score:
230. highestScore = score
231. winners = [name] # Overwrite any previous winners.
232. elif score == highestScore:
233. # This player is tied with the highest score.
234. winners.append(name)
235.
236. if len(winners) == 1:
237. # There is only one winner:
238. print('The winner is ' + winners[0] + '!!!')
239. else:
240. # There are multiple tied winners:
241. print('The winners are: ' + ', '.join(winners))
242.
243. print('Thanks for playing!')
After entering the source code and running it a few times, try making experimental changes to it. The comments marked with (!)
have suggestions for small changes you can make.
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.
random.shuffle(cup)
on line 114?skulls >= 3
on line 167 to skulls > 3
?(turn + 1) % numPlayers
on line 206 to (turn + 1)
?endGameWith = None
on line 84 to endGameWith = playerNames[0]
?break
on line 170?playerScores[response] = 0
on line 76 to playerScores[response] = 10
?