Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

Python

Kevin Faust
Kevin Faust
15,353 Points

Python: Number Game Refinement

im debugging what i have right now and so when i type in a number, it tells me "local variable 'count' referenced before assignment. But I initialized my count variable at the very top so i dont understand why it is telling me this. The error occurs in my guessed() method which is the first function below.

import random

# variables
n1 = 1
n2 = 10
count = 0
guess_count = 10
again = False
guess = ""
secret_numer = ""

# functions
def guessed():
    count += 1
    guess_count -= 1

def isValid(input):
    try:
        int(input)
        return True
    except ValueError:
        return False

def winMessage():
    print("You guessed the number! It took you {} tries and you had {} guess left".format(count, guess_count))

def loseMessage():
    print("You have used all your guesses. Game over")

def incorrectGuessMessage():
    if guess > secret_number:
        print("{} was incorrect. Your guess was too high. You have {} guesses left".format(guess, guess_count))
    else:
        print("{} was incorrect. Your guess was too low. You have {} guesses left".format(guess, guess_count))

def promptPlayAgain():
    response = input("Would you like to play again? Type 'Y' or 'N'")
    if response.upper() == "Y":
        main()


# main 
def main():
    print("Welcome. You have {} guesses to guess the number. Guess a number between {} and {}: ".format(guess_count, n1, n2))
    secret_num = random.randint(n1, n2)
    while True:

        if guess_count != 0:

            guess = int(input("> "))
            if isValid(guess):
                if guess == secret_num:
                    winMessage()
                    break
                else:
                    guessed()
                    incorrectGuessMessage()
            else:
                print("That is not a proper number")
                continue

        else:
            loseMessage()
            break
    promptPlayAgain()

main()
Kevin Faust
Kevin Faust
15,353 Points

Ok I did this and it worked. However, I read on stackoverflow that we should NOT use global variables but i honestly dont know how to do this without the use of global variables. i did not yet watch kenneth's solution yet. i was wondering if I can have some feedback on this code.

import random

count = 0
guess_count = 10

# functions
def guessed():
    global count
    global guess_count
    count += 1
    guess_count-=1

def isValid(input):
    try:
        int(input)
        return True
    except ValueError:
        return False

def winMessage():
    print("You guessed the number! It took you {} tries and you had {} guess left".format(count, guess_count))

def loseMessage():
    print("You have used all your guesses. Game over")

def incorrectGuessMessage(guess, secret_num):
    if guess > secret_num:
        print("{} was incorrect. Your guess was too high. You have {} guesses left".format(guess, guess_count))
    else:
        print("{} was incorrect. Your guess was too low. You have {} guesses left".format(guess, guess_count))

def promptPlayAgain():
    response = input("""Would you like to play again? Type 'Y' or 'N': 
    > """)
    if response.upper() == "Y":
        main()


# main 
def main():
    global count 
    global guess_count
    count = 0
    guess_count = 10
    n1 = 0
    n2 = 10
    print("Welcome. You have {} guesses to guess the number. Guess a number between {} and {}: ".format(guess_count, n1, n2))
    secret_num = random.randint(n1, n2)
    while True:

        if guess_count != 0:

            guess = input("> ")
            if isValid(guess):
                guess = int(guess)
                guessed()
                if guess == secret_num:
                    winMessage()
                    break
                else:
                    incorrectGuessMessage(guess, secret_num)
                    continue
            else:
                print("That is not a proper number")
                continue

        else:
            loseMessage()
            break
    promptPlayAgain()

main()

3 Answers

Chris Freeman
MOD
Chris Freeman
Treehouse Moderator 68,423 Points

To avoid using global pass the variables as arguments:

# functions
def guessed(count, guess_count):
    count += 1
    guess_count-=1

EDIT: Above trivial example does not modify the variables in the global scope because the int arguments are immutable. Pass arguments as list or dict:

>>> counts = {'count': 0, 'global_guesses': 0}
>>> def test_modifies_global(counts):
...     counts['count'] += 1
...     counts['global_guesses'] += 2
...     print("counts", counts)
... 
Kevin Faust
Kevin Faust
15,353 Points

That's actually what I did at first but it wasn't updating the "count" and "guess_count" variables located inside my main() method

I tried again and still doesnt work

Am I supposed to return the count and guess_count variables from the guessed() method? and then update the variables from my main method?

Kevin Faust
Kevin Faust
15,353 Points

i dont think im doing this right

Chris Freeman
Chris Freeman
Treehouse Moderator 68,423 Points

My fault. The example I used was too trivial.

If you pass immutable arguments like integers, strings or tuples to a function, the passing acts like call-by-value. The object reference is passed to the function parameters. They can't be changed within the function, because they can't be changed at all, i.e. they are immutable. It's different, if we pass mutable arguments [like lists, dicts, classes]. They are also passed by object reference, but they can be changed in place in the function. If we pass a list to a function, we have to consider two cases: Elements of a list can be changed in place, i.e. the list will be changed even in the caller's scope. If a new list is assigned to the name, the old list will not be affected, i.e. the list in the caller's scope will remain untouched. Reference

If count were a list:

>>> count = [0]
>>> def test_modifies_global(count):
...     count[0] += 1
...     print("count:", count)
... 
>>> count
[0]
>>> test_modifies_global(count)
count: [1]
>>> test_modifies_global(count)
count: [2]
>>> test_modifies_global(count)
count: [3]
>>> test_modifies_global(count)
count: [4]

Or a dict:

>>> counts = {'count': 0, 'global_guesses': 0}
>>> def test_modifies_global(counts):
...     counts['count'] += 1
...     counts['global_guesses'] += 2
...     print("counts", counts)
... 
>>> counts
{'count': 0, 'global_guesses': 0}
>>> test_modifies_global(counts)
counts {'count': 1, 'global_guesses': 2}
>>> test_modifies_global(counts)
counts {'count': 2, 'global_guesses': 4}
>>> test_modifies_global(counts)
counts {'count': 3, 'global_guesses': 6}
>>> counts
{'count': 3, 'global_guesses': 6}
Kevin Faust
Kevin Faust
15,353 Points

thanks alot for that. I didn't understand the dict part as we haven't learned that yet but I do understand what you wrote with the list. Lists are mutable and so if we pass in a parameter that takes in a list and we modify that parameter, the list will be changed even from outside that function. if we pass in string or ints, then a local variable of that parameter will be created. makes sense

i encountered some problems now. This is a snippet from my guessed method. I tried to follow your example but I get this error: Index Error: List index out of range

This doesn't make sense to me because we are just increasing the length of the list by 1 or decreasing it by 1. Why would an Index Error possibly occur?

n1 = [0]
n2 = [10]

guessed(count, guess_count, n1, n2)

def guessed(count, guess_count, n1, n2):
    count[n1] += 1
    guess_count[n2] -=1

And also im trying to call len() on the list so i can get the actual number instead of something like [3]. I called the len() function on a list of 10 however instead of the number 10, i get the number 1. Any idea why this is the case?

This is another snippet

    count = [0]
    guess_count = [10]
    n1 = 0
    n2 = 10
    print("Welcome. You have {} guesses to guess the number. Guess a number between {} and {}: ".format(len(guess_count), n1, n2))

What gets printed is "You have 1 guesses to......" It should say 10 instead of 1

Here is my full code as of now:

import random

# functions
def guessed(count, guess_count, n1, n2):
    count[n1] += 1
    guess_count[n2] -=1

def isValid(input):
    try:
        int(input)
        return True
    except ValueError:
        return False

def winMessage(count, guess_count):
    print("You guessed the number! It took you {} tries and you had {} guess left".format(count, guess_count))

def loseMessage():
    print("You have used all your guesses. Game over")

def incorrectGuessMessage(guess, secret_num, guess_count):
    if guess > secret_num:
        print("{} was incorrect. Your guess was too high. You have {} guesses left".format(guess, guess_count))
    else:
        print("{} was incorrect. Your guess was too low. You have {} guesses left".format(guess, guess_count))

def promptPlayAgain():
    response = input("""Would you like to play again? Type 'Y' or 'N': 
    > """)
    if response.upper() == "Y":
        main()


# main 
def main():
    count = [0]
    guess_count = [10]
    n1 = 0
    n2 = 10
    print("Welcome. You have {} guesses to guess the number. Guess a number between {} and {}: ".format(len(guess_count), n1, n2))
    secret_num = random.randint(n1, n2)
    while True:

        if guess_count != 0:

            guess = input("> ")
            if isValid(guess):
                guess = int(guess)
                guessed(count, guess_count, n1, n2)
                if guess == secret_num:
                    winMessage(len(count), len(guess_count))
                    break
                else:
                    incorrectGuessMessage(guess, secret_num, len(guess_count))
                    continue
            else:
                print("That is not a proper number")
                continue

        else:
            loseMessage()
            break
    promptPlayAgain()

main()
Chris Freeman
Chris Freeman
Treehouse Moderator 68,423 Points

The key is not to confuse the index of a value and the list with the actual value.

count = [0]  # list with one item at index 0 with value count[0]
guess_count = [10] # list with one item at index 0 with value guess_count[0]

def guessed(count, guess_count):
    # count and guess_count passed as lists
    # modify the first item in list count. This is the actual count value 
    count[0] += 1
    # modify the first item in list guess_count. This is the actual guess_count value 
    guess_count[0] -=1

My example of modifying the lists count and guess_count were intended to be examples of technique and not necessarily directly applicable to your code situation. In my example, I was using a 1-item list for count and guess_count to illustrate how the results of passing a list and modifying the items of that list within a function can be seen outside of the function.

Overall, I'm not sure how you are using count vs guess_count. Are n1 and n2 used as the initial values for the low and high limits?

Kevin Faust
Kevin Faust
15,353 Points

Oh I completely misinterpreted what you were saying. I thought that count = [0] and guess_count = [10] meant that we were creating a list with 0 items and 10 items respectively and therefore the lengths of each are 0 and 10 respectively. I got confused with java where you can specify the initial length of an array. After I realized my mistake, everything made sense instantly.

The program is working perfectly now. thanks for the help

SNEHA VASANTH
SNEHA VASANTH
4,455 Points
def playAgainCheck():
  print("Do you want to play again? Y/N ")
  while True:
    playAgain = input(">  ")
    if playAgain == "Y":
      return True
    elif playAgain == "N":
      return False
    else:
      print("Please enter Y or N only")

def checkNumber():
  print("Is the number bigger or smaller? B/S ")
  while True:
    checkGuess = input("> ")
    if checkGuess == "S":
      return "S"
    elif checkGuess == "B":
      return "B"
    else:
      print("Please enter either S or B ")

def guessRandomNumber(count,number1,number2,removeList):
  valuesList = []
  values = range(number1,number2+1)
  #print(values)
  for i in values:
    if i not in valuesList:
      valuesList.append(i)
  for i in removeList:
    #print(removeList)
    if i in valuesList:
      #print(valuesList)
      valuesList.remove(i)
  random.shuffle(valuesList)
  return valuesList

import random

# check for int input
# too high
# too low
# play again

count = 0
keepPlaying = True
smallBig = "B"
guess = 0
while keepPlaying:
  if count == 0: 
    guessList = []
    removeList = []
    number1 = 1
    number2 = 10
    guess = random.randint(1,10)
    removeList.append(guess)
  else:
    guessList = guessRandomNumber(count,number1,number2,removeList)
    #for item in guessList:
      #print(item)
    guess = guessList.pop()
    removeList.append(guess)
    #print(removeList)
  count += 1
  answer = input("Computer says {}, Is this right? Y/N  ".format(guess))
  if answer == "Y":
    print("Computer won!")
    count = 0
    keepPlaying = playAgainCheck()
  elif count == 5:
    count = 0
    print("Computer lost!")
    keepPlaying = playAgainCheck()
  else:
    smallBig = checkNumber()
    if smallBig == "S":
      number2 = guess
    else:
      number1 = guess