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\t250ドル
BELL\tBELL\tBELL/BAR\tpays\t20ドル
PLUM\tPLUM\tPLUM/BAR\tpays\t14ドル
ORANGE\tORANGE\tORANGE/BAR\tpays\t10ドル
CHERRY\tCHERRY\tCHERRY\t\tpays\t7ドル
CHERRY\tCHERRY\t -\t\tpays\t5ドル
CHERRY\t -\t -\t\tpays\t2ドル
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()
Jamal
35.2k13 gold badges134 silver badges238 bronze badges
asked Jul 22, 2015 at 9:47
\$\endgroup\$
1
  • 2
    \$\begingroup\$ Avoid time.sleep \$\endgroup\$ Commented Jul 22, 2015 at 12:46

3 Answers 3

8
\$\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\t250ドル
BELL\tBELL\tBELL/BAR\tpays\t20ドル
PLUM\tPLUM\tPLUM/BAR\tpays\t14ドル
ORANGE\tORANGE\tORANGE/BAR\tpays\t10ドル
CHERRY\tCHERRY\tCHERRY\t\tpays\t7ドル
CHERRY\tCHERRY\t -\t\tpays\t5ドル
CHERRY\t -\t -\t\tpays\t2ドル
7\t 7\t 7\t\tpays\t The Jackpot!
''')
 SlotMachine().play()
Graipher
41.7k7 gold badges70 silver badges134 bronze badges
answered Jul 23, 2015 at 23:51
\$\endgroup\$
1
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.

answered Jul 22, 2015 at 14:58
\$\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.

answered Jul 22, 2015 at 10:12
\$\endgroup\$

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.