2

The main problem I'm having is trying to get the total wins loses and ties when user is playing with computer(random function). But I keep getting this error whenever I'm inputting either 1, 2, or 3 for rock paper scissors for player_choice.

Welcome to a game of paper, rock, scissors!
Please input the correct number according 
to the object.
Select rock(1), paper(2), or scissors(3): 2
Computer chose ROCK .
You chose PAPER .
Traceback (most recent call last):
  File "C:\Program Files (x86)\Wing IDE 101 4.1\src\debug\tserver\_sandbox.py", line    
114, in <module>
  File "C:\Program Files (x86)\Wing IDE 101 4.1\src\debug\tserver\_sandbox.py", line   
43, in main
  File "C:\Program Files (x86)\Wing IDE 101 4.1\src\debug\tserver\_sandbox.py", line 
106, in determine_winner
builtins.UnboundLocalError: local variable 'win' referenced before assignment

Clearly its a local variable issue. Are there any other solutions? Here is my code:

#import the library function "random" so that you can use it for computer
#choice
import random

#define main
def main():
    #assign win, lose, and tie variables to zero so that later it can be added
    #and displayed
    win = 0
    lose = 0
    tie = 0

    #control loop with 'y' variable
    play_again = 'y'

    #start the game
    while play_again == 'y':
        #make a welcome message and give directions
        print('Welcome to a game of paper, rock, scissors!')
        print('Please input the correct number according')
        print('to the object.')

        #write computer and players choices as value returning functions and
        #assign them to variables
        computer_choice = get_computer_choice()
        player_choice = get_player_choice()

        #print outcome
        print('Computer chose', computer_choice, '.')
        print('You chose', player_choice, '.')

        #determine who won by defining a function
        determine_winner(computer_choice, player_choice)

        #ask the user if they want to play again
        play_again = input("Play again? Enter 'y' for yes or 'n' for no. ")

    #print results
    print('Your total wins are', win, '.')
    print('Your total losses are', lose, '.')
    print('Your total ties are', tie, '.')

#define computer choice
def get_computer_choice():
    #use imported random function from library
    choice = random.randint(1,3)

    #assign what the computer chose to rock, paper, or scissors
    if choice == 1:
        choice = 'ROCK'
    elif choice == 2:
        choice = 'PAPER'
    else:
        choice = 'SCISSORS'

    #return value
    return choice

#define player choice
def get_player_choice():
    #assign input to variable by prompting user
    choice = int(input("Select rock(1), paper(2), or scissors(3): "))

    #use while function if user inputs the invalid selection
    while choice != 1 and choice != 2 and choice != 3:
        print('The valid numbers are rock(type in 1), paper(type in 2),')
        print('or scissors(type in 3).')
        choice = int(input('Enter a valid number please: '))

    #assign what the player chose to rock, paper, or scissors
    if choice == 1:
        choice = 'ROCK'
    elif choice == 2:
        choice = 'PAPER'
    else:
        choice = 'SCISSORS'

    #return value
    return choice

#determine the winner by assigning the assigned variables
def determine_winner(computer_choice, player_choice):
    #if its a tie, add 1 to tie variable and display message
    if computer_choice == player_choice:
        tie += 1
        print("It's a tie!")

    #if its a win, add to win variable and display message
    elif computer_choice == 'SCISSORS' and player_choice == 'ROCK':
        win += 1
        print('ROCK crushes SCISSORS! You win!')
    elif computer_choice == 'PAPER' and player_choice == 'SCISSORS':
        win += 1
        print('SCISSORS cut PAPER! You win!')
    elif computer_choice == 'ROCK' and player_choice == 'PAPER':
        win += 1
        print('PAPER covers ROCK! You win!')

    #if it does not match any of the win criteria then add 1 to lose and
    #display lose message
    else:
        lose += 1
        print('You lose!')
main()

3 Answers3

1

The function determine_winner() can't see the variables win, tie and lose that you have defined in main(). Therefore you can't do win +=1.

You usually don't use a main() routine in Python anyway (I've seen a few questions here recently that use them - whoever is teaching this?), but even if you move its contents into the top level of the program, it wouldn't work because win += 1 would still fail for the same reason.

You could define local variables win, tie and lose in determine_winner() and have it return their values, then add those to the respective variables in the top level code. In fact, you don't even need those variables in that function at all.

For example:

def determine_winner(computer_choice, player_choice):
    #if its a tie, add 1 to tie variable and display message
    if computer_choice == player_choice:
        print("It's a tie!")
        return 0

    #if its a win, add to win variable and display message
    elif computer_choice == 'SCISSORS' and player_choice == 'ROCK':
        print('ROCK crushes SCISSORS! You win!')
        return 1
    elif computer_choice == 'PAPER' and player_choice == 'SCISSORS':
        print('SCISSORS cut PAPER! You win!')
        return 1
    elif computer_choice == 'ROCK' and player_choice == 'PAPER':
        print('PAPER covers ROCK! You win!')
        return 1

    #if it does not match any of the win criteria then add 1 to lose and
    #display lose message
    else:
        print('You lose!')
        return -1

and in the top level:

result = determine_winner(computer_choice, player_choice)
if result == -1:
    lose += 1
elif result == 0:
    tie += 1
else:
    win += 1
Tim Pietzcker
  • 328,213
  • 58
  • 503
  • 561
  • Thank you so much! I've been staring at this problem for hours! – Oiugghog Jkhkh Mar 02 '12 at 07:50
  • 2
    Even if your not using a `main()` function, it's still a good idea to place your main code under an `if __name__ == "__main__":` statement. – Joel Cornett Mar 02 '12 at 20:44
  • The `if __name__ == "__main__": main()` line at the bottom is usually done by everyone I've seen, actually. I think one purpose is so that the file can be imported without all of the code in `main` running. So you could use a hypothetical `randRGB()` function or something in the file from an external script. – SimonT Apr 15 '13 at 03:33
  • @Tangmeister: The code in `main()` wouldn't run during an `import` anyway. Only the module-level code would, so it makes sense putting *that* under an `if...` statement (as Joel Cornett mentioned above). – Tim Pietzcker Apr 15 '13 at 07:45
  • I might've been misunderstood, but I also said that the code in `main` wouldn't run. So it's a matter of personal taste, then. – SimonT Apr 15 '13 at 20:09
1

You can make your variables win, lose and tie global. Here, they aren't. How to make them global

Edit: I agree that making global is not a good solution.

Community
  • 1
  • 1
bmkorkut
  • 616
  • 5
  • 17
  • I don't think that's a good solution. First, even if you make them global, it still doesn't work unless you also use `global win` at the start of `determine_winner()`, and second, global variables are almost never a good idea. – Tim Pietzcker Mar 02 '12 at 07:33
  • I agree that returning the result is a better solution than using globals. I just thought Oiugghog Jkhkh was asking how to use global variables. – bmkorkut Mar 02 '12 at 07:37
0

Python uses lexical scoping. That means that if a variable is defined inside a function, code outside that function cannot see it (unless it's marked global).

A quick-and-dirty fix would be to mark win, and any other variables which need to be seen from outside main, as global. A better solution would be to restructure your code.

Taymon
  • 24,950
  • 9
  • 62
  • 84
  • You'd first have to move them outside of `main()` or they won't be global anyway. – Tim Pietzcker Mar 02 '12 at 07:34
  • With a `global` statement, they will be. Not that this is the most elegant solution. – Taymon Mar 02 '12 at 07:37
  • No. Currently they are not defined at the top level of the module. The `global` statement does not make local variables global. It tells the function to *look for* the referenced variable in the global scope instead of creating a local one. That only works if there already *is* such a global variable. – Tim Pietzcker Mar 02 '12 at 07:39
  • If you say `global win` at the top of a function and then follow it with an assignment to `win`, the assignment will be to the global variable `win`, even if there are no assignments to that variable in top-level module code. I just tested this with the OP's code and it works. – Taymon Mar 02 '12 at 07:43
  • OK, but only if you to that `global` thing in all the functions *and* make sure that they are assigned to 0 first (which in this case would indeed work). At which point it would make more sense to move the `main()` function completely into the top level. – Tim Pietzcker Mar 02 '12 at 07:47