Python rock, paper, scissors game - python-3.x

I am using Python and I am trying to write a simple program that simulates a rock, paper, scissors game. Everything works except for when I enter an invalid response (something other than rock, paper, or scissors) when I get this error.
Traceback (most recent call last):
File "C:/Users/home/Desktop/BAGARDNER/Python/rock_pape_scissors.py", line 88, in <module>
main()
File "C:/Users/home/Desktop/BAGARDNER/Python/rock_pape_scissors.py", line 14, in main
number = user_guess()
File "C:/Users/home/Desktop/BAGARDNER/Python/rock_pape_scissors.py", line 48, in user_guess
return number
UnboundLocalError: local variable 'number' referenced before assignment
I understand that this is telling me that number isn't referenced, but from what I understand of the code, it shouldn't need a number when the qualifier is false.
#import random module
import random
#main function
def main():
#intro message
print("Let's play 'Rock, Paper, Scissors'!")
#call the user's guess function
number = user_guess()
#call the computer's number function
num = computer_number()
#call the results function
results(num, number)
#computer_number function
def computer_number():
#get a random number in the range of 1 through 3
num = random.randrange(1,4)
#if/elif statement
if num == 1:
print("Computer chooses rock")
elif num == 2:
print("Computer chooses paper")
elif num == 3:
print("Computer chooses scissors")
#return the number
return num
#user_guess function
def user_guess():
#get the user's guess
guess = input("Choose 'rock', 'paper', or 'scissors' by typing that word. ")
#while guess == 'paper' or guess == 'rock' or guess == 'scissors':
if is_valid_guess(guess):
#if/elif statement
#assign 1 to rock
if guess == 'rock':
number = 1
#assign 2 to paper
elif guess == 'paper':
number = 2
#assign 3 to scissors
elif guess == 'scissors':
number = 3
return number
else:
print('That response is invalid.')
user_guess()
def is_valid_guess(guess):
if guess == 'rock' or 'paper' or 'scissors':
status = True
else:
status = False
return status
def restart():
answer = input("Would you like to play again? Enter 'y' for yes or \
'n' for no: ")
#if/elif statement
if answer == 'y':
main()
elif answer == 'n':
print("Goodbye!")
else:
print("Please enter only 'y' or 'n'!")
#call restart
restart()
#results function
def results(num, number):
#find the difference in the two numbers
difference = num - number
#if/elif statement
if difference == 0:
print("TIE!")
#call restart
restart()
elif difference % 3 == 1:
print("I'm sorry! You lost :(")
#call restart
restart()
elif difference % 3 == 2:
print("Congratulations! You won :)")
#call restart
restart()
main()
Thank you for your help!

Here's your problem:
if guess == 'rock' or 'paper' or 'scissors':
This line in is_valid_guess doesn't do what you think it does. Instead, it always returns True. What you're looking for is something like this:
if guess == 'rock' or guess == 'paper' or guess == 'scissors':
or more concisely:
if guess in ('rock', 'paper', 'scissors'):
The problem is that what you have always returns True because of how Python evaluates strings in a boolean context. The line if guess == 'rock' or 'paper' or 'scissors': evaluates as:
if (guess == 'rock') or ('paper') or ('scissors'):
What this means is that Python checks to see if guess == 'rock'. If that's true, the conditional evaluates to True. If it's false, the interpreter tries to evaluate bool('paper'). This always evaluates to True because all non-empty strings are "truthy". Therefore, your whole conditional is always True, and every string is "valid".
As a result, your code considers all strings "valid" and then blows up when it fails to assign a number to a guess that is not actually supported.
As a final note, your is_valid_guess method could be trimmed a bit, since you're just returning the result of your boolean expression. Rather than using the status variable as an intermediate, you can just compute the expression and return it right away. I also use the lower() method of string objects to allow for case-insensitive guessing, in case that's something you want to allow.
def is_valid_guess(guess):
return guess.lower() in ('rock', 'paper', 'scissors')
You've got another issue, which you mentioned in the comments: you've implemented user_guess in a recursive fashion, so that it calls itself if the user enters an invalid guess. However, in this case, it does not return the result of the recursive call. You need to either return the recursive result by changing the last line of user_guess to:
return user_guess()
Or else you should make that function use a loop instead of recursion, which is what I would do, since the function is not inherently recursive. You can do something like this:
def user_guess():
# get first guess
guess = input("Choose 'rock', 'paper', or 'scissors' by typing that word. ")
# If that guess is invalid, loop until we get a valid guess.
while not is_valid_guess(guess):
print('That response is invalid.')
guess = input("Choose 'rock', 'paper', or 'scissors' by typing that word. ")
# Now assign the (valid!) guess a number
# This dictionary is just shorthand for your if/elif chain.
guess_table = {
'rock' : 1,
'paper' : 2,
'scissors' : 3
}
# Return the number associated with the guess.
return guess_table[guess.lower()]

Change
if guess == 'rock' or 'paper' or 'scissors':
to
if guess == 'rock' or guess == 'paper' or guess == 'scissors':
In fact, to make the function as streamlined as possible, just do this:
def is_valid_guess(guess):
return guess == 'rock' or guess == 'paper' or guess == 'scissors'

As other users have pointed out, you need to change your validation in is_valid_guess to:
if guess == 'rock' or guess == 'paper' or guess == 'scissors':
While this won't solve your immediate problem, it is good (upvote-worthy) advice, and will let you avoid some errors you would have run into.
Additionally, no matter what the user inputs, you always return what they type in. To prevent this, you must return user_guess() in your else block:
if is_valid_guess(guess):
#if/elif statement
#assign 1 to rock
if guess == 'rock':
number = 1
#assign 2 to paper
elif guess == 'paper':
number = 2
#assign 3 to scissors
elif guess == 'scissors':
number = 3
return number
else:
print('That response is invalid.')
return user_guess() # <-- right here

Just change input to raw_input

Related

exit(), conditionals, return or break on Python menu?

If we are doing a menu on python and the user selects option for finish the interaction. Is preferable to use exit(), conditionals, return or break?
Example with break, where we stop the infinite loop with the break:
def show_menu():
print('1. Pet kitten\n'
'0. Exit')
def start_app():
while True:
show_menu()
user_choice = input('Select an option: ')
if user_choice == '1':
pet()
elif user_choice == '0':
print('\nBye!')
break
else:
print('\nPlease select a number from the menu.')
start_app()
Example with exit(), where we use built-in function exit() for stop the execution of the script:
def show_menu():
print('1. Pet kitten\n'
'0. Exit')
def start_app():
while True:
show_menu()
user_choice = input('Select an option: ')
if user_choice == '1':
pet()
elif user_choice == '0':
print('\nBye!')
exit()
else:
print('\nPlease select a number from the menu.')
start_app()
Example with conditionals, where the while stops when the condition change:
def show_menu():
print('1. Pet kitten\n'
'0. Exit')
def start_app():
continue_ = True
while continue_:
show_menu()
user_choice = input('Select an option: ')
if user_choice == '1':
pet()
elif user_choice == '0':
print('\nBye!')
continue_ = False
else:
print('\nPlease select a number from the menu.')
start_app()
Example with return, where we finish the interaction returning a random value:
def show_menu():
print('1. Pet kitten\n'
'0. Exit')
def start_app():
continue_ = True
while continue_:
show_menu()
user_choice = input('Select an option: ')
if user_choice == '1':
pet()
elif user_choice == '0':
print('\nBye!')
return None
else:
print('\nPlease select a number from the menu.')
start_app()
It is worth noticing that your options fall into two categories, with one important difference between them.
On one hand, you can use break, return or a condition variable to break out of the loop and, eventually, return to the caller. Among these options, I'd say just pick whichever gives the cleanest code.
On the other hand, you can use exit() which ends the program there and then.
If you ever wish to use this as something other than a top-level menu, for example wrapped in a library to be used as a sub-menu of something else, you do not want the program to suddenly exit.
Generally, exit() is a rather big chunk of explosives, that should be treated with a bit of respect.
For example 1:
First give 4 space in line 2 so that the print function can stay into the show_menu() function and second define the #pet() function in line 11, otherwise you will get name error. Then put a break statement after line 11.
For example 3:
The while loop stop in line 15 when you define continue as False.
#HappyCoding

I don't understand this rock paper scissors game

I found this code, and I'm having trouble understanding the lines 'user_hand = rps[int(user_input) - 1]' , 'com_hand = choice(rps)' , ' if rps_dict[user_hand]['strong'] == com_hand:' , 'print_result(**game_result)' , '
Why should I subtract 1 from user_input? Why put rps inside brackets next to choice? Why do you win 'if rps_dict[user_hand]['strong'] == com_hand ? Why if user_hand equal to com_hand? It doesnt make sense to me.. I know '**game_result' means it's a kwark, but I dont know why I need to declare it as a kwarg. I'm sorry if these questions seem stupid, but I'm frustrated.
from random import choice
rps = ('rock', 'paper', 'scissors')
rps_dict = {
'rock': {'strong': 'scissors', 'weak': 'paper'},
'paper': {'strong': 'rock', 'weak': 'scissors'},
'scissors': {'strong': 'paper', 'weak': 'rock'}
}
def print_result(user_score, com_score, win, lose, tie):
print('Result:', end=' ')
if user_score > com_score:
print('You win!')
elif user_score < com_score:
print('You lose...')
else:
print('Draw.')
print('--------------------')
# Print scores
print(f'Your score: {user_score}')
print(f'Computer score: {com_score}')
print('--------------------')
# Print statistics
print(f'Win: {win}')
print(f'Lose: {lose}')
print(f'Tie: {tie}')
def play(rounds):
game_result = {
'user_score': 0,
'com_score': 0,
'win': 0,
'lose': 0,
'tie': 0
}
while rounds > 0:
user_input = input(
'Enter your choice (1: Rock, 2: Paper, 3: Scissors, 0: Quit): ')
# Check whether the input is in the options
if user_input in ('1', '2', '3'):
rounds -= 1
user_hand = rps[int(user_input) - 1]
com_hand = choice(rps)
# user_hand is strong against com_hand
if rps_dict[user_hand]['strong'] == com_hand:
game_result['user_score'] += 1
game_result['win'] += 1
result = 'You win!'
# user_hand is weak against com_hand
elif rps_dict[user_hand]['weak'] == com_hand:
game_result['com_score'] += 1
game_result['lose'] += 1
result = 'You lose...'
# Tie
else:
game_result['tie'] += 1
result = 'Tie.'
print(
f'You -> {user_hand}. Computer -> {com_hand}. {result}')
elif user_input == '0':
break
else:
print('Invalid input!')
print()
print_result(**game_result)
if __name__ == "__main__":
print('Welcome to Rock-Paper-Scissors Game!')
try:
rounds = int(input('How many rounds you want to play? '))
play(rounds)
except ValueError:
print('Please input a valid number!')
This is an interesting question, and I'll do my best to discuss the lines that you said you have trouble with:
user_hand = rps[int(user_input) - 1]
The user_hand variable is used to store the choice the user inputs. user_input is the text the user directley entered. This will be saved as a string, so the code stransforms it into an integer with the int class. Next, it subtracts one from the user input (computers count from zero rather than 1). Then, it grabs the element from the list that has that index. For example, if I entered one, it would grab the list item at index 0 ("rock").
com_hand = choice(rps)
This line here is used to gather the computer's choice. As you can see from the first line, the choice function from the random module is imported directly. This allows you to use the function without specifying the module it came from. The choice function selects a random item from the specified list, which is the same rps list as before.
if rps_dict[user_hand]['strong'] == com_hand:
The if statement here gathers data from the rps_dict and compares it to the computer's hand. The rps_dict is a dictionary that contains data on which hand beats or loses to another. To translate the if statement into simpler english, it means if the hand the user's hand would beat (which can be found with rps_dict[user_hand]["strong"]), is the computer's hand, the user will win. In addition, to avoid confusion, the == operator check's for equality, and doesn't assign the variable to com_hand.
print_result(**game_result)
Here you said that you don't understand why the parameters are passed in this way. You don't really need to do it in this format, but the person who created the script decided to (possibly as it is simpler to read).
Thank you, and if you have any other questions, please comment and I'll do my best to answer them!

How to access the variable delcared inside a function outside the function in Python 3?

I am trying to make a simple guess the number program in python. When I run this code,an error generates saying that,"local variable 'chance' referenced before assignment". I looked up for a solution on internet but I could not rectify my error. Please help with this problem. How can I use the variable globally which is declared inside a function?
I am beginner in programming, so plese explain in simple words.
Here is the code..
Since I am a beginner,I will be pleased if my code can be rectified
import random
def Random():
chance = 3
number = random.randint(0,20)
return chance
return number
def main():
while chance > 0:
UserInput = int(input('Guess the number: '))
if UserInput == number:
print('You have guesses the secret number!')
elif UserInput > 20 and UserInput < 0:
print('Your guess is out of range!\n Try again!')
else:
chance -= 1
if chance == 1:
print('You are out of chances!')
print('Wrong Guess!\nTry again!')
print(f'You have {chance} chances left!')
Random()
main()
playAgain = input('Want to play again? ')
if playAgain == 'yes' or 'YES' or 'Yeah' or 'yeah':
Random()
main()
else:
print('Thanks for playing!')
You can return a list or a tuple to the outside word:
import random
def example():
chance = 3
number = random.randint(0,20)
return (chance, number) # return both numbers as a tuple
chance, randNr = example() # decomposes the returned tuple
print(chance, randNr)
prints:
3, 17
There are more bugs in your program, f.e.:
if playAgain == 'yes' or 'YES' or 'Yeah' or 'yeah':
is always True and you'll never be able to leave the game. Better would be
if playAgain.lower() in {'yes', 'yeah'}:
etc.
Here is a working example for your programs purpose:
import random
while True:
chances = 3
number = random.randint(0,20)
while chances > 0:
guess = int(input("Guess number: "))
if guess == number:
print("Correct")
break
else:
chances -= 1
print("Wrong, ", chances, " more tries to get it right.")
if chances == 0:
print ("You failed")
if not input("Play again? ")[:1].lower() == "y":
break
print("Bye.")
Read about tuples
Output:
Guess number: 1
Wrong, 2 more tries to get it right.
Guess number: 4
Correct
Play again? y
Guess number: 1
Wrong, 2 more tries to get it right.
Guess number: 2
Wrong, 1 more tries to get it right.
Guess number: 3
Wrong, 0 more tries to get it right.
You failed
Play again? n
Bye.
import random
def Random():
chance = 3
number = random.randint(0,20)
main(chance,number)
def main(chance,number):
while chance > 0:
UserInput = int(input('Guess the number: '))
if UserInput == number:
print('You have guesses the secret number!')
elif UserInput > 20 and UserInput < 0:
print('Your guess is out of range!\n Try again!')
else:
chance -= 1
if chance == 1:
print('You are out of chances!')
print('Wrong Guess!\nTry again!')
print('You have',chance,'chances left!')
Random()
playAgain = input('Want to play again? ')
if playAgain == 'yes' or 'YES' or 'Yeah' or 'yeah':
Random()
else:
print('Thanks for playing!')

Problem with my small dictionary quiz. can someone explain this error please

d = {'Red': 1, 'Green': 2, 'Blue': 3}
for color_key, value in d.items():
userinput == (input(color_key))
if userinput == (d[color_key]):
print("correct")
else:
print("wrong")
Hi everyone, i am trying to simulate a quiz with this dictionary. I want to iterate through the dictionary and prompt the user for the questions (which is the key) (i.e what is the number for the colour: color_key). I then want the user to put the value for the key that corresponds to the right colour.
I am getting this error:
userinput == input(color_key)
NameError: name 'userinput' is not defined
Can anyone help me please.
Based on assumptions that you want to make kind of "memory" game with colors and integers, code proposal for your game would be something like this:
import random
d = {'Red': 1, 'Green': 2, 'Blue': 3}
while 1==1:
rand1 = random.choice(list(d))
user_input = input("Please guess the code of "+rand1+" color:\n")
try:
int(user_input)
if(int(user_input) == d[rand1]):
print("Color code is correct!")
else:
print("Color code is incorrect!")
except ValueError:
if(user_input.lower() == "quit"):
print("Program will terminate now")
else:
print("Invalid input provided.")
Take in consideration few things important for these kind of exercises:
Despite python is not strictly typizied language, you have to take
care of exceptions in the user input
"While 1==1" generates something
called "dead loop". Make sure you always have exit condition for this
one - In our case out here, that is keyword "quit" on the input.
In case of keyword "quit" on the input, it has to be validated for both
upper and lowercase
EDIT:
According to your newest update, I am providing you the example of simple 3-operations based game:
import random
def detect_string_operation(elem1, elem2, operator):
result = ""
if(operator == "+"):
result = str(elem1 + elem2)
elif(operator == "-"):
result = str(elem1 - elem2)
elif(operator == "*"):
result = str(elem1 * elem2)
elif(operator == "/"):
result = str(elem1/elem2)
return result
operators_list = ["+", "-", "*"]
while 1==1:
elem1 = random.randint(0, 10)
elem2 = random.randint(0, 10)
operator_index = random.randint(0, len(operators_list)-1)
result_operation = detect_string_operation(elem1, elem2, operators_list[operator_index])
user_input = input("Please calculate following: "+str(elem1)+str(operators_list[operator_index])+str(elem2)+"=")
try:
int(user_input)
if(user_input == result_operation):
print("Result is correct!")
else:
print("Result is incorrect!")
except ValueError:
if(user_input.lower() == "quit"):
print("Program will terminate now")
break
else:
print("Invalid input provided.")
Note that I didn't implement division for a reason: for division totally random choice of values is not an option, since we need an integer as a result of division. Algorithm for generating divisor and divider pair is quite simple to be implemented in iterative way, but it is out of scope of your initial question.

How to print if first condition is not met?

I'm practicing conditionals and logical operators.
How do I make the following rock, paper, scissors game print "This is not a valid object selection." immediately after Player 1's input, if Player 1 enters an invalid object? Right now the string is not printed until both players have entered an object.
Also, any suggestions for making the following code more elegant?
player1 = input('Player 1? ')
player2 = input('Player 2? ')
if (player1.lower() == 'rock' and
player2.lower() == 'rock'):
print('Tie.')
elif (player1.lower() == 'rock' and
player2.lower() == 'paper'):
print('Player 2 wins.')
elif (player1.lower() == 'rock' and
player2.lower() == 'scissors'):
print('Player 1 wins.')
elif (player1.lower() == 'paper' and
player2.lower() == 'paper'):
print('Tie.')
elif (player1.lower() == 'paper' and
player2.lower() == 'scissors'):
print('Player 2 wins.')
elif (player1.lower() == 'paper' and
player2.lower() == 'rock'):
print('Player 1 wins.')
elif (player1.lower() == 'scissors' and
player2.lower() == 'scissors'):
print('Tie.')
elif (player1.lower() == 'scissors' and
player2.lower() == 'rock'):
print('Player 2 wins.')
elif (player1.lower() == 'scissors' and
player2.lower() == 'paper'):
print('Player 1 wins.')
else:
print('This is not a valid object selection.')
How about a function to ask each player their choice? Only if the player enters a valid selection will they be allowed to proceed through the code to your logic statements.
def get_choice(Player_number):
print('Player', Player_number, 'please enter your choice: ', end='')
while True:
choice = input().lower() #lower converts input to all lowercase
if choice in ('rock', 'paper', 'scissors'): # check if valid choice
return choice # if valid return choice
else:
print('Incorrect choice, try again: ', end='') # else print this and start loop agan
player1 = get_choice('1')
player2 = get_choice('2')
For the logic part, note that if player1 choice == player 2 choice, this will substitute 3 elif blocks in your code, ie.
if player1 == player2:
print('tie')
Now replaces pl==rock and p2 == rock, p1 == scissors and p2 == scissors, ect.
edit:
1) The problem if you move the print statement in 2 to inside the input in 4 is you can no longer specify the ,end='' parameter, as it does not work with input. As you said it will generate SyntaxError. The code looks much cleaner when run this way in terminal as it all lines up, but do test it for yourself.
2) end='' prints an empty string at the end of the print statement. you are confusing this with end='\n' which prints a new line after print. As my way keeps the cursor on the same line after the print, it lines up with the input to make it look nice, see above question. Note the print statement in python by default passes , end='\n'. This is why
print('hello') #same as print('hello', end='\n')
print('world)
hello
world
print('hello', end='')
print('world', end='')
helloworld
3) The while True loop will alway evaluate to true. So the body of the while loop will constantly cycle - However, it can return out of the entire function with the 'return choice' function. The only way to leave this function if to get down the logical steps required to reach the return statement. In this case unless the choice is in that tuple('rock', 'paper', 'scisors') it will just print invalid entry try again, finishing the block. However, As while is still true the loop will begin again and ask the user to input again. This will repeat until a valid choice is selected.
4) You could concatenate it onto the player_number eg..
print('Player', Player_number + ',' , 'please enter your choice: ', end='')

Resources