8
\$\begingroup\$

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 <=1):
            print ("Machine balance reset.")
            balance = 1000

        print ("The Jackpot is currently: £" + str(balance) + ".")
        answer = input("Would you like to play? Or check your money? ")
        answer = answer.lower()
        if(answer == "yes" or answer == "y"):
            return True
        elif(answer == "no" or answer == "n"):
            print("You ended the game with £" + str(stake) + " in your hand. Great job!")
            time.sleep(5)
            return False
        elif(answer == "check" or answer == "CHECK"):
            print ("You currently have £" + str(stake) + ".")
        else:
            print("Whoops! Didn't get that.")

def spinWheel():
    '''
    returns a random item from the wheel
    '''
    randomNumber = random.randint(0, 5)
    return ITEMS[randomNumber]

def printScore():
    '''
    prints the current score
    '''
    global stake, firstWheel, secondWheel, thirdWheel, balance
    if((firstWheel == "CHERRY") and (secondWheel != "CHERRY")):
        win = 2
        balance = balance - 2
    elif((firstWheel == "CHERRY") and (secondWheel == "CHERRY") and (thirdWheel != "CHERRY")):
        win = 5
        balance = balance - 5
    elif((firstWheel == "CHERRY") and (secondWheel == "CHERRY") and (thirdWheel == "CHERRY")):
        win = 7
        balance = balance - 7
    elif((firstWheel == "ORANGE") and (secondWheel == "ORANGE") and ((thirdWheel == "ORANGE") or (thirdWheel == "BAR"))):
        win = 10
        balance = balance - 10
    elif((firstWheel == "PLUM") and (secondWheel == "PLUM") and ((thirdWheel == "PLUM") or (thirdWheel == "BAR"))):
        win = 14
        balance = balance - 14
    elif((firstWheel == "BELL") and (secondWheel == "BELL") and ((thirdWheel == "BELL") or (thirdWheel == "BAR"))):
        win = 20
        balance = balance - 20
    elif((firstWheel == "BAR") and (secondWheel == "BAR") and (thirdWheel == "BAR")):
        win = 250
        balance = balance - 250
    elif((firstWheel == "7") and (secondWheel == "7") and (thridWheel == "7")):
        win = balance
        balance = balance - win
    else:
        win = -1
        balance = balance + 1

    stake += win
    if win == balance:
        print ("You won the JACKPOT!!")
    if(win > 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()
\$\endgroup\$
  • 2
    \$\begingroup\$ Avoid time.sleep \$\endgroup\$ – Caridorc Jul 22 '15 at 12:46
6
\$\begingroup\$

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 <= 1:
                print("Machine balance reset.")
                self.current_jackpot = SlotMachine.INITIAL_JACKPOT

            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.")

    def _play_round(self):
        first, second, third = random.choice(SlotMachine._values), random.choice(SlotMachine._values), random.choice(SlotMachine._values)
        self._adjust_score(first, second, third)

    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

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


if __name__ == '__main__':
    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!
''')
    SlotMachine().play()
\$\endgroup\$
3
\$\begingroup\$

There are 6 global variables in your file. Considering a simple app that is 10x the lines of code of this, you would have written 60 global variables. Each global variable by definition can be modified from anywhere in the code. This is impossible to keep track of. Each function should be as pure as possible, taking input and giving output not caring of the state of the world.

\$\endgroup\$
2
\$\begingroup\$

Please follow PEP8, the coding style guide.

Use boolean expressions directly, no need to have condition == True

Avoid global variables. If many methods share data, consider moving the method and the common variables to a class.

Avoid duplicated string literals like "ORANGE".

Avoid duplicated logic, especially when it depends on the operating system like clearing the screen. Encapsulate this in a function.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.