5
\$\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\$
4
\$\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\$
6
\$\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\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.