green_bean
green_bean

Reputation: 39

Unexpected result for Rock, Paper, Scissors assignment

I am learning functions in my programming class by making a game of paper, rock, scissors.

My program is running according to expectations except that when there is a tied game, it repeats the result twice.

I have a function to get the user's choice, I have one to generate the computer's choice, I have one that determines the winner and displays it (using result + win/lose functions to display the winner), and all three are in a function called Play_the_Game.

In case of a tie, the function prints "It's a tie!" and calls Play_the_Game again.

This is the output I get:

Please choose - Rock, Paper, or Scissors? Rock
The computer chooses rock.
The game is tied, choose again.

Please choose - Rock, Paper, or Scissors? Rock
The computer chooses paper.
Paper covers rock, you lose.
Paper covers rock, you lose.

def user_choice():
    choice = input("Please choose - Rock, Paper, or Scissors? ")
    global choice_int
    choice_int = int()
    if choice == "Rock" or choice == "rock":
        choice_int = 1
    elif choice == "Paper" or choice == "paper":
        choice_int = 2
    elif choice == "Scissors" or choice == "scissors":
        choice_int = 3
    else:
        print("That is not a valid choice.")
        user_choice()


def comp_choice():
    global choice
    choice = random.randint(1,3)
    if choice == 1:
        print("The computer chooses rock.")
    if choice == 2:
        print("The computer chooses paper.")
    if choice == 3:
        print("The computer chooses scissors.")
    return choice

### does comparisons to determine the winner
def determine_winner():
    if choice_int == 1:
        if choice == 1:
            Tied()
        if choice == 2:
            print(PaperVRock(), Loser())
        if choice == 3:
            print(RockVScissors(), Winner())
    if choice_int == 2:
        if choice == 1:
            print(PaperVRock(), Winner())
        if choice == 2:
            Tied()
        if choice == 3: 
            print(ScissorsVPaper(), Loser())
    if choice_int == 3:
        if choice == 1:
            print(RockVScissors(), Loser())
        if choice == 2:
            print(ScissorsVPaper(), Winner())
        if choice == 3:
            Tied()



def PaperVRock():
    return "Paper covers rock, "

def ScissorsVPaper():
    return "Scissors cuts paper, "

def RockVScissors():
    return "Rock smashes scissors, "

def Winner():
    return "you win!"
def Loser():
    return "you lose."
def Tied():
    print("The game is tied, choose again.")
    print()
    Play_the_Game()

    

### Take everything together
def Play_the_Game():
    user_choice()
    comp_choice()
    determine_winner()

Play_the_Game()

Upvotes: 0

Views: 417

Answers (1)

Blckknght
Blckknght

Reputation: 104712

The issue you have is that you're repeating the game, when you get a tie, using recursion, and that your if clauses in determin_winner are independent of each other. Together those two features let you get multiple results outputted at the end if the first game tied on rock or paper and the non-tied game was with a different player pick of either paper or scissors.

To understand what's happening, lets first consider a different function:

def foo():
    if a == 1:
        do_stuff()
    if a == 2:
        do_some_other_stuff()

In this function, you have two if statements that test the value of some global variable a. Now, since a can't be equal to both 1 and 2 at the same time, you might expect that only one of the do_stuff or do_other_stuff functions would be run. But what if do_stuff changes the global variable's value? In that case, if a is initially 1, but gets changed to 2, both of the functions could get run in turn.

This is a simplified version of what is happening in your code. When a tie is detected in one of the first two top-level if blocks in determine_winner (which is when the user picked "rock" or "scissors"), you call the Tied function which causes the whole game to be replayed. As part of that replaying, the global variables representing the picks the player and computer have made will be changed, and so when the tie-breaker game eventually ends, the original determine_result function will continue running and will make more tests to see who won. Like in the example I wrote above, you'd normally not expect it to find another result, since we already found a tie in one of the earlier branches. But since the if statements are independent and rely on global variables, another one can be true too.

There are several ways you can fix this issue. The simplest might be to use elif instead of if for all the test other than the first in each compound test. This makes the tests depend on each other, since only one branch can ever be run, even if more than one of the conditions are true when the time would come to test them.

def determine_winner():
    if choice_int == 1:
        if choice == 1:
            Tied()
        elif choice == 2:
            print(PaperVRock(), Loser())
        elif choice == 3:
            print(RockVScissors(), Winner())
    elif choice_int == 2:
        if choice == 1:
            print(PaperVRock(), Winner())
        elif choice == 2:
            Tied()
        elif choice == 3: 
            print(ScissorsVPaper(), Loser())
    elif choice_int == 3:
        if choice == 1:
            print(RockVScissors(), Loser())
        elif choice == 2:
            print(ScissorsVPaper(), Winner())
        elif choice == 3:
            Tied()

Another option would be to change the design of your code to avoid using recursion for flow control. When you may want to run something several times, use a loop! Here's a bare sketch of what that might look like for Rock Paper Scisors:

def play_the_game():
   pchoice = cchoice = None
   while pchoice == cchoice:
       pchoice = user_choice()
       cchoice = comp_choice()
       determine_winner(pchoice, cchoice)

With that framework for the game, the determine_winner function can just report the tie to the player, but doesn't need to re-run the game, the loop will handle that. You might want to use a similar loop in user_choice, for repeatedly asking the user for a choice until you get an answer that is valid.

Another design change that would improve your code and help you avoid issues like the one you're having is to avoid global variables. Your issue was caused by the global variables from one game (the first, that tied) being overwritten by the same global variables being used in the second game (the tiebreaker). If you used arguments, you could avoid that. My sketch of a play_the_game function above shows how that might work, with the X_choice functions returning the chosen values, and the determine_answer function accepting the two choices as arguments. You could make just that change (while keeping the recursive structure) if you wanted to, and it would fix your immediate problem too, but getting rid of both the recursion and the global variables is best!

Upvotes: 0

Related Questions