First, check_replay
has a few notable things.
Since you're only using valid_yes
and valid_no
to check for membership, they would be better as sets which have a much more efficient membership lookup. The performance difference won't be noticeable in this case, but it's a good thing to keep in mind.
The whole purpose of check_replay
is to ask if they want to play again, yet you're printing the "Do you want to play again?"
message outside of the function. I would just pass it into the initial input
call.
Even as someone who loves recursion, I agree with @abendrot that recursion isn't the ideal tool for the job here. Using it here means your program could crash if the user enters bad input too many times. I'd just use a while
loop.
I also think it should return the decision instead of calling start_game
Taking all that into consideration, I'd write it closer to:
def check_replay():
valid_yes = {"yes", "ye", "y"} # Using sets instead of lists
valid_no = {"no", "n"}
while True:
answer = input("Do you want to play again?: ") # Printing the message here instead
if answer.lower() in valid_yes:
return True
# I added blank lines for readability
elif answer.lower() in valid_no:
print("Thanks for playing!")
return False
else:
print("Please enter yes or no")
My other concern is that start_game
and check_valid
don't really make sense as two different functions. start_game
is basically just being used to initialize the globals, but the globals aren't necessary in the first place. Normally I'm all for breaking up functions into smaller pieces, but I think here everything works better if you collapse them into one function. I also neatened up a lot of stuff. See the comments:
def play_game():
# I wrapped the whole thing in a loop to avoid the recursive call
while True:
print("I'm thinking of a number between 1 and 10.")
print("Can you guess it?")
# No more globals
number = random.randint(1, 10)
counter = 0
while True:
counter += 1
guess = input("Your guess: ")
try:
val = int(guess) # You forgot to use val and were instead writing int(guess) all over
if val not in set(range(0, 11)): # Made into a set as well
print("Hmmm.. that number is not between 1 and 10! Try again!")
# Again, I added blank lines for readability
elif val > number:
print("Too high, try a smaller number")
elif val < number:
print("Too low, try a bigger number")
else: # This should just be an else since if the other two checks failed, they must be equal
print("Congratulations, you guessed it! The number was " +
str(number) + ".\nIt took you " + str(counter) + " tries!")
if check_replay():
break # Break to the outer loop to play again
else:
return # Else exit
except ValueError:
print("That's not a number, try again!")
If you wanted to break that large function up (which is understandable), I'd factor out the turn-taking loop aspect of it. Something like:
def make_guess(computer_number): # Pass in the target number
while True:
guess = input("Your guess: ")
try:
val = int(guess)
if val not in set(range(0, 11)):
print("Hmmm.. that number is not between 1 and 10! Try again!")
elif val > computer_number:
print("Too high, try a smaller number")
elif val < computer_number:
print("Too low, try a bigger number")
else:
return True # Tell the caller that the player won
return False # Else return that they haven't won yet
except ValueError:
print("That's not a number, try again!")
def play_game():
while True:
print("I'm thinking of a number between 1 and 10.")
print("Can you guess it?")
number = random.randint(1, 10)
counter = 0
while True:
counter += 1
has_won = make_guess(number)
if has_won:
print("Congratulations, you guessed it! The number was " +
str(number) + ".\nIt took you " + str(counter) + " tries!")
if check_replay():
break
else:
return
Normally I don't like using while True
, but to avoid it here you'd need to use flags all over instead which I don't think would help readability.
Altogether, I have:
import random
def make_guess(computer_number): # Pass in the target number
while True:
guess = input("Your guess: ")
try:
val = int(guess)
if val not in set(range(0, 11)):
print("Hmmm.. that number is not between 1 and 10! Try again!")
elif val > computer_number:
print("Too high, try a smaller number")
elif val < computer_number:
print("Too low, try a bigger number")
else:
return True # Tell the caller that the player won
return False # Else return that they haven't won yet
except ValueError:
print("That's not a number, try again!")
def play_game():
while True:
print("I'm thinking of a number between 1 and 10.")
print("Can you guess it?")
number = random.randint(1, 10)
counter = 0
while True:
counter += 1
has_won = make_guess(number)
if has_won:
print("Congratulations, you guessed it! The number was " +
str(number) + ".\nIt took you " + str(counter) + " tries!")
if check_replay():
break
else:
return
def check_replay():
valid_yes = {"yes", "ye", "y"} # Using sets instead of lists
valid_no = {"no", "n"}
while True:
answer = input("Do you want to play again?: ") # Printing the message here instead
if answer.lower() in valid_yes:
return True
# I added blank lines for readability
elif answer.lower() in valid_no:
print("Thanks for playing!")
return False
else:
print("Please enter yes or no")
play_game()