2
\$\begingroup\$

I made a 3 reel slot machine using the pygame library in Python. This is what I have so far.
I want to improve it to make it work for a 3x5 slot machine with multiple paylines, right now it is a 1x3 slot machine.
I also want to improve on my programming skills as I am still fairly new to programming and have only been doing it for about a year. If anyone has any recommendations on how to make this code cleaner or more efficient, let me know.
nums.json contains this list of numbers. I made this list of numbers so some icons have more weight than others, hence why some give the player more money.
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2 ]

This is the slotmachine class file.

import random
import json
f = open("nums.json")
nums = json.load(f)
class SlotMachine:
 def __init__(self, windict):
 self.windict = windict
 self.output = ""
 def play(self):
 num = random.choice(nums)
 self.output += str(num)
 return num
 def checkwin(self):
 if self.output in self.windict:
 win = str(self.windict[self.output] * 100)
 self.output = ""
 return win
 else:
 loss = "0"
 self.output = ""
 return loss

This is the main Python file.

import pygame
from slotmachine import SlotMachine
import time
pygame.init()
eagles = "The Best of My Love - On the Border (front).jpg"
beatles = "Abbey Road (front).jpg"
pink = "Wish you were here (front).jpg"
(width, height) = (800, 600)
screen = pygame.display.set_mode((width, height))
pygame.display.set_caption("Ryan's Slot Machine")
white = (255, 255, 255)
green = (0, 255, 0)
blue = (0, 0, 128)
screen.fill(white)
bg = pygame.image.load("border.png")
screen.blit(bg, (0, 0))
pygame.display.update()
picdict = {0: eagles, 1: beatles, 2: pink}
positions = ((200, 275), (350, 275), (497, 275))
slot = SlotMachine({"000": 1, "111": 2, "222": 5})
font = pygame.font.Font("freesansbold.ttf", 25)
def icon_to_screen(x, y, path):
 icon = pygame.image.load(path)
 small_icon = pygame.transform.scale(icon, (100,50))
 screen.blit(small_icon, (x, y))
 pygame.display.update()
 
def main():
 play = True
 while play:
 for event in pygame.event.get():
 if event.type == pygame.QUIT:
 play = False
 if event.type == pygame.KEYDOWN:
 if event.key == pygame.K_p:
 screen.fill(white)
 bg = pygame.image.load("border.png")
 screen.blit(bg, (0, 0))
 pygame.display.update()
 for position in positions:
 i = slot.play()
 icon_to_screen(position[0], position[1], picdict[i])
 time.sleep(.5)
 text = font.render(slot.checkwin(), True, green, blue)
 screen.blit(text, (670,36))
 pygame.display.update()
 
if __name__ == "__main__":
 main()
greybeard
7,4313 gold badges21 silver badges55 bronze badges
asked Jul 18, 2022 at 14:10
\$\endgroup\$

1 Answer 1

1
\$\begingroup\$

nums.json should have a better name like weights.json, and should only contain three numbers: the weights of each slot outcome, as in

 [ 10, 5, 2 ]

When you open this file, do so with a context manager.

picdict shouldn't be a dictionary: you have a simple integer index, so just make it a tuple.

Don't call random.choice; call random.choices passing your weights.

Don't make output stringly-typed. Build it up as a tuple of integers. Similarly, checkwin (which should be named check_win) should return an integer and not a string.

The logic in check_win can be simplified by unconditionally calling get on windict with a default of 0 for no winnings. Only reset output once.

Some of the simple constants like your colours can stay as capitalised constants in the global namespace. The rest of the global code should move into a function. One easy way to achieve this is to move the global code into the __init__ of a class.

play needs to go away, and you should just use a while True.

When you check KEYDOWN you should simultaneously check the key code after an and.

Add a constant for things like the antialias parameter to render().

Suggested

Only partially tested since I don't have your images:

import json
import random
import pygame
import time
WHITE = (255, 255, 255)
GREEN = (0, 255, 0)
BLUE = (0, 0, 128)
ANTIALIAS = True
with open("nums.json") as f:
 WEIGHTS = json.load(f)
class SlotMachine:
 def __init__(self, win_dict: dict[tuple[int, ...], int]):
 self.win_dict = win_dict
 self.output: tuple[int, ...] = ()
 def play(self) -> int:
 num, = random.choices(population=range(3), weights=WEIGHTS)
 self.output += num,
 return num
 def check_win(self) -> int:
 winnings = self.win_dict.get(self.output, 0)
 self.output = ()
 return 100 * winnings
class Game:
 WIDTH, HEIGHT = 800, 600
 POSITIONS = (200, 275), (350, 275), (497, 275)
 def __init__(self) -> None:
 pygame.init()
 pygame.display.set_caption("Ryan's Slot Machine")
 self.screen = pygame.display.set_mode((self.WIDTH, self.HEIGHT))
 self.screen.fill(WHITE)
 self.bg = pygame.image.load("border.png")
 self.screen.blit(self.bg, (0, 0))
 pygame.display.update()
 self.slot_pictures = (
 "The Best of My Love - On the Border (front).jpg",
 "Abbey Road (front).jpg",
 "Wish you were here (front).jpg",
 )
 self.machine = SlotMachine({(0, 0, 0): 1, (1, 1, 1): 2, (2, 2, 2): 5})
 self.font = pygame.font.Font("freesansbold.ttf", 25)
 def icon_to_screen(self, x: int, y: int, path: str) -> None:
 icon = pygame.image.load(path)
 small_icon = pygame.transform.scale(icon, (100, 50))
 self.screen.blit(small_icon, (x, y))
 pygame.display.update()
 def run(self) -> None:
 while True:
 for event in pygame.event.get():
 if event.type == pygame.QUIT:
 return
 if event.type == pygame.KEYDOWN and event.key == pygame.K_p:
 self.screen.fill(WHITE)
 self.screen.blit(self.bg, (0, 0))
 pygame.display.update()
 for x, y in self.POSITIONS:
 i = self.machine.play()
 self.icon_to_screen(x, y, self.slot_pictures[i])
 time.sleep(.5)
 winning_string = str(self.machine.check_win())
 foreground = GREEN
 background = BLUE
 text = self.font.render(winning_string, ANTIALIAS, foreground, background)
 self.screen.blit(text, (670, 36))
 pygame.display.update()
if __name__ == "__main__":
 Game().run()

You can further simplify by not keeping an output and not mutating the slot machine at all; just returning three reels at once; and including the factor of 100 in your winnings dictionary:

import json
import random
import pygame
import time
WHITE = (255, 255, 255)
GREEN = (0, 255, 0)
BLUE = (0, 0, 128)
ANTIALIAS = True
class SlotMachine:
 def __init__(self, win_dict: dict[tuple[int, ...], int]):
 with open("weights.json") as f:
 self.weights = json.load(f)
 self.win_dict = win_dict
 def play(self) -> list[int]: # reel positions
 return random.choices(population=range(3), weights=self.weights, k=3)
 def check_win(self, reels: list[int]) -> int:
 return self.win_dict.get(tuple(reels), 0)
class Game:
 WIDTH, HEIGHT = 800, 600
 POSITIONS = (200, 275), (350, 275), (497, 275)
 def __init__(self) -> None:
 pygame.init()
 pygame.display.set_caption("Ryan's Slot Machine")
 self.screen = pygame.display.set_mode((self.WIDTH, self.HEIGHT))
 self.screen.fill(WHITE)
 self.bg = pygame.image.load("border.png")
 self.screen.blit(self.bg, (0, 0))
 pygame.display.update()
 self.slot_pictures = (
 "The Best of My Love - On the Border (front).jpg",
 "Abbey Road (front).jpg",
 "Wish you were here (front).jpg",
 )
 self.machine = SlotMachine({
 (0, 0, 0): 100,
 (1, 1, 1): 200,
 (2, 2, 2): 500,
 })
 self.font = pygame.font.Font("freesansbold.ttf", 25)
 def icon_to_screen(self, x: int, y: int, path: str) -> None:
 icon = pygame.image.load(path)
 small_icon = pygame.transform.scale(icon, (100, 50))
 self.screen.blit(small_icon, (x, y))
 pygame.display.update()
 def run(self) -> None:
 while True:
 for event in pygame.event.get():
 if event.type == pygame.QUIT:
 return
 if event.type == pygame.KEYDOWN and event.key == pygame.K_p:
 self.screen.fill(WHITE)
 self.screen.blit(self.bg, (0, 0))
 pygame.display.update()
 reels = self.machine.play()
 for (x, y), reel in zip(self.POSITIONS, reels):
 self.icon_to_screen(x, y, self.slot_pictures[reel])
 time.sleep(.5)
 winning_string = str(self.machine.check_win(reels))
 foreground = GREEN
 background = BLUE
 text = self.font.render(winning_string, ANTIALIAS, foreground, background)
 self.screen.blit(text, (670, 36))
 pygame.display.update()
if __name__ == "__main__":
 Game().run()
answered Jul 19, 2022 at 1:23
\$\endgroup\$
0

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.