I am trying to complete a rock, paper, scissors assignment for class.
I'm getting a "UnboundLocalError: local variable 'tied' referenced before assignment" error.
Can someone please tell me why I'm getting this error?
import random
user_score = 0
computer_score = 0
tied = 0
def main():
print ("Let's play the game of Rock, Paper, Scissors. ")
while True:
print ("Your current record is", user_score, "wins,", computer_score, "losses and", tied, "ties")
computer_choice = random.randint(1,3)
if computer_choice == 1:
computer_rock()
elif computer_choice == 2:
computer_paper()
else:
computer_scissors()
def computer_rock():
user_choice = input("1 for Rock, 2 for Paper, 3 for Scissors: ")
if user_choice == "1":
print ("Draw! You both chose Rock.")
tied += 1
try_again()
elif user_choice == "2":
print ("You Win! The computer chose Rock, while you picked Paper.")
user_score += 1
try_again()
elif user_choice == "3":
print ("You Lose! You chose scissors, while the computer picked Rock.")
computer_score += 1
try_again()
else:
print ("ERROR: Invalid entry, please re-enter your choice. ")
computer_rock()
def computer_paper():
user_choice = input("1 for Rock, 2 for Paper, 3 for Scissors: ")
if user_choice == "1":
print ("You Lose! You chose rock, while the computer picked Paper.")
computer_score += 1
try_again()
elif user_choice == "2":
print ("Draw! You both picked Paper.")
tied += 1
try_again()
elif user_choice == "3":
print ("You Win! The computer chose Paper, while you picked Scissors.")
user_score += 1
try_again()
else:
print ("ERROR: Invalid entry, please re-enter your choice. ")
computer_paper()
def computer_scissors():
user_choice = input("1 for Rock, 2 for Paper, 3 for Scissors: ")
if user_choice == "1":
print ("You Win! You chose rock, while the computer picked Scissors.")
user_score += 1
try_again()
elif user_choice == "2":
print ("You Lose! The computer chose Scissors, while you picked Paper.")
computer_score += 1
try_again()
elif user_choice == "3":
print ("Draw! You both picked Scissors.")
tied += 1
try_again()
else:
print ("ERROR: Invalid entry, please re-enter your choice. ")
computer_scissors()
def try_again():
choice = input("Play again? Yes or no. ")
if choice == "y" or choice == "Y" or choice == "yes" or choice == "Yes":
main()
elif choice == "n" or choice == "N" or choice == "no" or choice == "No":
print ("Thanks for playing. ")
else:
print ("Try again")
try_again()
main()
Adding the following code as the first line in each of the three computer_() functions should fix your problem.
global tied, user_score, computer_score
There are better ways to accomplish what you're doing, but that should get you over the hump here :)
While Triptych's answer is perfectly acceptable (and also widely used), for a relatively novice-level programmer it is usually better practice to pass arguments into functions instead of utilizing the global keyword.
More info can be found at the Python Documentation: https://docs.python.org/3/tutorial/controlflow.html#defining-functions
In essence, the point is for the programmer to pass what is called an argument (or arguments) into the function, and the function containing those parameters can process this data and return values back to the location where it was called, similar to how the print() function works. You pass a string (ex. "Hi") into the print() function (ex. print("Hi")), and code within this built-in function displays the characters "Hi" onto the screen.
In this case, your code would look something like this:
# In your main function:
def main():
print ("Let's play the game of Rock, Paper, Scissors. ")
while True:
print ("Your current record is", user_score, "wins,", computer_score, "losses and", tied, "ties")
computer_choice = random.randint(1,3)
if computer_choice == 1:
result = computer_rock(user_score, computer_score, tied) ## Notice the difference here
elif computer_choice == 2:
result = computer_paper(user_score, computer_score, tied) ## Those variables you put in the function call are arguments
else:
result = computer_scissors(user_score, computer_score, tied)
# ...
# In the computer_rock() function:
# Even though I only modified this function, you should probably modify all three to suit your needs.
def computer_rock(user_score, computer_score, tied): ## <-- See the parameters?
user_choice = input("1 for Rock, 2 for Paper, 3 for Scissors: ")
if user_choice == "1":
print ("Draw! You both chose Rock.")
tied += 1
try_again()
elif user_choice == "2":
print ("You Win! The computer chose Rock, while you picked Paper.")
user_score += 1
try_again()
elif user_choice == "3":
print ("You Lose! You chose scissors, while the computer picked Rock.")
computer_score += 1
try_again()
return [user_score, computer_score, tied] # Returning a list so it is easier to sort variables
Another thing to note, even though you are calling try_again() to restart the game, it is not a very good idea to call main() inside of a function that will be called by main(). It is better to use a while loop in the main function to regulate and control the flow of the program.
Hopefully this helped!
It caused from a feature in Python.
The following example emits the same Exception. Note that You can't assign to Global-Variable in Local-Scope.
>>> variable = 1
>>> def function():
... variable += 1
...
>>> function()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in function
UnboundLocalError: local variable 'variable' referenced before assignment
So if you write as the following, the value of Globale-Variable is not changed. This variable in function() is not Global-Variable but Local-Variable. Right?
>>> variable = 1
>>> def function():
... variable = 2
...
>>> function()
>>> variable
1
By the way, this feature is useful for us, because we want to use functions as small as possible, if speaking loudly, simply because we humans don't understand long functions.
Perhaps you want to use the Global-Variable here now, but when you write many and many codes, and can use Global-Variable, you will be panic such as "Where did this variable change?" because there are many places you changed.
If we have codes which we can't know where we change, these codes will be mysterious codes. It's so disgusting.
#Triptych 's answer is also right. If you adopt his answer, this codes will work. However I recommend that you don't use global.
p.s. You can do it in JavaScript.
Related
I am looking for some input on a rock, paper, scissors program that I am making where the statements in the main() and determineWinner that use playerChoice always terminate in the else: case. Each trial will output the player chooses scissors and that the game is tied. I am not sure where I went wrong here as I've printed the input to confirm it is correct before sending to it to the other functions. I cannot figure what pare of the above to function is causing the problem, if anyone could point me in the right direction here I would be grateful.
Here is the code I have so far:
import random
# define main function
def main():
# initialize playAgain to start game, set stats to 0
playAgain = 'y'
numberTied = 0
numberPlayerWon = 0
numberComputerWon = 0
print("Let's play a game of rock, paper, scissors.")
# loop back to play again if user confirms
while playAgain == 'y' or playAgain == 'Y':
computerChoice = processComputerChoice()
playerChoice = processPlayerChoice()
# display computer choice
if computerChoice == 1:
print('The computer chooses rock.')
elif computerChoice == 2:
print('The computer chooses paper.')
else:
print('The computer chooses scissors.')
# display player choice
if playerChoice == 1:
print('You choose rock.')
elif playerChoice == 2:
print('You choose paper.')
else:
print ('You choose scissors.')
# assign who won to result and add total wins/ties to accumulator
result = determineWinner(playerChoice, computerChoice)
if result == 'computer':
numberComputerWon += 1
elif result == 'player':
numberPlayerWon += 1
else:
numberTied += 1
# ask player if they would like to play again
print('')
print
playAgain = input('Do you want to play again? (Enter y or Y to start another game)')
print('')
else:
# print accumulated wins and ties for computer and player
print('There were', numberTied, 'tie games played.')
print('The computer won', numberComputerWon, 'game(s).')
print('The player won', numberPlayerWon, 'game(s).')
print('')
# define computer choice function
def processComputerChoice():
# randomly select an option for the computer to play
randomNumber = random.randint(1,3)
print(randomNumber)
return randomNumber
# define player choice function
def processPlayerChoice():
choice = int(input(('What is your choice? Enter 1 for rock, 2 for paper, or 3 for scissors. ')))
print (choice)
# throw error if player makes invalid choice
while choice != 1 and choice != 2 and choice != 3:
print('ERROR: please input a valid choice of 1, 2, or 3')
choice = int(input('Please enter a correct choice: '))
return choice
# definition for the function to determine the winner
def determineWinner(playerChoice, computerChoice):
# determine player choice and compare to computer choice to determine the winner
if computerChoice == 1:
if playerChoice == 2:
print('Paper covers rock. You are victorious!')
winner = 'player'
elif playerChoice == 3:
print('Rock bashes scissors. The computer is victorious!')
winner = 'computer'
else:
print('The game is tied. Try again 1')
winner = 'tied'
if computerChoice == 2:
if playerChoice == 1:
print('Paper covers rock. The computer is victorious!')
winner = 'computer'
elif playerChoice == 3:
print('Scissors slice paper. You are victorious!')
winner = 'player'
else:
print('The game is tied. Try again 2')
winner = 'tied'
if computerChoice == 3:
if playerChoice == 1:
print('Rock bashes scissors. You are victorious!')
winner = 'player'
elif playerChoice == 2:
print('Scissors slice paper. The computer is victorious!')
winner = 'computer'
else:
print('The game is tied. Try again 3')
winner = 'tied'
return winner
main()
input("Press Enter to continue")
The return statement of your function processPlayerChoice has incorrect indentation. It should be out of while loop (unindent it one level)
At the moment, if player enters correct choice your function will return None.
If user enters incorrect choice, it will enter the while loop and will return whatever the second input from user is.
def processPlayerChoice():
choice = int(input(('What is your choice? Enter 1 for rock, 2 for paper, or 3 for scissors. ')))
print (choice)
# throw error if player makes invalid choice
while choice != 1 and choice != 2 and choice != 3:
print('ERROR: please input a valid choice of 1, 2, or 3')
choice = int(input('Please enter a correct choice: '))
return choice
Make sure to align your return statements with the function body. Currently in both processPlayerChoice and determineWinner they are aligned with the conditional loops, and thus will not be reached every time.
I am new to coding. I want to try writing a simple rock paper scissors game. But I can't figure out how to end the game.
In the end of this program if the user input is wrong I want to go to the end variable again. I tried with the commented lines but its not working.
player1 = input("What is player 1's name ? ")
player2 = input("What is player 2's name ? ")
player1 = player1.title()
player2 = player2.title()
while True:
print(player1 + " What do you choose ? rock / paper / scissors : ")
a = input()
print(player2 + " What do you choose ? rock / paper / scissors : ")
b = input()
if a == "rock" and b == "scissors" :
print(player1, "won !!!")
elif a == "scissors" and b == "rock":
print(player2, "won !!!")
elif a == "paper" and b == "rock":
print(player1, "won !!!")
elif a == "rock" and b == "paper":
print(player2, "won !!!")
elif a == "scissors" and b == "paper":
print(player1, "won !!!")
elif a == "paper" and b == "scissors":
print(player2, "won !!!")
elif a == b:
print("Its a tie :-(")
elif a or b != "rock" or "paper" or "scissors":
print("Wrong input, Try again")
end = input("Do you want to play again ? yes/no ") == "yes"
if input == "yes":
continue
else:
print('''
GAME OVER''')
break
# elif input != "yes" or "no":
# print("Wrong input, Try again. yes or no ?")
I expect it to end game if the input is "no" and restart the game if input is "yes" if the input is not correct I want the prompt to appear again.
Your code has a few issues which need some addressing, and a few places where it can be streamlined. I have made a few changes to your program as well as added a few comments explaining the changes.
player1 = input("What is player 1's name ? ").title() #This uses chaining to streamline code
player2 = input("What is player 2's name ? ").title() #Same as above
while True:
a = input(player1 + " What do you choose ? rock / paper / scissors : ") #no need to use a separate print statement
b = input(player2 + " What do you choose ? rock / paper / scissors : ")
valid_entries = ["rock", "paper", "scissors"] #To check for valid inputs
if (a not in valid_entries) or (b not in valid_entries):
print("Wrong input, try again")
continue
a_number = valid_entries.index(a) #Converting it to numbers for easier comparison
b_number = valid_entries.index(b)
if(a_number == b_number):
print("Its a tie :-(")
else:
a_wins = ((a_number > b_number or (b_number == 2 and a_number == 0)) and not (a_number == 2 and b_number == 0)) #uses some number comparisons to see who wins instead of multiple if/elif checks
if(a_wins):
print(player1, "won !!!")
else:
print(player2, "won !!!")
end = input("Do you want to play again ? yes/no ")
while (end !="yes") and (end != "no"):
print("invalid input, try again")
end = input("Do you want to play again ? yes/no ")
if end == "yes":
continue
else:
print("GAME OVER")
break
These changes also make the check by using another while loop to see if the input to restart the game was valid or not
*Note that I have not tested these changes and some edits may need to be be made
Just check the value of end
if end is True:
continue
else:
break
Since, you have set the value of end as a boolean by comparing the input() to "yes", it will say whether the user wants to end the game?
Also, you are not initializing the input variable, and the last elif condition will always be true as mentioned in the comment.
Well you can simplify your code using a list and then simplify your if tests. You can check the order of the options and based on it make a decision. You can also make the tests standard to minimize the number of if statements. This my suggestion to improve your code. I hope it helps:
# get playe names
player1 = input("What is player 1's name ? ")
player2 = input("What is player 2's name ? ")
player1 = player1.title()
player2 = player2.title()
# init vars
options = ["rock", "paper", "scissors"]
players = [player1, player2]
# start game
while True:
a = input(player1 + " What do you choose ? rock / paper / scissors : ")
b = input(player2 + " What do you choose ? rock / paper / scissors : ")
# check if inputs are correct
while (a not in options or b not in options):
print("Wrong input, Try again")
a = input(player1 + " What do you choose ? rock / paper / scissors : ")
b = input(player2 + " What do you choose ? rock / paper / scissors : ")
# check who won
if abs(options.index(a) - options.index(b)) == 1:
print(players[1*int(options.index(a) > options.index(b))], "won !!!")
elif abs(options.index(b) - options.index(a)) > 1:
print(players[1*int(options.index(a) > options.index(b))], "won !!!")
elif a == b:
print("Its a tie :-(")
# continue or drop game
end = input("Do you want to play again ? yes/no ")
if end == "yes":
continue
else:
print('''
GAME OVER''')
break
I'm new to programming. I have written code for the rock paper scissors game but there is one bug that I can't seem to fix. When the game closes, the user is asked if he wants to play again. If the user answers yes the first time, then plays again then answers no the second time, the computer for some reason asks the user again if he wanted to play again. The user must enter no in this case. This is because although the user answers no, the answer gets reset to yes and goes over again. How can this be fixed?
# This code shall simulate a game of rock-paper-scissors.
from random import randint
from time import sleep
print "Welcome to the game of Rock, Paper, Scissors."
sleep(1)
def theGame():
playerNumber = 4
while playerNumber == 4:
computerPick = randint(0,2)
sleep(1)
playerChoice = raw_input("Pick Rock, Paper, or Scissors. Choose wisely.: ").lower()
sleep(1)
if playerChoice == "rock":
playerNumber = 0
elif playerChoice == "paper":
playerNumber = 1
elif playerChoice == "scissors":
playerNumber = 2
else:
playerNumber = 4
sleep(1)
print "You cookoo for coco puffs."
print "You picked " + playerChoice + "!"
sleep(1)
print "Computer is thinking..."
sleep(1)
if computerPick == 0:
print "The Computer chooses rock!"
elif computerPick == 1:
print "The Computer chooses paper!"
else:
print "The Computer chooses scissors!"
sleep(1)
if playerNumber == computerPick:
print "it's a tie!"
else:
if playerNumber < computerPick:
if playerNumber == 0 and computerPick == 2:
print "You win!"
else:
print "You lose!"
elif playerNumber > computerPick:
if playerNumber == 2 and computerPick == 0:
print "You lose!"
else:
print "You win!"
replay()
def replay():
sleep(1)
playAgain = "rerun"
while playAgain != "no":
playAgain = raw_input("Would you like to play again?: ").lower()
if playAgain == "yes":
sleep(1)
print "Alright then brotha."
sleep(1)
theGame()
elif playAgain == "no":
sleep(1)
print "Have a good day."
sleep(1)
print "Computer shutting down..."
sleep(1)
else:
sleep(1)
print "What you said was just not in the books man."
sleep(1)
theGame()
This is because of the way the call stack is created.
The First time you play and enter yes to play again, you are creating another function call to theGame(). Once that function call is done, your program will continue with the while loop and ask if they want to play again regardless if they entered no because that input was for the second call to theGame().
To fix it, add a break or set playAgain to no right after you call theGame() when they enter yes
while playAgain != "no":
playAgain = raw_input("Would you like to play again?: ").lower()
if playAgain == "yes":
sleep(1)
print "Alright then brotha."
sleep(1)
theGame()
break ## or playAgain = "no"
You should break out of the loop after calling theGame. Imagine you decided to play again 15 times. Then there are 15 replay loops on the stack, waiting to ask you if you want to play again. Since playAgain is "yes" in each of these loops, each is going to ask you again, since playAgain is not "no"
I'm really new to programming, and just started making a rock, paper, scissors game. But I'm hung up on assigning randint to an object, I made a bold comment where I'm having the problem. I'm assuming when I keep calling computer = randint(0,2) it will change computer each time, so how can I fix that? Sorry if this is a silly question.
import random
from random import randint
import time
import sys
def choice():
print("Rock, paper, scissors, or quit?")
answer = input('> ').lower()
if answer in('rock'):
print("\nYou have chosen {}".format(answer))
elif answer in('paper'):
print("\nYou have chosen {}".format(answer))
elif answer in('scissors'):
print("\nYou have chosen {}".format(answer))
elif answer in('quit'):
sys.exit(0)
else:
print("Could not recognize your answer. Please try again.")
choice()
print("Rock")
time.sleep(0.5)
print("Paper")
time.sleep(0.5)
print("Scissors")
time.sleep(0.5)
options = ('Rock', 'Paper', 'Scissors')*3
print("\nI have chosen: " + random.choice(options))
print('\n')
new_answer = answer
#THIS IS WHERE IM HAVING TROUBLE ASSIGNING OBJECT TO THE RANDINT
computer = randint(0,2)
if new_answer == 'rock':
if computer == 0: #paper
print("1")
elif computer == 1: #scissors
print("2")
elif computer == 2: #
print("3")
if new_answer == 'paper':
if computer == 0: #
print("Paper covers rock. You win.")
elif computer == 1:
print("It's a draw. We suck.")
elif computer == 2:
print("Scissors cuts paper. I win")
if new_answer == 'scissors':
if computer == 0:
print("Rock crushes scissors. I win.")
if computer == 1:
print("Scissors cut paper. You win.")
if computer == 2:
print("It's a draw. We suck.")
print("\nI have chosen: " + random.choice(options))
#...
computer = randint(0,2)
You are making the computer choose twice. You should choose (randomly) once, assign the result to a variable, and then print it.
As soon as you assign the value of the function call to a variable (as in computer = randint(0,2)), the value of the variable (computer) does not change, unless you assign to it again.
A couple more remarks:
As wnnmaw mentioned, you don't need to import random
You don't need to import exit from sys, it's natively available
You can import time.sleep directly
You should keep the association between numbers and choices (rock,paper,scissor) only once in your code, to prevent errors, and use apropriate list functions to get them (suc
h as list.index
You were using in innapropriately in place of the == operator
Once you keep the associations in one place, you don't need to test them individually: use in
('Rock', 'Paper', 'Scissors')*3: This creates a tuple with 9 elements, which is probably not what you wanted
the new_answer variable seems redundant
The function is becoming very long, so you can refactor parts of it to new functions, so it becomes more readable
Be carefull calling a function inside the function itself. Generally, you should prefer to use a cycle (lookup "recursion" and "stack overflow")
You can use the order of the choices (rock, paper, scissors) to check the outcome of the match elegantly, as each choice wins when up agains the choice immediatelly before it
. You can do this using the modulus operator (%)
Here's a rewritten version taking these tips into consideration:
from random import choice
from time import sleep
CHOICES=('rock','paper','scissors')
def print_animation():
print("Rock")
sleep(0.5)
print("Paper")
sleep(0.5)
print("Scissors")
sleep(0.5)
def rock_paper_scissors():
while(True):
print("Rock, paper, scissors, or quit?")
answer = input('> ').lower()
if answer in CHOICES:
print("\nYou have chosen {}\n".format(answer))
break
elif answer=='quit':
sys.exit(0)
else:
print("Could not recognize your answer. Please try again.")
print_animation()
computer= choice(CHOICES)
print("\nI have chosen: " + computer + "\n")
player_answer_index= CHOICES.index(answer)
computer_answer_index= CHOICES.index(computer)
if player_answer_index==computer_answer_index:
print("draw")
elif (player_answer_index+1)%3==computer_answer_index:
print("computer wins")
else:
print("player wins")
rock_paper_scissors()
This question already has answers here:
Python NameError from contents of a variable
(2 answers)
Closed 8 years ago.
I'm trying to make a simple rock paper scissors game, and I get an error with in the line, guess = input. It says I need to define the function or variable before I use it in this way and I am unsure of how I can do that. This is using Python/JES programming
#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():
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.')
return user_guess()
def is_valid_guess(guess):
if guess == 'rock' or guess == 'paper' or guess == '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()
Using raw_input instead of input seems to solve the problem.
guess = raw_input ("Choose 'rock', 'paper', or 'scissors' by typing that word. ")
and also in
answer = raw_input("Would you like to play again? Enter 'y' for yes or 'n' for no: ")
I'm using Python 2.7.x