-
Notifications
You must be signed in to change notification settings - Fork 14
/
slotmachine0_4.py
569 lines (498 loc) · 21.4 KB
/
slotmachine0_4.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
# Source File Name: slotmachine0_2.py
# Author's Name: Aldrin Jerome Almacin
# Last Modified By: Aldrin Jerome Almacin
# Date Last Modified: June 1, 2013
"""
Program Description: This program is a Casino-style slot machine.
The player is given cash to begin the game and he plays the slot machine to earn more cash. He is given a fair chance of winning the game.
Winning an additional jackpot price is also possible when the user gets 3 pairs. The user can also reset or quit the game if desired.
Version: 0.4: Renamed the game
"""
# import statements
import random
import pygame
import time
# Initialize pygame
pygame.init()
# Initialize game constants
FRAME_RATE = 30
GAME_TITLE = "Slot Machine"
BACKGROUND_IMAGE_NAME = "images/background.png"
"""
Class: SlotMachineButton
Description: A generic slot machine button. It only have an image positioned in the screen.
"""
class SlotMachineButton(pygame.sprite.Sprite):
def __init__(self, image_file_name, pos):
pygame.sprite.Sprite.__init__(self)
# Load the png image with transparency
self.image = pygame.image.load("images/" + image_file_name)
self.image = self.image.convert_alpha()
# Move the rect to make sure it follows the image
self.rect = self.image.get_rect()
self.rect = self.rect.move(pos)
self.pos = pos
"""
Class: SlotMachineBetButton
Description: Sprite used as a button that has a bet value.
"""
class SlotMachineBetButton(SlotMachineButton):
"""
Constructor:
params:
image_file_name: @override
bet_value: The bet value.
pos: @override
"""
def __init__(self, image_file_name, bet_value, pos):
SlotMachineButton.__init__(self, image_file_name, pos)
self.bet_value = bet_value
"""
Class: SlotMachineActionButton
Description: Slot machine button that can call a function/method
"""
class SlotMachineActionButton(SlotMachineButton):
"""
Constructor:
params:
image_file_name: @override
function_callable: The method to be called when this button is clicked
pos: @override
"""
def __init__(self, image_file_name, function_callable, pos):
SlotMachineButton.__init__(self, image_file_name, pos)
self.function_callable = function_callable
"""
Function: Execute Func
Purpose: Executes the function callable
"""
def execute_func(self):
self.function_callable()
"""
Class: SlotMachine
Description: The slot machine which is the main game object. All the methods required when playing a slot machine is included in this class.
"""
class SlotMachine:
MAIN_MSG = "Aldrin's Slot Machine"
YOU_WIN = "You just won $"
YOU_WIN_JACKPOT = "Jackpot won $"
YOU_LOST = "You just lost $"
YOU_BET = "You bet $"
NO_CASH_LEFT = "Cannot bet to that amount. Cash not enough."
CANNOT_SPIN = "Cannot spin. Change bet to a lower value."
STARTING_BET = 10
JACKPOT_INCREASE_RATE = .15
"""
Constructor:
params:
starting_jackpot: The jackpot price to start the game with
starting_cash: The Starting cash when the game starts
"""
def __init__(self, starting_jackpot, starting_cash):
# Set all the sounds
pygame.mixer.init()
self.bet_snd = pygame.mixer.Sound("sounds/bet_snd.wav")
self.bet_no_cash_snd = pygame.mixer.Sound("sounds/bet_no_cash_snd.wav")
self.spin_snd = pygame.mixer.Sound("sounds/spin_snd.ogg")
self.spinning_snd = pygame.mixer.Sound("sounds/spinning_snd.ogg")
self.reset_snd = pygame.mixer.Sound("sounds/reset_snd.ogg")
# Set Starting values
self.starting_jackpot = starting_jackpot
self.starting_cash = starting_cash
# Set the icons/images that would be in the reels
self.icons = []
self.__create_icons()
# Call the method used to set the initial values
self.set_resettable_values()
"""
Method: Set resettable values
Description: Set the values of the slot machine which are resettable
"""
def set_resettable_values(self):
self.current_message = SlotMachine.MAIN_MSG
self.current_jackpot = self.starting_jackpot
self.current_cash = self.starting_cash
self.results = 3*["Siete"]
self.bet = SlotMachine.STARTING_BET
"""
Method: __create_icons
Purpose: Private method used to create and set icons in an array.
"""
def __create_icons(self):
# The bonus win rate is for when no sad face is on the reel
self.icons.append(Icon("Sad Face", 0, 0, "sadface.png", bonus_win_rate = 1))
self.icons.append(Icon("Katipunero Hat", 10, 1, "katipunero_hat.png"))
self.icons.append(Icon("Bandana", 20, 2, "bandana.png"))
self.icons.append(Icon("Camesa De Chino", 30, 2, "camesa_de_chino.png"))
self.icons.append(Icon("Banyal", 100, 2, "banyal.png"))
self.icons.append(Icon("Tsinelas", 200, 2, "tsinelas.png"))
self.icons.append(Icon("Arnis", 300, 5, "arnis.png"))
self.icons.append(Icon("Siete", 1000, 10, "siete.png", bonus_win_rate = 5))
"""
Method: Set bet
Purpose: Method used to set a bet. When valid, the user is allowed to bet. If not, then tell the user he's out of cash.
"""
def set_bet(self, bet):
if self.current_cash - bet >= 0:
self.bet = bet
self.current_message = SlotMachine.YOU_BET + str(self.bet)
self.bet_snd.play()
else:
self.current_message = SlotMachine.NO_CASH_LEFT
self.bet_no_cash_snd.play()
"""
Group of Functions: Getters
Purpose: These methods are used to get attributes as a method.
"""
def get_bet(self):
return self.bet
def get_current_cash(self):
return self.current_cash
def get_current_jackpot(self):
return self.current_jackpot
def get_current_message(self):
return self.current_message
"""
Method: Spin
Purpose: Method used to spin the reels in the slot machine. It generates spin values to be used as spin data. Spinning is only allowed when there is enough money to do so.
"""
def spin(self):
if self.current_cash - self.bet >= 0:
self.spin_snd.play()
# pay the bet and increase the jackpot
self.__pay()
self.__increase_jackpot()
# For each reel
for spin in range(3):
# Save the wildcard number as spinned_result
spinned_result = random.randint(0, 100)
if spinned_result in range(0, 40): # 40% Chance
self.results[spin] = self.icons[0].name
elif spinned_result in range(40, 56): # 16% Chance
self.results[spin] = self.icons[1].name
elif spinned_result in range(56, 70): # 14% Chance
self.results[spin] = self.icons[2].name
elif spinned_result in range(70, 82): # 12% Chance
self.results[spin] = self.icons[3].name
elif spinned_result in range(82, 89): # 7% Chance
self.results[spin] = self.icons[4].name
elif spinned_result in range(89, 95): # 6% Chance
self.results[spin] = self.icons[5].name
elif spinned_result in range(95, 99): # 4% Chance
self.results[spin] = self.icons[6].name
elif spinned_result in range(99, 100): # 1% Chance
self.results[spin] = self.icons[7].name
# Check what does the result of the calculation rewards.
self.__check_results()
else:
# Show the message why the slot machine cannot be spinned
self.current_message = SlotMachine.CANNOT_SPIN
"""
Method: Pay
Purpose: Private method used to reduce the cash using the bet amount. Pays for one spin.
"""
def __pay(self):
self.current_cash -= self.bet
"""
Method: Increase jackpot
Purpose: Private method used to increase the jackpot prize to be winned.
"""
def __increase_jackpot(self):
self.current_jackpot += (int(self.bet * SlotMachine.JACKPOT_INCREASE_RATE))
"""
Method: Check results
Purpose: Check how much the player won or lost
"""
def __check_results(self):
winnings = 0
jackpot_won = 0
# Go through each icon and check how many of the said icon is present. Base on that, check how much the player have won.
for icon in self.icons:
# Check how many of this icon is on the reel. Multiply the win rate to the bet and add it to winnings.
if self.results.count(icon.name) == 3:
winnings += self.bet * icon.win_rate_full
# Play jackpot when 3 of a kind and not sadface is the result
if winnings > 0:
jackpot_won = self.jackpot_win()
if self.results.count(icon.name) == 2:
winnings += self.bet * icon.win_rate_two
# If there is 1 Siete, it is considered a win
if self.results.count(self.icons[7].name) == 1:
winnings += self.bet * self.icons[7].bonus_win_rate
# If there is no sad face, it is considered a bet return win
if self.results.count(self.icons[0].name) == 0:
winnings += self.bet * self.icons[0].bonus_win_rate
# If the winner won the jackpot or the winner just won something or the winner lost
# Set the appropriate message
if jackpot_won > 0:
self.current_message = SlotMachine.YOU_WIN_JACKPOT + str(jackpot_won) + " With Cash $" + str(winnings)
elif winnings > 0:
self.current_cash += winnings
self.current_message = SlotMachine.YOU_WIN + str(winnings)
elif winnings <= 0:
self.current_message = SlotMachine.YOU_LOST + str(self.bet)
else:
self.current_message = "Somethings wrong"
"""
Method: Jackpot win
Purpose: Play the jackpot and return the value of the player's jackpot price.
Returns: The jackpot winnings
"""
def jackpot_win(self):
# Set the wildcard jackpot number
JACKPOT_WILDCARD = 7
# Generate a random number from 1 to 100
jackpot_try = random.randint(1, 100)
winnings = 0
# Compare the wildcard to the random number
if jackpot_try == JACKPOT_WILDCARD:
# If they match, then the user wins
self.current_cash += self.current_jackpot
# Set the current jackpot as the winnings. This is done before resetting the jackpot price to the starting jackpot value.
winnings = self.current_jackpot
# Reset the jackpot
self.current_jackpot = self.starting_jackpot
return winnings
"""
Method: Reset
Purpose: Resets the slot machine to its default values when the slot machine started.
"""
def reset(self):
self.set_resettable_values()
"""
Class: Icon
Description: The icons shown inside the reels
"""
class Icon(pygame.sprite.Sprite):
"""
Constructor:
params:
name: The name of the icon
win_rate_full: The winning rate when 3 of these icons are selected
win_rate_two: The winning rate when 2 of these icons are selected
icon_image: The file name of the image of this sprite
bonus_win_rate: Optional win rate for special icons
"""
def __init__(self, name, win_rate_full, win_rate_two, icon_image, bonus_win_rate = 0):
pygame.sprite.Sprite.__init__(self)
self.name = name
self.image = pygame.image.load("images/" + icon_image)
self.image = self.image.convert_alpha()
self.rect = self.image.get_rect()
self.win_rate_full = win_rate_full
self.win_rate_two = win_rate_two
self.bonus_win_rate = bonus_win_rate
"""
Class: DigitalFont
Description: An object that shows a text label using the digital font ttf.
"""
class DigitalFont(pygame.sprite.Sprite):
"""
Constructor:
params:
method: The method that is used to grab the right message
pos: The text's position in the screen
color: Optional parameter which is the color of the text
"""
def __init__(self, method, pos, color = (196,65,46)):
pygame.sprite.Sprite.__init__(self)
self.digital_font = pygame.font.Font("fonts/DS-DIGIT.TTF", 22)
self.font_color = color
self.meth = method
self.pos = pos
"""
Method: Get rendered surface
Purpose: Returns the rendered text
Returns: The rendered text
"""
def get_rendered_surface(self):
return self.digital_font.render(str(self.meth()), 1, self.font_color)
"""
Method: Update
Purpose: Render the text
"""
def update(self):
self.digital_font.render(str(self.meth()), 1, self.font_color)
"""
Function: Start game
Purpose: Starts the slot machine game
"""
def start_game():
# Assign the Display Variables
background = pygame.image.load(BACKGROUND_IMAGE_NAME)
screen = pygame.display.set_mode(background.get_size())
pygame.display.set_caption(GAME_TITLE)
# Create the slot machine object and hashes to be used by the game
slot_machine = SlotMachine(10000, 1000)
spin_results = slot_machine.results
icon_images = [] # The current icon images or spin result icons
# Create the text labels
digital_fonts_hash = [
{"method": slot_machine.get_bet, "pos": (245, 424)},
{"method": slot_machine.get_current_cash, "pos": (80, 424)},
{"method": slot_machine.get_current_jackpot, "pos": (445, 424)},
]
digital_fonts = pygame.sprite.Group()
current_message_digifont = DigitalFont(slot_machine.get_current_message, (100, 140), (0, 0, 0))
for digital_font in digital_fonts_hash:
digital_fonts.add(DigitalFont(digital_font["method"], digital_font["pos"]))
# Set the constants
BUTTON_BOTTOM_POS = background.get_height() - 165
# Create the bet buttons
bet_buttons_hash = [
{"image_file_name": "ten_button.png", "bet_value": 10, "pos": (70, BUTTON_BOTTOM_POS)},
{"image_file_name": "twenty_button.png", "bet_value": 20, "pos": (140, BUTTON_BOTTOM_POS)},
{"image_file_name": "fifty_button.png", "bet_value": 50, "pos": (490, BUTTON_BOTTOM_POS)},
{"image_file_name": "hundred_button.png", "bet_value": 100, "pos": (560, BUTTON_BOTTOM_POS)}
]
bet_buttons = pygame.sprite.Group()
for bet_button in bet_buttons_hash:
bet_buttons.add(SlotMachineBetButton(bet_button["image_file_name"], bet_button["bet_value"], bet_button["pos"]))
# Create the action buttons
spin_button = SlotMachineActionButton("spin_button.png" , slot_machine.spin, (270, BUTTON_BOTTOM_POS))
reset_button = SlotMachineActionButton("reset_button.png" , slot_machine.reset, (210, BUTTON_BOTTOM_POS + 30))
quit_button = SlotMachineActionButton("quit_button.png" , slot_machine.reset, (422, BUTTON_BOTTOM_POS + 30))
action_buttons = pygame.sprite.Group(spin_button, reset_button, quit_button)
# Create all the symbols/icons to be shown in the reels
all_symbols = pygame.sprite.Group()
icons = slot_machine.icons
for icon in icons:
all_symbols.add(icon)
# Set the game clock
clock = pygame.time.Clock()
# The reel positions is saved as an array with tuples
reel_positions = [(75, 258), (265, 258), (445, 258)]
# Add the spin result symbols to icon images
for symbol in all_symbols:
for symbol_name in spin_results:
if (symbol.name == symbol_name):
icon_images.append(symbol)
# Set the variables to be used by the game loop
start_time = 0
spinning = False
# Set the previous spin results
prev_results = slot_machine.results
#Play the bg music
pygame.mixer.music.load("sounds/background_msc.wav")
pygame.mixer.music.play(-1)
# Set the current slot machine values as previous values
prev_bet, prev_jackpot, prev_current_msg, prev_cash = slot_machine.bet, slot_machine.current_jackpot, slot_machine.current_message, slot_machine.current_cash
# Create functions used to get the previous slot machine values
def prev_get_bet():
return prev_bet
def prev_get_current_cash():
return prev_cash
def prev_get_current_jackpot():
return prev_jackpot
def prev_get_current_msg():
return prev_current_msg
# Set the text values as the previous values
# The reason this is done is to not let the user see how much he won until the spin animation is done
prev_bet_digifont = DigitalFont(prev_get_bet, (245, 424))
prev_cash_digifont = DigitalFont(prev_get_current_cash, (80, 424))
prev_jackpot_digifont = DigitalFont(prev_get_current_jackpot, (445, 424))
prev_message_digifont = DigitalFont(prev_get_current_msg, (100, 140), (0, 0, 0))
# Create the sprite group digifonts
# The prev digifonts are the ones to be shown to the user while the spin animation is still running.
prev_digifonts = pygame.sprite.Group(prev_bet_digifont, prev_jackpot_digifont, prev_cash_digifont, prev_message_digifont)
# Continue looping while the player hasn't ended the game
continue_playing = True
while (continue_playing):
# Tick
clock.tick(FRAME_RATE)
# Check for events
for event in pygame.event.get():
# Stop the loop when the user chooses to quit the game
if (event.type == pygame.QUIT):
continue_playing = False
# When the user pushes the mouse button down, Check which sprites are involved
elif (event.type == pygame.MOUSEBUTTONDOWN):
# Check if a bet button is clicked then set the bet value to the value of that button
for bet_button in bet_buttons:
if(bet_button.rect.collidepoint(event.pos)):
slot_machine.set_bet(bet_button.bet_value)
# Check if spin button is clicked
if(spin_button.rect.collidepoint(event.pos)):
# Make sure you cant click the spin button while the reels are spinning
if not spinning:
# Execute the function inside the spin button. It would be slot_machine.spin()
spin_button.execute_func()
# If the message in the slot machine says the user cannot spin the reels, nothing happens. But if it is not then do the spin and set the spin results in the icon images
if slot_machine.current_message != SlotMachine.CANNOT_SPIN:
spin_results = slot_machine.results
# Set the result's icon into icon_images
icon_images = []
for symbol in all_symbols:
for symbol_name in spin_results:
if (symbol.name == symbol_name):
icon_images.append(symbol)
# Set the start time to current time. Making the spin animation run
start_time = time.time()
# Set spinning to true to make sure the user can't click spin again while spinning
spinning = True
else:
slot_machine.bet_no_cash_snd.play()
# If it is the reset button, call the function associated with the button and play the reset sound
elif(reset_button.rect.collidepoint(event.pos)):
slot_machine.reset_snd.play()
reset_button.execute_func()
# If the quit button is clicked, stop the loop
elif(quit_button.rect.collidepoint(event.pos)):
continue_playing = False
# Display the sprites
# Display the background image
screen.blit(background, background.get_rect())
# Update the action buttons and position them on the screen
action_buttons.update()
for action_button in action_buttons:
screen.blit(action_button.image, action_button.pos)
# Update the texts
digital_fonts.update()
# Update the bet buttons and position them on the screen
bet_buttons.update()
for bet_button in bet_buttons:
screen.blit(bet_button.image, bet_button.pos)
# This section is the one responsible for the reel animation
# While the current time - the time the spin button is clicked is less than one
# Change the images in the reel and show the previous/current texts
if time.time() - start_time < 1 and spinning:
# Display the current icons in the reel so it does not change until the pulling the lever sound is finished
for i in range(3):
screen.blit(prev_results[i].image, reel_positions[i])
# Display the current texts
for digital_font in prev_digifonts:
screen.blit(digital_font.get_rendered_surface(), digital_font.pos)
elif time.time() - start_time < 2 and spinning:
# Display a random icon in each reel and play the spinning sound
for i in range(3):
screen.blit(icons[random.randint(0, len(icons) - 1)].image, reel_positions[i])
slot_machine.spinning_snd.play()
# Display the current texts
for digital_font in prev_digifonts:
screen.blit(digital_font.get_rendered_surface(), digital_font.pos)
else:
# The animation is done and display the resulted values
for i in range(3):
screen.blit(icon_images[i].image, reel_positions[i])
screen.blit(current_message_digifont.get_rendered_surface(), current_message_digifont.pos)
# Spinning is now false. The user can hit spin again
spinning = False
# Set the prev results to the current images to be used again on animation
prev_results = icon_images
# Stop the spinning sound if playing
slot_machine.spinning_snd.stop()
# Render the current texts in the screen
for digital_font in digital_fonts:
screen.blit(digital_font.get_rendered_surface(), digital_font.pos)
# Reset the prev values
prev_bet, prev_jackpot, prev_current_msg, prev_cash = slot_machine.bet, slot_machine.current_jackpot, slot_machine.current_message, slot_machine.current_cash
# Refresh the display
pygame.display.flip()
"""
Function: Main
Purpose: Calls the start game function
"""
def main():
start_game()
#Calls the main function
if __name__ == "__main__": main()