Trying to avoid Globals in Python Functions

Question:

I’m still munching through learning the ins and outs of Python3 through multiple sources (books like LPTHW and online resources) and I like to mash up everything I have learned in some of the tasks… only this one has me stumped as I come from a limited C/Embedded background and I know that (writeable) globals are very much frowned upon which is why I am trying to avoid any globals where possible.

Only in this instance my mind has gone blank as to how to deal with num_guesses in the following code (as it’s broken by num_guesses in it’s current state):

import random

min_num = 1
max_num = 100

def generate_number(min_num, max_num):
    """This function generates a random number within a specified range"""
    return random.randint(min_num, max_num)

def get_guess():
    """This function asks the player to guess a number"""
    guess = input("Guess a number between 1 and 100: ")
    return int(guess)

def check_guess(guess, target):
    """This function checks if the player's guess matches the target number"""
    if guess == target:
        print("Congratulations! You guessed the number!")
        return True
    elif guess < min_num or guess > max_num:
        print("Your guess is out of bounds. Try again.")
        return False
    elif num_guesses[-2]:
        if abs(target-guess) < abs(target-num_guesses[-2]):
            print("Warmer!")
            return False
        else:
            print("Colder!")
            return False
    else:
        if abs(target-guess) <= 10:
            print("Warm!")
            return False
        else:
            print("Cold!")
            return False

def play_game():
    """This function runs the game"""
    #min_num = 1
    #max_num = 100
    target = generate_number(min_num, max_num)
    guesses = []
    num_guesses = 0

    while True:
        guess = get_guess()
        num_guesses += 1

        if guess in guesses:
            print("You already guessed that number. Try again.")
        else:
            guesses.append(guess)
            if check_guess(guess, target):
                print("You guessed the number in", num_guesses, "guesses!")
                break

    play_again = input("Do you want to play again? (yes or no)")
    if play_again == "yes":
        play_game()
    else:
        print("Thanks for playing!")

play_game()

I’ve yet to tackle the object orientated side of things so trying to keep this fairly simple using what I have learned so far as I move into the next step (which is the object orientated part of which I have no experience at all!).

The game is [supposed to be] a simple ‘guess the number’ type game where the input is checked for validity within the range and then hot/cold based on how close you get to the number based off your previous guess.

ANY pointers on how to go about fixing this so I can learn best practises would be greatly appreciated 🙂

Thanks

EDIT:

Thanks to the answer below I was also able to understand how to pass min_num and max_num integers to various functions without being a global variable.

I also added some text and tidied up other parts to make it more user friendly 🙂

import random

def show_instructions(min_num, max_num):
    """This function displays the rules/instructions for playing the game"""
    print("nn")
    print("*" * 61)
    print("*** Welcome to the Random Number Guess GeneRatoR [RNG GRR]***")
    print("*" * 61)
    print("nTo play:n")
    print("Enter a value between the range shown at the start of the game")
    print("After each guess you will be told 'Warmer' if getting closer to the value")
    print("If further away, then it will show 'Colder'.")
    print("If within 10 of the value it will say 'Very Warm!'n")
    print(f"To begin: enter a number between the {min_num} and {max_num}")

def generate_number(min_num, max_num):
    """This function generates a random number within a specified range"""
    return random.randint(min_num, max_num)

def get_guess(min_num, max_num):
    """This function asks the player to guess a number"""
    guess = input("> ")
    return int(guess)

def check_guess(guess, target, guesses, min_num, max_num):
    """This function checks if the player's guess matches the target number"""
    if guess == target:
        print("Congratulations! You guessed the number!")
        return True
    elif guess < min_num or guess > max_num:
        print("Your guess is out of bounds. Try again.")
        print(f"The number is between {min_num} and {max_num}.")
        return False
    elif abs(target - guess) <= 10:
            print("Very warm!")
            return False
    elif len(guesses) > 1:
        if abs(target-guess) < abs(target-guesses[-2]):
            print("Warmer!")
            return False
        else:
            print("Colder!")
            return False
    else:
        print("Quite far out, try again")
        return False

def play_game():
    """This function runs the game"""
    min_num = 1
    max_num = 100
    target = generate_number(min_num, max_num)
    guesses = []
    num_guesses = 0

    show_instructions(min_num, max_num)

    while True:
        guess = get_guess(min_num, max_num)
        num_guesses += 1

        if guess in guesses:
            print("You already guessed that number. Try again.")
        else:
            guesses.append(guess)
            if check_guess(guess, target, guesses, min_num, max_num):
                print("You guessed the number in", num_guesses, "guesses!")
                break

    play_again = input("Do you want to play again? (yes or no)")
    if play_again == "yes":
        play_game()
    else:
        print("n***Thanks for playing!nn")

play_game()
Asked By: Dan Lewis

||

Answers:

I have changed your code as follows:
I passed in the guesses list to your check_guess function, as I believe that is what you were trying to index when you used num_guesses[-2].
For readability, I also modified your if statement to verify the length of the list instead of checking for an existence of a -2 index.

import random

min_num = 1
max_num = 100

def generate_number(min_num, max_num):
    """This function generates a random number within a specified range"""
    return random.randint(min_num, max_num)

def get_guess():
    """This function asks the player to guess a number"""
    guess = input("Guess a number between 1 and 100: ")
    return int(guess)

def check_guess(guess, target, guesses):
    """This function checks if the player's guess matches the target number"""
    if guess == target:
        print("Congratulations! You guessed the number!")
        return True
    elif guess < min_num or guess > max_num:
        print("Your guess is out of bounds. Try again.")
        return False
    elif len(guesses) > 1:
        if abs(target-guess) < abs(target-guesses[-2]):
            print("Warmer!")
            return False
        else:
            print("Colder!")
            return False
    else:
        if abs(target-guess) <= 10:
            print("Warm!")
            return False
        else:
            print("Cold!")
            return False

def play_game():
    """This function runs the game"""
    #min_num = 1
    #max_num = 100
    target = generate_number(min_num, max_num)
    guesses = []
    num_guesses = 0

    while True:
        guess = get_guess()
        num_guesses += 1

        if guess in guesses:
            print("You already guessed that number. Try again.")
        else:
            guesses.append(guess)
            if check_guess(guess, target, guesses):
                print("You guessed the number in", num_guesses, "guesses!")
                break

    play_again = input("Do you want to play again? (yes or no)")
    if play_again == "yes":
        play_game()
    else:
        print("Thanks for playing!")

play_game()

num_guesses isn’t necessary in the function, as in check_guesses you only care about the previous guesses, and not the number of guesses.

Answered By: Dominic