1

I am trying to write a program for an assignment where you input a specific command and you can play Rock-Paper-Scissors-Lizard-Spock against the computer. It was done and working until I realized that the assignment instructions wanted me to make it so that you keep playing the game until one person gets five wins.

So I thought, no big deals, let's throw in a while loop and some variables to track the wins. But when I run the program, it only runs once still. I don't know what I am doing wrong - as this should work. This is my first time working with Python (version 3.3) and this IDE, so I really need some help. Usually I'd just debug but I can't figure out how to work the one in this IDE.

Here is my code. The trouble while-loop is at the way bottom. I am nearly positive everything inside the class works. I would like to note that I already tried while(computerWins < 5 and userWins < 5), so I don't think the condition is the problem.

import random

computerWins = 0
userWins = 0
print ('SELECTION KEY:\nRock = r\nPaper = p\nScissors = sc\nLizard = l\nSpock = sp')

class rockPaperScissorsLizardSpock:
#Two methods for converting from strings to numbers

    #convert name to number using if/elif/else
    #also converts abbreviated versions of the name
    def convertName(name):
        if(name == 'rock' or name == 'r'):
            return 0
        elif(name == 'Spock' or name == 'sp'):
            return 1
        elif(name == 'paper' or name == 'p'):
            return 2
        elif(name == 'lizard' or name == 'l'):
            return 3
        elif(name == 'scissors' or name == 'sc'):
            return 4
        else:
            print ('Error: Invalid name')

    #convert number to a name using if/elif/else
    def convertNum(number):
        if(number == 0):
            return 'rock'
        elif(number == 1):
            return 'Spock'
        elif(number == 2):
            return 'paper'
        elif(number == 3):
            return 'lizard'
        elif(number == 4):
            return 'scissors'
        else:
            print ('Error: Invalid number')

    #User selects an option, and their selection is saved in the 'choice' variable    
    #Using a while loop so that the user cannot input something other than one of the legal options
    prompt = True
    while(prompt):
        i = input('\nEnter your selection: ')
        if(i=='r' or i=='p' or i=='sc' or i=='l' or i=='sp'):
            prompt = False
        else:
            print('Invalid input.')
    prompt = True

    #Convert the user's selection first to a number and then to its full string
    userNum = convertName(i)
    userChoice = convertNum(userNum)

    #Generate random guess for the computer's choice using random.randrange()
    compNum = random.randrange(0, 4)

    #Convert the computer's choice to a string
    compChoice = convertNum(compNum)

    print ('You chose', userChoice)
    print ('The computer has chosen', compChoice)

    #Determine the difference between the players' number selections
    difference = (compNum - userNum) % 5

    #Use 'difference' to determine who the winner of the round is
    if(difference == 1 or difference == 2):
        print ('The computer wins this round.')
        computerWins = computerWins+1
    elif (difference == 4 or difference == 3):
        print ('You win this round!')
        userWins = userWins+1
    elif(difference == 0):
        print ('This round ended up being a tie.')

#Plays the game until someone has won five times
while(computerWins != 5 and userWins != 5):
    rockPaperScissorsLizardSpock()

if(computerWins == 5 and userWins != 5):
    print ('The computer wins.')
elif(computerWins != 5 and userWins == 5):
    print ('You win!')
jonrsharpe
  • 115,751
  • 26
  • 228
  • 437
  • The code is very complicated for something so simple. – jkd Mar 20 '15 at 02:47
  • 1
    what in the world is `class rockPaperScissorsLizardSpock:` supposed to do. And yeah, wayyy to complicated for something so simple – letsc Mar 20 '15 at 02:48
  • I am supposed to make the user input these letters, and using numbers to match the values seemed like the most straightforward way of doing this. If this were java or I wasn't supposed to do such particular stuff, it would be simpler. Do you have any suggestions for this while loop issue? – lovechicken Mar 20 '15 at 02:49
  • 2
    I am trying my best. I am new to python. I thought it was supposed to be a class. It worked fine before this loop. Well, like I said I did use < 5 in my while loop for both statements, but it didn't help anything. I don't think that is the problem...or is it? – lovechicken Mar 20 '15 at 02:53
  • @lovechicken Nothing immediately seems obviously wrong with it (I admit I skimmed), but two things that immediately spring to mind for debugging: (1) Have you tried printing out the values of `computerWins` and `userWins` after the loop prematurely terminates? And have you tried putting both of the loop conditions in parentheses? So, in other words, checking that it properly incremented the variables, and that it grouped the boolean expressions the way it was supposed to. – Parthian Shot Mar 20 '15 at 02:53
  • It's not that it only plays once, you're stuck in an infinite loop. I'm willing to bet the program does not terminate (ie. put you back to the command prompt). – Edward L. Mar 20 '15 at 02:55
  • @ParthianShot I tried what you said. I printed out the values, placed them after the loop not indented at all...but they never were printed. it's like the loop doesn't have a close. I printed them out in my class and it worked fine. I put the loop conditions in parentheses and no change – lovechicken Mar 20 '15 at 02:58
  • Whoops- nevermind. I've never tried writing code in the class definition, before. But... yeah, I'm guessing it's what everyone else seems to be saying (that). – Parthian Shot Mar 20 '15 at 02:58
  • Ok, well it seems the problem is an infinite loop, you are right. How can I make my class run again? I am confused because I usually code Java, so this is strange. – lovechicken Mar 20 '15 at 02:59
  • @ParthianShot is it wrong to be writing my stuff in a class definition? I don't know what I should put. The lack of a main method and calling other methods from it is weird – lovechicken Mar 20 '15 at 03:00
  • 1
    For something so simple, don't bother with the class definition. Just make a few functions that you'll call. Python is created to be flexible like this without the rigid class structure so you can prototype simple things fast (you can certainly make classes, but it's not required). Also, clearly mark the `__main__` method, it makes the code easier to read. Do something like `if __name__ == "__main__":` This is the Python equivalent of Java's `public static void main(String[] args)` – Edward L. Mar 20 '15 at 03:01
  • Thanks guys! It's fixed. The class definition was the problem just like you said. I have to remember this isn't Java. I'm taking a course that teaches lots of languages, so in the past three weeks I've been through C, C++, and Python, and still have Java stuff, so I'm a bit mixed up. – lovechicken Mar 20 '15 at 03:16
  • Make you own answer, post it, then mark it as accepted since the situation is solved. – jkd Mar 20 '15 at 03:20
  • sorry - thanks for the info! I obviously don't use this site much haha. – lovechicken Mar 20 '15 at 03:23

3 Answers3

3

The essential problem is that rockpaperscissorslizardspock is a class, where you expect it to be a function. The code inside it runs exactly once, when the whole class definition is parsed, rather than each time you call the class as you seem to expect.

You could put the relevant code into an __init__ method - this is a fairly direct analogue of a Java constructor, and hence is is run each time you call the class. But in this case, you probably don't need it to be in a class at all - calling the class creates a new instance (like doing new MyClass() in Java), which you don't use. You would also in this case (or if you made it into a function) need to make some more modifications to make sure the game state persists properly.

The easiest actual solution is to:

  1. delete the line class rockpaperscissorslizardspock: (and unindent everything below it)
  2. Take all the code that was under the class but not in a function - everything from the player makes a selection to determining the winner of the round - and paste it in place of the call to rockpaperscissorslizardspock() in the bottom loop.
lvc
  • 34,233
  • 10
  • 73
  • 98
  • Thank you!! That fixed everything! I wish I could vote you up. Thanks so much. I'll have to learn more about using classes properly. – lovechicken Mar 20 '15 at 03:14
1

The first thing is that you are using a class where you should probably be using a function.

Your code initially runs because python is loading the class.

However, the line rockPaperScissorsLizardSpock() is creating new anonymous instances of your class which calls a constructor that you haven't defined so it does nothing.

One of the interesting things about python is that it allows nested functions so if you change the class to a def you're almost there.

After that, you'll run into trouble with global variables in a local context. That problem is already explained in another StackOverflow question: Using global variables in a function other than the one that created them.

Community
  • 1
  • 1
fdsa
  • 1,379
  • 1
  • 12
  • 27
1

Here is my suggestion for the skeleton to a more simple solution. Use some ideas from here if you like.

import random

legal_shapes = ['r', 'p', 'sc', 'sp', 'l']
scoreboard = [0, 0]
print('SELECTION KEY:\nRock = r\nPaper = p\nScissors = sc\nLizard = l\n'
      'Spock = sp')

while(max(scoreboard) < 5):

    print("\nScore is {}-{}".format(*scoreboard))

    # pick shapes
    p1_shape = input('Enter your selection: ')
    if p1_shape not in legal_shapes:
        print('Not legal selection!')
        continue
    p2_shape = random.choice(legal_shapes)
    print('\np1 plays {} and p2 plays {}'.format(
        p1_shape.upper(), p2_shape.upper()))

    # determine int values and result indicator
    p1_shape_int = legal_shapes.index(p1_shape)
    p2_shape_int = legal_shapes.index(p2_shape)
    res = (p1_shape_int - p2_shape_int) % 5
    if res != 0:
        res = abs((res % 2) - 2)

    # Print winner
    if res == 0:
        print(' -> Draw!!')
    else:
        print(' -> p{} wins'.format(res))
        scoreboard[res-1] += 1

print("\nThe game is over!!")
print("p{} won with score {}-{}".format(res, *scoreboard))

It outputs something like

(env)➜ tmp python3 rsp.py
SELECTION KEY:
Rock = r
Paper = p
Scissors = sc
Lizard = l
Spock = sp

Score is 0-0
Enter your selection: T
Not legal selection!

Score is 0-0
Enter your selection: l

p1 plays L and p2 plays SP
 -> p2 wins

Score is 0-1
Enter your selection: l

p1 plays L and p2 plays SC
 -> p2 wins

...

The game is over!!
p2 won with score 2-5
brunsgaard
  • 5,066
  • 2
  • 16
  • 15
  • This is excellent - and I have learned some things here for sure. Unfortunately I think I had to go the way I did. here is what the assignment wanted me to do: – lovechicken Mar 20 '15 at 04:13
  • (10 points) rockPaperScissorsLizardSpock() Write a Python function to play the game Rock, Paper, Scissors, Lizard Spock. Name your function RockPaperScissorsLizardSpock. It should run as follows: The computer selects rock, paper, scissors, lizard or spock. The user enters her choice. The program prints out the choices and states who won. – lovechicken Mar 20 '15 at 04:13
  • Sample output from a run would look something like: Enter your choice (r)ock, (p)aper, (sc)cissors, (l)izard, (sp)pock): p The computer chose lizard. You chose paper. The computer wins. Your program should continue to play the game until one side has won five times. Note that a large conditional statement could be used to determine the winner, but a more natural way is to use a dictionary – lovechicken Mar 20 '15 at 04:13
  • I see, it was just for inspiration ;) – brunsgaard Mar 20 '15 at 04:16