Reputation: 3
I'm coding a game of rock, paper and scissors in Python. But here is the error:
If I have played 8 times and I want to exit, the game asks me 8 times too.
Example: I played 5 times.
The game asks me: Do you want to exit? yes/no.
When I say (write) yes, the game asks me again, this case 5 times.
I am a beginner in Python programming, and I really don't understand why this is happening.
Can you help me please?
I'm programming in Windows and using the command line to execute the program. (I don't know if this affects the correct function of the program.)
Here is the code. It's not finished yet:
class RPS_Game(object):
def Check(self):
P1 = raw_input("Player 1: Enter Rock, Paper or Scissors: ")
P2 = raw_input("Player 2: Enter Rock, Paper or Scissors: ")
if(str(P1.lower()) != "rock" and str(P1.lower()) != "paper" and str(P1.lower()) != "scissors"):
print "Must be Rock, Scissors or Paper, not: " + str(P1.lower())
elif(str((P2).lower()) != "rock" and str(P2.lower()) != "paper" and str(P2.lower()) != "scissors"):
print "Must be Rock, Scissors or Paper, not: " + str(P2.lower())
else:
sendDataToGame = self.Game(P1,P2)
def Game(self,P1,P2):
self.P1 = P1
self.P2 = P2
wantToExit = ""
while(True):
if(str(self.P1).lower() == str(self.P2).lower()):
print "You are in a tie!"
wantToExit = raw_input("Do you want to exit? yes/no: ")
if(wantToExit.lower() == "yes"):
break
else:
self.Check()
Call = RPS_Game() #instantiate
Call.Check() #calling Check function
Upvotes: 0
Views: 169
Reputation: 8520
you fall in some recursive call
check ->
Game ->
check ->
Game -> ...
when you exit the game in one level you return to a previous level in the chain call and that is why it ask you so many times.
You also convert your variables to string when they are already a string like in str(...)
so that accomplished nothing. You also repeat to many time a call to lower, try to avoid that as much as possible. Instead of recursive call as you are doing now use return
to get the result of a function.
like this for example
class RPS_Game(object):
def ask_play(self, player):
# this function will iterate until you get a satisfactory
# input from the user
while True:
P = raw_input(player+" Enter Rock, Paper or Scissors: ").lower()
#raw_input give you a string result, to that result you can immediately call
#.lower(), that way you always work with a lower case string
if P in {"rock","paper","scissors"}:
#this is one of the best way to ask if a variable have one of several values
return P #exit the function now that you get a satisfactory input
else:
print "Must be Rock, Scissors or Paper, not:", P
def Game(self):
while True:
P1 = self.ask_play("Player 1")
P2 = self.ask_play("Player 2")
if P1 == P2:
print "You are in a tie!"
wantToExit = raw_input("Do you want to exit? yes/no: ").lower()
if wantToExit == "yes":
break
elif P1 == "rock" and P2 == "paper":
print "Player 2 win"
#complete the rest of combination
the_game = RPS_Game() #instantiate
the_game.Game() #play the game
notice how I make the ask_play
as general as possible and the details are provided by how you used it, that way you don't need to complicated stuff by checking 2 variables at the same time against all possible combination, just do it for 1 variable, and use that generalized function to get as may values as you want as all of them are obtained the same way
Upvotes: 0
Reputation: 9633
You're recusively creating more games. Notice that RPS_Game.Game
calls self.Chek()
, and RPS_Game.Check
calls self.Game()
.
So every time a game is over, the line with sendDataToGame = self.Game(P1,P2)
creates a new game. You have to exit all of the games to exit the script.
You have a lot of other things in your code I would do differently as well, so here's an implementation that fixes your issue and cleans up some other things:
class RPS_Game(object):
# create tuples that contain all valid combinations
# this will make the comparisons easier later
ties = (('r', 'r'), ('p', 'p'), ('s', 's'))
p1_wins = (('r', 's'), ('s', 'p'), ('p', 'r'))
p2_wins = (('s', 'r'), ('p', 's'), ('r', 'p'))
# use a method to print our options for the users so we don't have to code the same
# thing twice - also notice that I'm using the python convention of lowercase names
# for functions & methods
def display_options(self, player):
print("Player {}: Press 'R' for rock, 'P' for paper, or 'S' for scissors"
.format(player)) # using string substitution to insert the player
# number appropriate on each function call
def check(self, inputs):
# Since we created the ties and wins tuples, we can now use the "in" operator
# to check for membership instead of having long and difficult to read
# string comparisons
if inputs in self.ties:
print("You tied!")
elif inputs in self.p1_wins:
print("Player 1 wins!")
elif inputs in self.p2_wins:
print("Player 2 wins!")
# if the inputs weren't in any of our tuples, we know it was invalid input
else:
print("\nInvalid input. Please try again.\n")
# return false if the input was invalid - this will be used by the caller
return False
# returning True indicates that the responses were valid
return True
def run(self):
# use a loop to start another game if the user wants to
while True:
# call our display options function, passing it the player number
self.display_options(1)
# get first player's response
p1 = raw_input("").lower()
# same things for second player
self.display_options(2)
p2 = raw_input("").lower()
# create a tuple out of our player's selections for easy membership
# checking in our tuples of valid combinations
inputs = (p1, p2)
# check our inputs both for validity and to see who wins
valid = self.check(inputs)
# if our input wasn't valid, skip the exit prompt and start a new game
# notice how the "check" function was set up to return false if
# input is not valid - now this comparison reads almost like regular
# English!
if not valid:
continue
repeat = raw_input("Play again? (Y/N)\n").lower()
# if the user entered "n" for starting another game, break out of
# the infinite loop and exit
if repeat == 'n':
break
# create the game object and run it
game = RPS_Game()
game.run()
Upvotes: 2