Reputation: 13
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()
Upvotes: 1
Views: 1583
Reputation: 1325
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!
Upvotes: 1
Reputation: 713
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.
Upvotes: 0
Reputation: 212208
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 :)
Upvotes: 2