HiveBrain v1.2.0
Get Started
← Back to all entries
patternpythonMinor

Slot Machine in Python

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
machinepythonslot

Problem

I have made this little program which allows you to play a slot machine:

import random
import time
import os
print()
print('''Welcome to the Slot Machine 
You'll start with £50. You'll be asked if you want to play.
Answer with yes/no. you can also use y/n
There is no case sensitivity, type it however you like!
To win you must get one of the following combinations:
BAR\tBAR\tBAR\t\tpays\t£250
BELL\tBELL\tBELL/BAR\tpays\t£20
PLUM\tPLUM\tPLUM/BAR\tpays\t£14
ORANGE\tORANGE\tORANGE/BAR\tpays\t£10
CHERRY\tCHERRY\tCHERRY\t\tpays\t£7
CHERRY\tCHERRY\t  -\t\tpays\t£5
CHERRY\t  -\t  -\t\tpays\t£2
7\t  7\t  7\t\tpays\t The Jackpot!
''')
time.sleep(10)
#Constants:
INIT_STAKE = 50
INIT_BALANCE = 1000
ITEMS = ["CHERRY", "LEMON", "ORANGE", "PLUM", "BELL", "BAR", "7"]

firstWheel = None
secondWheel = None
thirdWheel = None
stake = INIT_STAKE
balance = INIT_BALANCE

def play():
    global stake, firstWheel, secondWheel, thirdWheel
    playQuestion = askPlayer()
    while(stake != 0 and playQuestion == True):
        firstWheel = spinWheel()
        secondWheel = spinWheel()
        thirdWheel = spinWheel()
        printScore()
        playQuestion = askPlayer()

def askPlayer():
    '''
    Asks the player if he wants to play again.
    expecting from the user to answer with yes, y, no or n
    No case sensitivity in the answer. yes, YeS, y, y, nO . . . all works
    '''
    global stake
    global balance
    while(True):
        os.system('cls' if os.name == 'nt' else 'clear')
        if (balance  0):
        print(firstWheel + '\t' + secondWheel + '\t' + thirdWheel + ' -- You win £' + str(win))
        time.sleep(3)
        os.system('cls' if os.name == 'nt' else 'clear')
    else:
        print(firstWheel + '\t' + secondWheel + '\t' + thirdWheel + ' -- You lose')
        time.sleep(2)
        os.system('cls' if os.name == 'nt' else 'clear')

play()

Solution

I'd say you should encapsulate as much of your code as possible into functions and classes, limiting the global state when possible. This serves two purposes - the first is that it improves debugging (by limiting the odds that something unintentionally alters global state) and readability (by making it easier to understand what everything does).

Encapsulate functionality in a class

I'd create a class called SlotMachine that holds the global state. It should store constants as class-level variables, and other values as instance-variables (or better yet properties). Then all of your methods should belong to that class.

Keep related constants in an Enum

You have a bunch of constants related to what the slot reel is showing - these can be better described as an Enum

class Reel(Enum):
    CHERRY = 1
    LEMON = 2
    ORANGE = 3
    PLUM = 4
    BELL = 5
    BAR = 6
    SEVEN = 7


and then use Reel.CHERRY, for example, in the future. This also helps avoid magic numbers. If you don't have Python 3.4 or later you'll have to make your own homegrown Enum class, or use something like

def enum(*sequential, **named):
    enums = dict(zip(sequential, range(1, len(sequential) + 1)), **named)
    return type('Enum', (), enums)

Reel = enum("CHERRY", "LEMON", "ORANGE", "PLUM", "BELL", "BAR", "SEVEN")


or use the enum34 library which is a backport of 3.4's version of Enum.

Simplify boolean expressions

You don't need parentheses around your boolean expressions - they make it more confusing. Instead of something like answer == "yes" or answer == "y" you can do answer in ["yes", "y"].

Be clever with properties

Now that we're using a class, we can use a property to encapsulate behavior that you want. For example,

@property
def keep_playing(self):
    while(True):
        os.system('cls' if os.name == 'nt' else 'clear')
        if self.current_jackpot <= 1:
            print("Machine balance reset.")
            balance = 1000

        print("The Jackpot is currently: £{}.".format(self.current_jackpot))
        answer = input("Would you like to play? Or check your money? ").lower()
        if answer in ["yes", "y"]:
            return True
        elif answer in ["no", "n"]:
            print("You ended the game with £{} in your hand. Great job!".format(self.current_stake))
            return False
        elif answer == "check":
            print("You currently have £{}.".format(stake))
        else:
            print("Whoops! Didn't get that.")


now any time you want to find out if they want to keep playing, just use

if self.keep_playing:
    ...


Use dictionaries to simplify payout logic

Instead of all of those if statements, do something like this

payout = {
    Reel.CHERRY: 7,
    Reel.ORANGE: 10,
    Reel.PLUM: 14,
    Reel.BELL: 20,
    Reel.BAR: 250,
    Reel.SEVEN: 'jackpot'
}

def _adjust_score(first, second, third):
        if first == SlotMachine.Reel.CHERRY:
            if second == SlotMachine.Reel.CHERRY:
                win = 7 if third == SlotMachine.Reel.CHERRY else 5
            else:
                win = 2
        else:
            if first == second == third:
                win = SlotMachine.payout[first]
                win = self.current_jackpot if win == 'jackpot' else win
            else:
                win = -1

        if win == self.current_jackpot:
            print("You won the JACKPOT!!")
        else:
            print('\t'.join(map(lambda x: x.name.center(6), (first, second, third))))
            print("You {} £{}".format("won" if win > 0 else "lost", win)
            self.current_stake += win
            self.current_jackpot -= win


Note - your payout in the instructions isn't consistent with your logic, but I just kept it as your logic is. You can adjust this function and the dictionary to have more complicated arrangements and expand the payouts. Also, you're missing payouts for Lemons.

Altogether

```
import random
import time
import os
from enum import Enum

class SlotMachine:
INITIAL_STAKE = 50
INITIAL_JACKPOT = 1000

class Reel(Enum):
CHERRY = 1
LEMON = 2
ORANGE = 3
PLUM = 4
BELL = 5
BAR = 6
SEVEN = 7

_values = list(Reel)
payout = {
Reel.CHERRY: 7,
Reel.ORANGE: 10,
Reel.PLUM: 14,
Reel.BELL: 20,
Reel.BAR: 250,
Reel.SEVEN: 'jackpot'
}

def __init__(self, stake=INITIAL_STAKE, jackpot=INITIAL_JACKPOT):
self.current_stake = stake
self.current_jackpot = jackpot

@property
def keep_playing(self):
while(True):
os.system('cls' if os.name == 'nt' else 'clear')
if self.current_jackpot 0 else "lost", win))
self.current_stake += win
self.current_jackpot -= win

def play(self):
while self.current_stake and self.keep_playing:
self._play_round()

if __name__ == '__main__':
print('''
Welcom

Code Snippets

class Reel(Enum):
    CHERRY = 1
    LEMON = 2
    ORANGE = 3
    PLUM = 4
    BELL = 5
    BAR = 6
    SEVEN = 7
def enum(*sequential, **named):
    enums = dict(zip(sequential, range(1, len(sequential) + 1)), **named)
    return type('Enum', (), enums)

Reel = enum("CHERRY", "LEMON", "ORANGE", "PLUM", "BELL", "BAR", "SEVEN")
@property
def keep_playing(self):
    while(True):
        os.system('cls' if os.name == 'nt' else 'clear')
        if self.current_jackpot <= 1:
            print("Machine balance reset.")
            balance = 1000

        print("The Jackpot is currently: £{}.".format(self.current_jackpot))
        answer = input("Would you like to play? Or check your money? ").lower()
        if answer in ["yes", "y"]:
            return True
        elif answer in ["no", "n"]:
            print("You ended the game with £{} in your hand. Great job!".format(self.current_stake))
            return False
        elif answer == "check":
            print("You currently have £{}.".format(stake))
        else:
            print("Whoops! Didn't get that.")
if self.keep_playing:
    ...
payout = {
    Reel.CHERRY: 7,
    Reel.ORANGE: 10,
    Reel.PLUM: 14,
    Reel.BELL: 20,
    Reel.BAR: 250,
    Reel.SEVEN: 'jackpot'
}

def _adjust_score(first, second, third):
        if first == SlotMachine.Reel.CHERRY:
            if second == SlotMachine.Reel.CHERRY:
                win = 7 if third == SlotMachine.Reel.CHERRY else 5
            else:
                win = 2
        else:
            if first == second == third:
                win = SlotMachine.payout[first]
                win = self.current_jackpot if win == 'jackpot' else win
            else:
                win = -1

        if win == self.current_jackpot:
            print("You won the JACKPOT!!")
        else:
            print('\t'.join(map(lambda x: x.name.center(6), (first, second, third))))
            print("You {} £{}".format("won" if win > 0 else "lost", win)
            self.current_stake += win
            self.current_jackpot -= win

Context

StackExchange Code Review Q#97666, answer score: 8

Revisions (0)

No revisions yet.