You want less static code. Take calc
, you want to change it so you only have to define one print
.
And so the aim is:
print('You {} - {} {} {}'.format('win' if user_wins else 'lose', winner, ACTION[winner], looser))
Working backwards you should know who the winner and looser are if you know if the user wins.
Using tuple unpacking and the ternary operator you do this in one line:
winner, looser = (user, comp) if user_wins else (comp, user)
We then want you code to find user_wins
, if we stay with your current approach then we should get six ifs:
user_wins = True
if user == 0:
if comp == 1:
user_wins = False
elif user == 1:
if comp == 2:
user_wins = False
elif user == 2:
if comp == 0:
user_wins = False
We can actually simplify this. But it's easier to say it defaults to False, and we need to change it to True.
This makes the first computer if, if comp == 2
rather than if comp == 1
.
We then want to transform these to use and
and or
.
Which should get you:
user_wins = (
(user == 0 and comp == 2)
or (user == 1 and comp == 0)
or (user == 2 and comp == 1)
)
This should remind you of lists, and in
. And so you can make that code a list of tuple of ints, and use in
.
Which can result in:
user_wins = (user, comp) in [(0, 2), (1, 0), (2, 1)]
Which drastically simplifies your function.
You should also use more constants. The list from above, [(0, 2), (1, 0), (2, 1)]
, should be one.
Same with the numbers 0, 1, and 2. This is as it's easier to understand user == ROCK
rather than user == 0
.
And so I'd move the actions, smothers, smashes, and slices, to become a list.
The winning moves from above. The moves should also be constants.
And so you should have:
ROCK = 0
PAPER = 1
SCISSORS = 2
ACTION = ["smashes", "smothers", "slices"]
WIN_CONDITIONS = [(ROCK, SCISSORS), (PAPER, ROCK), (SCISSORS, PAPER)]
Finally I'd say you should simplify your input to move code, getUser
.
First, to follow the same style as a lot of Python programmers you should rename it to get_user
.
After this, you could use a datatype that's whole point is to simplify lookup.
In Python this is called a dictionary, aka dict
.
This stores a key and a value, we could input the key 'r' to output '0'.
Which can look like {'r': ROCK}
. After this we can add the two other moves.
However we'll have to use dict.get
, so that if it's not in the dictionary, we'll get None
.
This will allow us to implement the else
, of your current function.
But, I would change it so that it doesn't use recursion, as recursion has a limit.
Instead of doing getUser()
I'd use a while True
loop.
And have an if where if the input, after going through the dict, is not None
, we return the input.
All this together can get you:
from random import randint
ROCK = 0
PAPER = 1
SCISSORS = 2
ACTION = ["smashes", "smothers", "slices"]
WIN_CONDITIONS = [(ROCK, SCISSORS), (PAPER, ROCK), (SCISSORS, PAPER)]
USER_INPUT = {
'r': ROCK,
'rock': ROCK,
'p': PAPER,
'paper': PAPER,
's': SCISSORS,
'scissors': SCISSORS,
}
def getUser():
while True:
print('Rock, Paper, Scissors: ')
user_input = USER_INPUT.get(input().lower())
if user_input is not None:
return user_input
def display_winner(user, comp):
if user == comp:
print("Draw!")
else:
user_wins = (user, comp) in WIN_CONDITIONS
winner, looser = (user, comp) if user_wins else (comp, user)
print('You {} - {} {} {}'.format('win' if user_wins else 'lose', winner, ACTION[winner], looser))
if __name__ == '__main__':
again = 'yes'
while again != 'no':
display_winner(getUser(), randint(0, 2))
again = input('Would you like to play again? ')
print('Thank you for playing.')