4
\$\begingroup\$

After an extended absence from coding, I decided I would make something to try and get back on my feet again. I ended up making a project that I have made several times before, a higher-lower guessing game. Now while the coding process went well and I came out with something that works quite well, I feel like I fell into a lot of my old bad coding practices. I feel it would be good that before I move onto bigger projects that I post this here and see where I'm screwing up.

I would just like to know if there are any just general bad practices or things that could be made better.

from random import randint


def find_min_max() -> list:
    """Find ths minimum and maximum values for the number to be between"""
    while True:
        try:
            min_max = [int(input("Please enter the min value: ")), int(input("Please enter max value: "))]
            if min_max[0] < min_max[1]:
                return min_max
            else:
                print("Make sure the min number is smaller than the max number.")
        except ValueError:
            print("Please enter numbers only.")


def find_guess_limit():
    """Finds if the user wants a guess limit, and sets it if they do"""
    while True:  # Finds if the user wants a guess limit
        guess_limit = input("Would you like to limit your guess's? (Y/N): ").lower()
        if (guess_limit == "y") or guess_limit == "n":
            if guess_limit == "n":
                return None
            while True:  # Gets what the user wants the guess limit to be
                try:
                    guess_limit = int(input("What would you like the guess limit to be: "))
                    if guess_limit > 0:
                        return guess_limit
                    else:
                        print("Make sure the number is greater than zero.")
                except ValueError:
                    print("Please enter only a number.")
        else:
            print("Please only enter Y or N.")


def setup():
    """Sets up the game parameters"""
    min_max = find_min_max()
    guess_limit = find_guess_limit()
    return min_max, guess_limit


def play_round(num: int) -> bool:
    """Goes through one guess by the player"""
    while True:
        try:
            guess = int(input("What number is your guess: "))
            if guess == num:
                print("You got it!")
                return True
            elif guess > num:
                print("The number is lower.")
                return False
            elif guess < num:
                print("The number is higher.")
                return False
        except ValueError:
            print("Please only enter a number.")


def reset() -> [bool]:
    """Checks if the player wants to quit, and if they don't, checks if they want to change the rules"""
    while True:  # Checks if the user wants to quit the game
        close = input("Would you like to exit the game? (Y/N): ").lower()
        if (close == "y") or (close == "n"):
            if close == "y":
                quit()
            else:
                break
        print("Please only enter Y or N.")
    while True:  # Checks if the user wants the rules to be changed
        rule_change = input("Would you like to change the rules? (Y/N): ").lower()
        if (rule_change == "y") or (rule_change == "n"):
            if rule_change == "y":
                return True
            else:
                return False
        print("Please only enter Y or N.")


min_max, guess_limit = setup()
while True:
    num = randint(min_max[0], min_max[1])
    if guess_limit is None:
        while True:
            if play_round(num):
                break
    else:
        for _ in range(guess_limit):
            won = play_round(num)
            if won:
                break
        if not won:
            print("Sorry, you ran out of guess's")
    if reset():
        min_max, guess_limit = setup()

\$\endgroup\$

2 Answers 2

2
\$\begingroup\$

Return tuples

find_min_max is not well-suited to returning a list. Instead:

  • Separate min_max into two variables, min_val and max_val
  • return min_val, max_val
  • Change your return hint to Tuple[int, int]

This is what setup already does, though setup would benefit from unpacking the result from find_min_max, and should get its own return type hint.

Grammar

your guess's -> your guesses

Input validation

if (guess_limit == "y") or guess_limit == "n":
    # ...
else:
    print("Please only enter Y or N.")

is better-stated, I think, as

if guess_limit == 'n':
    return None

if guess_limit != 'y':
    print("Please only enter Y or N.")
    continue

# ...

This allows de-indentation of the rest of the loop, takes care of the simple cases first, and reduces the number of comparisons necessary.

Similarly,

    if (rule_change == "y") or (rule_change == "n"):
        if rule_change == "y":
            return True
        else:
            return False
    print("Please only enter Y or N.")

can be

if rule_change in {'y', 'n'}:
    return rule_change == 'y'
print("Please only enter Y or N.")
\$\endgroup\$
5
\$\begingroup\$

Unnecessary construction of lists

min_max = [int(input("Please enter the min value: ")), int(input("Please enter max value: "))]

Unnecessary list construction here. It requires you to do min_max[] to get the correct value. Just remove the list construction and separate it into two variables.

min_val, max_val = int(input("Please enter the min value: ")), int(input("Please enter max value: "))
min_val = int(input("Please enter the min value: "))
max_val = int(input("Please enter the max value: "))

Your except block will catch any bad input. That's good! We can further improve it by doing the following

(optional)

Say I enter the first value correctly, but mess up when I input the second one. The problem here is I have to re-enter the first value again. We can solve this with just a few more lines of code, overall a better experience;

I personally prefer having a function like such

def num_input(prompt, err_msg = "Invalid input!"):
    while True:
        try:
            num = int(input(prompt))
        except Exception:
            print(err_msg)
            continue 
        break
    return num

That way I can take input in the following manner

min_val = num_input("Please enter the min value: ")
max_val = num_input("Please enter the max value: ")

Now each variable has its own while True loop which ensures you get good, valid input.


If-statement logic

        if (guess_limit == "y") or guess_limit == "n":
            if guess_limit == "n":
                return None
            while True:  # Gets what the user wants the guess limit to be
                try:
            ...
            ...

        else:
            print("Please only enter Y or N.")
  • The parenthesis are not required

Notice you are checking for guess_limit == "y" twice here. How about you re-structure this and make it

        if guess_limit == "n":
            return None 
        if guess_limit != "y":
            print("Please only enter Y or N.") 
            continue
        while True:  # Gets what the user wants the guess limit to be
            try:
             .......           

Not only here, but there are 2-3 instances in your code where having a num_input function like the one in my previous point will reduce a lot of repetition. They all follow the same rule, put them in a function.


Splitting work

def find_guess_limit():
    """Finds if the user wants a guess limit, and sets it if they do"""
    while True:  # Finds if the user wants a guess limit
        guess_limit = input("Would you like to limit your guess's? (Y/N): ").lower()
        if (guess_limit == "y") or guess_limit == "n":
            if guess_limit == "n":
                return None
            while True:  # Gets what the user wants the guess limit to be
                try:
                    guess_limit = int(input("What would you like the guess limit to be: "))
                    if guess_limit > 0:
                        return guess_limit
                    else:
                        print("Make sure the number is greater than zero.")
                except ValueError:
                    print("Please enter only a number.")
        else:
            print("Please only enter Y or N.")

Better split this into two functions, wants_limit_guess() and find_limit_guess(). Follow the single-responsibillity-principle. That way you can do

if (wants_limit_guess()) 
    limit_guess = find_limit_guess()
else:
    ...
\$\endgroup\$
0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.