Lucky Stars
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.
lucky_stars.py
1"""Lucky Stars, by Al Sweigart al@inventwithpython.com
2A "press your luck" game where you roll dice to gather as many stars
3as possible. You can roll as many times as you want, but if you roll
4three skulls you lose all your stars.
5
6Inspired by the Zombie Dice game from Steve Jackson Games.
7This code is available at https://nostarch.com/big-book-small-python-programming
8Tags: large, game, multiplayer"""
9
10import random
11
12# Set up the constants:
13GOLD = 'GOLD'
14SILVER = 'SILVER'
15BRONZE = 'BRONZE'
16
17STAR_FACE = ["+-----------+",
18 "| . |",
19 "| ,O, |",
20 "| 'ooOOOoo' |",
21 "| `OOO` |",
22 "| O' 'O |",
23 "+-----------+"]
24SKULL_FACE = ['+-----------+',
25 '| ___ |',
26 '| / \\ |',
27 '| |() ()| |',
28 '| \\ ^ / |',
29 '| VVV |',
30 '+-----------+']
31QUESTION_FACE = ['+-----------+',
32 '| |',
33 '| |',
34 '| ? |',
35 '| |',
36 '| |',
37 '+-----------+']
38FACE_WIDTH = 13
39FACE_HEIGHT = 7
40
41print("""Lucky Stars, by Al Sweigart al@inventwithpython.com
42
43A "press your luck" game where you roll dice with Stars, Skulls, and
44Question Marks.
45
46On your turn, you pull three random dice from the dice cup and roll
47them. You can roll Stars, Skulls, and Question Marks. You can end your
48turn and get one point per Star. If you choose to roll again, you keep
49the Question Marks and pull new dice to replace the Stars and Skulls.
50If you collect three Skulls, you lose all your Stars and end your turn.
51
52When a player gets 13 points, everyone else gets one more turn before
53the game ends. Whoever has the most points wins.
54
55There are 6 Gold dice, 4 Silver dice, and 3 Bronze dice in the cup.
56Gold dice have more Stars, Bronze dice have more Skulls, and Silver is
57even.
58""")
59
60print('How many players are there?')
61while 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
68playerNames = [] # List of strings of player names.
69playerScores = {} # Keys are player names, values are integer scores.
70for 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.')
79print()
80
81turn = 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
84endGameWith = None
85while 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
212print('The game has ended...')
213
214# Display everyone's score:
215print()
216print('SCORES: ', end='')
217for 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='')
222print('\n')
223
224# Find out who the winners are:
225highestScore = 0
226winners = []
227for 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
236if len(winners) == 1:
237 # There is only one winner:
238 print('The winner is ' + winners[0] + '!!!')
239else:
240 # There are multiple tied winners:
241 print('The winners are: ' + ', '.join(winners))
242
243print('Thanks for playing!')