Name 'x' is not defined / Global variable? - python

I'm learning to program with python and I came across this issue: I'm trying to make a Guessing Game, and while trying to check for the win condition, the function doesn't recognise the input variable, which I made sure I returned with a previous function. So i get the 'name << 'first_input' is not defined' >> error. I thought it had something to do with the variable not being global or sth like that.
import random
ran_int = random.randint(1,100)
guesses = 0
# here you input the number and it keeps asking unless you do so with 1 to 100
def ask():
first_input = 0
while first_input < 1 or first_input > 100:
first_input = int(input('Enter a number between 1 and 100: '))
return first_input
# this is just to increment the number of guesses stored for showing at the end # of the game
def guesses_inc():
global guesses
guesses += 1
return guesses
# here is where i get the error, as if my ask() function didn't return
# the value properly or as if I assigned it wrongly
def check_win_1():
if first_input == ran_int:
guesses_inc()
print(f'BINGO!\nYou guessed correctly after {guesses} times.')
elif (abs(ran_int - first_input) <= 10):
guesses_inc()
print('WARM!')
ask2()
elif first_input < 1 or first_input > 100:
print('Out of bounds!')
ask2()
else:
guesses_inc()
print('COLD!')
ask2()
ask()
check_win_1()
And here is the error
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
<ipython-input-11-bfd5497995df> in <module>
----> 1 check_win_1()
NameError: name 'first_input' is not defined
I didn't paste the whole code because while testing it it returned the error at this stage so I didn't think the rest mattered for this particular problem. I tried making the var input global and stuff like that but i don't think I did it properly.

Your method call is not correct. You should call your functions like this
def check_win_1(first_input):
if first_input == ran_int:
guesses_inc()
print(f'BINGO!\nYou guessed correctly after {guesses} times.')
elif (abs(ran_int - first_input) <= 10):
guesses_inc()
print('WARM!')
ask2()
elif first_input < 1 or first_input > 100:
print('Out of bounds!')
ask2()
else:
guesses_inc()
print('COLD!')
ask2()
first_input = ask()
check_win_1(first_input)

The error is there because you are trying to use first_input somewhere (i.e. inside check_win_1()).
A possible, not recommended, solution is to qualify your variable as global, which should be used VERY sparingly.
Instead, it is recommended to use function parameters, so as to encapsulate your code in self-contained blocks, e.g.:
def func(a, b):
return a + b
x = func(10, 5)
rather than:
def func():
global a, b
return a + b
a = 10
b = 5
x = func()
For your that may mean doing something like:
def check_win_1(first_input, ran_int):
...
and use them accordingly, e.g.:
first_input = ask()
check_win_1(first_input, ran_int)
etc.
EDIT
Following the above principle, your code could have looked like:
import random
MIN_VAL = 1
MAX_VAL = 100
WARM_LIMIT = 10
def ask_number(
min_val=MIN_VAL,
max_val=MAX_VAL):
guess = None
while guess is None:
guess = int(input(f'Enter a number between {min_val} and {max_val}: '))
if guess < min_val or guess > max_val:
print('Out of bounds!')
guess = None
return guess
def check_guess(
guess,
target,
num_guesses,
warm_limit=WARM_LIMIT):
if guess == target:
print(f'BINGO!\nYou guessed correctly after {num_guesses} times.')
return True
else:
if (abs(guess - target) <= warm_limit):
print('WARM!')
else:
print('COLD!')
return False
# : main
target = random.randint(MIN_VAL, MAX_VAL)
num_guesses = 0
won = False
while not won:
guess = ask_number()
num_guesses += 1
won = check_guess(guess, target, num_guesses)

Related

Python, countdown number if the guess is right?

new in python here,
I have a code which guesses number and it works fine. but what I want to add to it is when my guess is correct count down to 0,
I have this code :
num = 3
my_guess = ""
while my_guess != num:
my_guess = int(input("enter:"))
print ("great job")
where and how to I do it (with comment line if possible please )
thanks
Hopefully this isn't too much new information at once but import random if/else continue try/raise and formatted strings are certainly worth understanding.
import random # random module for PRNG
num = random.randint(0,9) # get int 0<=i<=9
count_wins = 0 # start counter for wins at 0
count_losses = 0 # start counter for wins at 1
while count_wins <= 3: # while count_wins is less than 3
try: # If an error occurs in this try block the except will be executed
my_guess = int(input("enter:")) # cast input to int and set to my_guess
if my_guess < 0 or my_guess > 9: # raise Value Error for ints out of range
raise ValueError # Raise Value Error
continue # go back to the top of the loop
except ValueError: # specify this except block is for ValueErrors
print("invalid input") # print invalid input
if(my_guess == num): # if you guessed correctly
print("great job") # print "great job"
num = random.randint(0, 9) # pick a new number
count_wins += 1 # increment counter
else: # if you guessed incorrectly
count_losses += 1 # increment counter
print(f"Wins: {count_wins}") # print wins
print(f"Losses: {count_losses}") # print losses
this is what I was looking for , in case someone else has a similar question
num = 3
my_guess = ""
while my_guess != num:
my_guess = int(input("enter:"))
print ("great job")
while num >=0:
print (num)
num = num -1

While loop not breaking even with the 'break' statement

I'm a beginner at python and programming in general so I've no idea what's wrong with my code. I'm trying to break out of the while loop but it's not working. Also, the fibonacci number code is not working as well. All the numbers between 1 to 1000 are interpreted as FIB numbers.
import collections
import threading
def main():
my_list = []
i = 0
time_second = int(input("Please input seconds\n"))
def sample():
threading.Timer(time_second, sample).start()
# Counts the frequency of number in a list
ctr = collections.Counter(my_list)
print(ctr)
sample()
first_number = int(input("Please enter the first number\n"))
my_list.append(first_number)
while True:
user_input = input("Enter number\n")
if user_input.isnumeric():
user_input = int(user_input)
# check for Fibonacci number
def fibonacci(n):
if n == 1:
return 1
if n == 2:
return 1
elif n > 2:
return fibonacci(n - 1) + fibonacci(n - 2)
if user_input in range(1, 1001):
print("FIB")
my_list.append(user_input)
if user_input == 'q':
print("Bye")
break
main()
Your function is in an odd place and I recommend you place it outside of the while loop.
There are a few ways to exit a loop. One of these ways is by satisfying a condition for the while loop to exit from.
import time
def in_loop(count):
print(f"Still in loop... on the {count} cycle")
def exited_the_loop():
print("Exited the loop")
count = 0
while count < 10:
time.sleep(.3)
count += 1
in_loop(count)
exited_the_loop()
Another way is to use python's break when a certain condition has been met within the loop. In this case I've used an if statement to check for this condition.
import time
def in_loop(count):
print(f"Still in loop... on the {count} cycle")
def exited_the_loop():
print("Exited the loop")
count = 0
while True:
time.sleep(.3)
count += 1
in_loop(count)
if count > 10:
break
exited_the_loop()

Why is python giving me an UnboundLocalError when I run this program?

Background
I am currently experimenting with computer learning, and I made a function where you enter "true" or "false" and the computer learns which boolean it is, after which the program prints the percent of correct guesses the computer made:
import math
import random
endgame = False
def oneround():
Q1max = 1
Q1min = -2
guess = False
answer = 0
while guess == False:
useranswer = input("True or False?")
if useranswer == "True" or useranswer == "true":
answer = True
guess = True
elif useranswer == "False" or useranswer == "false":
answer = False
guess = True
corrects = 0
incorrects = 0
howmanytimes = int(input("how many times do you want the computer to guess? (If you want to end the game, type in letters instead of a number.) "))
for x in range(0,howmanytimes):
choice = random.randint(Q1min,Q1max)
if choice >= 0:
guess = True
else:
guess = False
if guess == answer:
corrects += 1
if guess == True:
Q1max += 1
else:
Q1min -= 1
else:
incorrects += 1
if guess == False:
Q1max += 1
else:
Q1min -= 1
percent = (corrects/howmanytimes)*100
print ("The computer learned to guess correctly",(str(math.floor(percent))+"%"),"of the time.")
while endgame == False:
try:
oneround()
except ValueError:
endgame = True
I then tried to improve my program by adding 2 global variables, percentavg and percentavgnum, that will average all the success percentages together at the end of the program:
import math
import random
endgame = False
global percentavg
global percentavgnum
percentavg = 0
percentavgnum = 0
def oneround():
Q1max = 1
Q1min = -2
guess = False
answer = 0
while guess == False:
useranswer = input("True or False?")
if useranswer == "True" or useranswer == "true":
answer = True
guess = True
elif useranswer == "False" or useranswer == "false":
answer = False
guess = True
corrects = 0
incorrects = 0
howmanytimes = int(input("how many times do you want the computer to guess? (If you want to end the game, type in letters instead of a number.) "))
for x in range(0,howmanytimes):
choice = random.randint(Q1min,Q1max)
if choice >= 0:
guess = True
else:
guess = False
if guess == answer:
corrects += 1
if guess == True:
Q1max += 1
else:
Q1min -= 1
else:
incorrects += 1
if guess == False:
Q1max += 1
else:
Q1min -= 1
percent = (corrects/howmanytimes)*100
percentavg += percent
percentavgnum += 1
print ("The computer learned to guess correctly",(str(math.floor(percent))+"%"),"of the time.")
while endgame == False:
try:
oneround()
except ValueError:
endgame = True
print ("The computer guessed correctly",(str(math.floor(percentavg/percentavgnum))+"%"),"of the time")
Problem
But I keep getting this error whenever I run the program:
Traceback (most recent call last):
File "main.py", line 49, in <module>
oneround()
File "main.py", line 44, in oneround
percentavg += percent
UnboundLocalError: local variable 'percentavg' referenced before assignment
Does anyone know what I am doing wrong?
Use global. Put it at the top of the function with the variable names after it. Like this: global percentavg, percentavgnum
NOTE: The names must be comma-separated.
This problem is related to how Python determines the scope of a variable.
You can notice that the error occurs when you try to increment percentavg via percentavg += percent.
So you are trying to assign a new value to percentavg.
The thing is that in Python, when you assign a value to a variable, the variable becomes a local variable. But percentavg has not been defined in this scope (the scope of oneround(), and so you get this UnboundLocalError.
All of this is explained in details here:
https://docs.python.org/3/faq/programming.html#why-am-i-getting-an-unboundlocalerror-when-the-variable-has-a-value
You have at least 3 options:
Define the variables in oneround():
def oneround():
percentavg = 0
percentavgnum = 0
# ...
Pass your variables as arguments of oneround():
percentavg = 0
percentavgnum = 0
oneround(percentavg,percentavgnum)
And you don't need to declare your variables as global at all.
Access your outer scope variables uing global inside your function:
(That's what #Blue proposed)
def oneround():
global percentavg
global percentavgnum
The keywork global is used to access the outer scope variables (the variables declared outside the scope of the function).
If you choose option 1, you can delete these lines at the begining of your code:
global percentavg
global percentavgnum
percentavg = 0
percentavgnum = 0
If you choose option 2, you can delete these lines at the begining of your code:
global percentavg
global percentavgnum
but you will have to keep these lines:
percentavg = 0
percentavgnum = 0
These lines could be at the beginin of your code, but it coul be in the while loop, or in the try statement, before calling oneround().
But, based on your piece of code, the option 1 is the best coding practice.
Instead of using a global variable and relying on a side affect of the function, write your function to accept the module level variables that need to be updated as arguments and to return the updated values.
>>> def f(one,two,three):
... return one*1,two*2,three*3
...
>>> a,b,c = 'xyz'
>>> a,b,c = f(a,b,c)
>>> a
'x'
>>> b
'yy'
>>> c
'zzz'
>>>

Python: how to increment number and store in variable every time function runs

(I'm a beginner in Python, just so you know)
What I'm trying to do: I want to keep count of how many times a user choose a wrong option and if it exceeds a number of times, he fails.
My approach was to store the count in a variable within a function and check with if/else statement if the number of times is exceeded.
Part of the code:
choice = int(input("> "))
if choice == 1:
print("This is the wrong hall.")
increment()
elif choice == 2:
print("This is the wrong hall.")
increment()
elif choice == 3:
hall_passage()
else:
end("You failed")
COUNT = 0
def increment():
global COUNT
COUNT += 1
increment()
print(COUNT)
The increment part is from this thread and read using global scope is not a good practice.
The part I don't really understand is how you store count in a variable and it remembers the last value every time the function runs.
What is the best way to do this?
maybe something like this...
class Counter():
def __init__(self):
self.counter = 0
def increment(self):
self.counter += 1
def reset(self):
self.counter = 0
def get_value(self):
return self.counter
mc = Counter()
while mc.get_value() < 3:
v = int(input('a number: '))
if v == 1:
print('You won!')
mc.counter = 3
else:
print('Wrong guess, guess again...')
if mc.counter == 2:
print('Last guess...')
mc.increment()
Adapting this answer you could utilize the functions own __dict__. Note: if you didn't come across the # syntax yet search for "python", "decorator":
import functools as ft
def show_me(f):
#ft.wraps(f)
def wrapper(*args, **kwds):
return f(f, *args, **kwds)
return wrapper
#show_me
def f(me, x):
if x < 0:
try:
me.count += 1
except AttributeError:
me.count = 1
print(me.count, 'failures')
f(0)
f(-1)
f(1)
f(-2)
Output:
1 failures
2 failures
What do you think about this solution?
If you put here while loop you will forced on user to put correct answer.
Also i placed between if/elif/else statements input function.
count - That variable is counting wrong options
choice = int(input("> "))
count =0
while choice !=3:
if choice == 1:
print("This is the wrong hall.")
count += 1
choice = int(input("> ")) # Also i place in the if/elif/else statements input function
elif choice == 2:
print("This is the wrong hall.")
count +=1
choice = int(input("> "))
elif choice == 3:
hall_passage()
else:
end("You failed")
count += 1
choice = int(input("> "))
print(count)

Issue with Python Slot Machine

import random
balance = 50
def generator():
slot = 0
count = 0
gen = random.random()
while count < 3:
count = count + 1
if gen <= 0.01:
slot = 'Cherry'
elif gen <= 0.06:
slot = 'Diamond'
elif gen <= 0.16:
slot = 'Heart'
elif gen <= 0.36:
slot = 'Spade'
elif gen <= 0.66:
slot = 'Club'
elif gen <= 1:
slot = 'Monkey'
else:
break
return slot
def win(generator):
if generator() == 'Monkey' and generator() == 'Monkey' and generator() == 'Monkey':
balance = balance + 2122
print "Welcome to the International Slot Machine"
print ""
print "Balance: $",balance
print ''
spinyn = (raw_input("Would you like to spin? $5 per spin. Enter y or n:\n"))
while True:
if spinyn == "y":
break
elif spinyn == "n":
print "Final Balance: $",balance
print "Thank you for using the International Slot Machine"
raise SystemExit
else:
spinyn = raw_input('\033[31mPlease enter only y or n.\033[0m\n')
spin = (raw_input("Press enter to spin for $5:\n"))
while True:
if spin == '':
balance = balance - 5
if balance <= 0:
print ""
print "Final Balance: $",balance
print "You have run out of money, the game has now ended."
raise SystemExit
print ""
print "\033[34mResult:\033[0m"
print "\033[34m-------\033[0m"
print generator()
print generator()
print generator()
print ""
print "New balance:$",balance
print ""
spinagain = (raw_input("Would you like to spin again? Press enter to spin again, type anything to exit.\n"))
while True:
if spinagain == "":
break
else:
print "Final Balance: $",balance
print "Thank you for using the International Slot Machine"
raise SystemExit
else:
spin = (raw_input("Please press enter to spin.\n"))
I'm trying to make a very basic slot machine.
My question is: How do I make the generator function repeat 3 times and return 3 outputs, and then how do I make it recognise certain combinations?
Is this possible at all, keeping with my current format?
Also, how could I incorporate arrays into my code?
Thanks
Make the generator return a list or tuple of three values after generating three values, also it would be easier to use random.choice() rather than random.random() . random.choice() randomly selects a element for a list of values/iterable with equal probability for all elements. Example -
def generator():
ret = []
for _ in range(3):
ret.append(random.choice(['Cherry','Diamond','Heart','Spade','Club','Monkey']))
return tuple(ret)
If you want to have different probabilities for different elements, you can keep the current method, just loop over that three times and append to ret like done above and return ret from it.
Then in your win function, keep a dictionary such that the key is the tuple of combination and the value is the amount the user wins, then you can simply use .get() with a default value of 0 , to get how much the user won. Do not pass in generator as an argument. Example -
def win():
roll = generator()
d = {('Monkey','Monkey','Monkey'):21222,...}
return d.get(roll,0)
Then in your main loop, call this win() function to roll and see how much the user won.
Use the range function to choose 3 times and store it in a list.
import random
choices_list=[]
for ctr in range(3):
gen = random.choice(['Cherry', 'Diamond', 'Heart',
'Spade', 'Club', 'Monkey'])
choices_list.append(gen)
print choices_list

Categories