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()
3 Answers 3
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()
-
\$\begingroup\$ Let us continue this discussion in chat. \$\endgroup\$Dan Oberlam– Dan Oberlam2015年07月25日 14:48:45 +00:00Commented Jul 25, 2015 at 14:48
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.
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.
Explore related questions
See similar questions with these tags.
time.sleep
\$\endgroup\$