number-guessing game - 1 through 30

I created this python number-guessing game and I have two concerns with it. The code works as intended with no flaws; however, I'm not too fond of the way I wrote it. It is messy, unorganized, and all over the place. There is repeated code such as the while loop that checks for a negative number or a number greater than 30, and the repeating "if number == n".

I wrote it like that because the program would bug if I did not repeat those expressions.

I also want to make it ask the user if they would like to play again; I do not know how.

import random
n = random.randint(1, 31)

choice = input("\nDo you want to play a game? (y/n): ")
if (choice == "y") or (choice == "Y") or (choice == "Yes") or (choice == "yes"):

counter = 0
number = int(input("\nGuess a number between 1 and 30: "))
if (number == n):
print("\nYou guessed correctly!!! Go you!")
counter += 1

while (number < 1) or (number > 30):
number = int(
input("\nThat is an invalid number. Please re-enter a number between 1 and 30: "))
if (number == n):
print("\nYou guessed correctly!!! Go you!")

while number != n:
if (number <= 5) and (n > 5):
number = int(input("\nToo low! Try again: "))
counter += 1
elif (number >= 25) and (n < 25):
number = int(input("\nWay too high! Try again: "))
counter += 1
elif ((n + 5 >= number) and (n - 5 <= number)):
number = int(input("\nYou are so close! Try again: "))
counter += 1
else:
number = int(input("\nWrong! Try again: "))
counter += 1
if (number == n):
print("\nYou guessed correctly!!! Go you!")
while (number < 1) or (number > 30):
number = int(
input("\nThat is an invalid number. Please re-enter a number between 1 and 30: "))

print(f"You took {counter} attempts to guess the number!")

else:

• Do you know about functions? Have you tried using one to solve the duplication? Feb 28 at 22:46

Bug

First off there's a minor bug in your code in that random.randint(1, 31) can be 31, which you are not allowed to enter in your game. You probably want random.randint(1, 30)

Naming

Your names are a little unhelpful. n should probably be something like target, counter num_guesses or similar. This makes it easier for someone coming along to easily identify what the variables actually mean.

Structure

You take an initial guess, then have a second guess if the number is outside [1,30], then you have 2 whiles one for the initial guess and one for subsequent ones. This is probably a little unnecessary.

For checking numbers we probably only need 2 loops. One to check while it's not the correct number, and another to get a valid input from the user.

We could just get the guess as a function!

def get_guess():
""" Get valid input from player """
while True:
inp = input("Guess a number between 1 and 30: ")
try:
inp = int(inp)
except ValueError:
print(f"Invalid value input {inp}, must be an integer between 1 and 30")
continue
if inp in range(1, 31):
return inp

print(f"Invalid value input {inp}, must be an integer between 1 and 30")

guesses = 0
while guesses < MAX_GUESSES:
number = get_guess()
if number <= 5 and n > 5:
...


Use of ifs

Comparisons in Python can be chained to clean up a lot of checks.

if 0 < i < 31:


checks whether i is in the range [1, 30], you can also do i in range(1,31) which also makes your intent obvious.

In order to check how far you are from the correct answer, rather than checking the value of n and number separately, why not check if number is far from n by calculating the difference?

if abs(number - target) <= 5:  # Could just precompute the difference and compare it against each
print("You're so close try again!")
elif number - target > 10:
print("Way too high!")
elif number - target > 5:
print("Too high!")
elif target - number > 10: # N.B. these are target - number i.e. number - target < -10
print("Way too low!")
elif target - number > 5:
print("Too low!")


In order to check whether choice is y,Y,yes or Yes, we could do:

if choice.lower() in ('y', 'yes'):


which will case insensitively check.

Replay

To answer your question on replaying the game, we need to wrap the whole thing in a while loop checking each time whether the player wants to play again, and generating a new number.

Putting it all together

Putting it all together with main guards and functions we might end up with something like:

"""
Number guessing game
"""

import random

def get_guess():
""" Get valid input from player """
while True:
inp = input("Guess a number between 1 and 30: ")
try:
inp = int(inp)
except ValueError:
print(f"Invalid value input {inp}, must be an integer between 1 and 30")
continue
if inp in range(1, 31):
return inp

print(f"Invalid value input {inp}, must be an integer between 1 and 30")

def play_guess_game():
""" Play a round of the guessing game """
target = random.randint(1, 30)

number = -1
guesses = 0
while number != target:
guesses += 1
number = get_guess()

diff = number - target

if diff == 0:
print("You guessed correctly!!! Go you!")
elif abs(diff) <= 5:
print("You're so close try again!")
elif diff > 10:
print("Way too high!")
elif diff > 5:
print("Too high!")
elif diff < -10:
print("Way too low!")
elif diff < -5:
print("Too low!")

print(f"You took {guesses} attempts to guess the number!")

if __name__ == "__main__":
while input("Do you want to play a game? (y/[n]): ").lower() in ('y', 'yes'):
play_guess_game()