I am unable to get the answer variable from the question function to check if the answer is indeed correct.
Following is what I have done so far:
import random
import operator
a = 0
ops = {
'+':operator.add,
'-':operator.sub
}
def generateQuestion():
x = random.randint(1, 10)
y = random.randint(1, 10)
op = random.choice(list(ops.keys()))
a = ops.get(op)(x,y)
print("What is {} {} {}?\n".format(x, op, y))
return a
def askQuestion():
guess = input("")
if guess == a:
print("Correct")
else:
print("Wrong, the answer is ", a)
generateQuestion()
askQuestion()
I cut out the in between stuff which is all working fine.
I'm aware I've set a = 0 at the top as well otherwise I got a was not defined error. However, I can't get the math from outside of the generateQuestion().
You can alleviate the need for the global by passing the answer value straight into askQuestion.
Don't forget to convert the return from input to an int, if you are running python 3. If using python 2 then you would not require the int conversion.
import random
import operator
ops = {
'+':operator.add,
'-':operator.sub
}
def generateQuestion():
x = random.randint(1, 10)
y = random.randint(1, 10)
op = random.choice(list(ops.keys()))
a = ops.get(op)(x,y)
print("What is {} {} {}?\n".format(x, op, y))
return a
def askQuestion(a):
guess = input("")
try:
if int(guess) == a:
print("Correct")
else:
print("Wrong, the answer is ", a)
except:
print('Did not input integer')
askQuestion(generateQuestion())
import random
import operator
ops = {
'+':operator.add,
'-':operator.sub
}
def generateQuestion():
x = random.randint(1, 10)
y = random.randint(1, 10)
op = random.choice(list(ops.keys()))
a = ops.get(op)(x,y)
print("What is {} {} {}?\n".format(x, op, y))
return a
def askQuestion(a):
guess = input("")
if guess == a:
print("Correct")
else:
print("Wrong, the answer is ", a)
variable = generateQuestion()
askQuestion(variable)
You have a scoping issue. Your variable a inside generateQuestion is not the same variable as a outside.
In order to fix this, you need to declare a as global inside generateQuestion.
import random
import operator
a = 0
ops = {
'+':operator.add,
'-':operator.sub
}
def generateQuestion():
x = random.randint(1, 10)
y = random.randint(1, 10)
op = random.choice(list(ops.keys()))
global a
a = ops.get(op)(x,y)
print("What is {} {} {}?\n".format(x, op, y))
return a
def askQuestion():
guess = input("")
if guess == a:
print("Correct")
else:
print("Wrong, the answer is ", a)
generateQuestion()
askQuestion()
Hav a look at this:
http://nbviewer.ipython.org/github/rasbt/python_reference/blob/master/tutorials/scope_resolution_legb_rule.ipynb
Related
I was making a class for logarithims of different bases and I noticed certain numbers like log(2) and log(4) were coming up as complex
class LogBaseN:
def __init__(self,base):
self.base = base
def __call__(self,x):
y,I = sp.symbols("y I")
self.x = x
if self.x == 1:
return 0
pass
if type(self.x) == int or type(self.x) == float:
ans = sp.solve(sp.Eq(self.base,self.x**(1/y)))[0]
try:
if int(ans) == float(ans):
return int(eval(str(ans)))
else:
return float(eval(str(ans)))
return ans
except:
return(eval(str(ans)))
if type(self.x) == list:
answers = []
for num in self.x:
i = num
if i == 1:
answers.append(0)
continue
ans = sp.solve(sp.Eq(self.base,i**(1/y)))[0]
try:
if int(ans) == float(ans):
answers.append(int(eval(str(ans))))
else:
answers.append(float(eval(str(ans))))
except:
answers.append(ans)
return answers
ln = LogBaseN(e)
log2 = LogBaseN(2)
Log = LogBaseN(10)
print(Log(4))
#Output log(2)/(3.14159265359*I + log(sqrt(10)))
I tried evaluating in by using str() then evaling using eval but that didnt fix it just to make it output I had to use sympy.symbols so the "I" would not cause an error
My code for now works as desired where the user can input a level 1-3 depending on how hard they would like it to be (1-3 being the amount of digits the numbers will have in the math equation), and then must solve math equations. Those math equations will output EEE if the answer is incorrect and everything works as planned if you correctly answer the question as it exits the function and adds one total_correct_answers variable at the bottom, then will prompt you with another equation. However, if you input an incorrect answer and then a correct answer, you will just be prompted with the same question over and over again without the try loop being truly broken out of and total_correct_answers not being incremented positively by 1. The incrementation block of code is at lines 61-65, and the equation code is lines 30-49.
import random
def main():
ten_questions()
def get_level():
while True:
try:
level_input = int(input("Level: "))
if level_input in [1,2,3]:
return level_input
except:
pass
def integer_generator(level):
if level == 1:
x = random.randint(0,9)
y = random.randint(0,9)
elif level == 2:
x = random.randint(10, 99)
y = random.randint(10, 99)
else:
x = random.randint(100, 999)
y = random.randint(100, 999)
return x, y
def question_generator(x, y):
real_answer = x + y
wrong_counter = 0
while True:
try:
answer_given = input(str(x) + " + " + str(y) + " = ")
if int(answer_given) == real_answer:
if wrong_counter == 0:
return True
elif int(answer_given) == real_answer and wrong_counter != 0:
break
else:
while wrong_counter < 2:
print("EEE")
wrong_counter +=1
break
else:
print(str(x) + " + " + str(y) + " = " + str(real_answer))
print("False, that was last attempt")
break
except:
print("EEE")
pass
def ten_questions():
num_of_questions = 0
total_correct_answers = 1
my_level = get_level()
correct_answers = question_generator(*integer_generator(my_level))
while num_of_questions <= 8:
question_generator(*integer_generator(my_level))
num_of_questions +=1
if correct_answers == True:
total_correct_answers +=1
print("Score: " + str(total_correct_answers))
if __name__ == "__main__":
main()
Because of your line 36:
if int(answer_given) == real_answer: happens when someone answers correctly, wether they are right or wrong. So it enters the if, and then faces if wrong_counter == 0: which discards wrong answers. So just replace those two lines with if int(answer_given) == real_answer and wrong_counter == 0: and you are good to go.
I'm relatively new to python and I'm looking for a way to make this code more efficient. Thank you!
import random
import string
import time
ques = []
anss = []
nums = string.digits
def que():
for i in range(10):
num0 = random.choice(nums)
num1 = random.choice(nums)
ans = num0 + '+' + num1
ques.append(ans)
ans = int(num0) + int(num1)
anss.append(ans)
global length
length = len(ques)
def main():
global counter
counter = 0
for i in range(10):
global answer
answer = int(input('What is ' + ques[i] + '?\n>>'))
if answer == anss[i]:
print('Correct!')
counter += 1
else:
print('Wrong!')
def score():
x = str((counter / length*100))
x = 'You got ' + x + '%'
return x
if __name__ == '__main__':
que()
main()
time.sleep(0.5)
print('Please wait while we calculate your score.')
time.sleep(1)
print(score())
Before, I tried just having the answers and questions in a single list - but after one loop it'd add one to the index something like this.
for i in range(10):
if answer == questions[i+1]:
print('correct')
i += 1 #This is meant to skip the answer part of the list and goto the next question but i couldnt get it to work.
Well... I just change your score method like
def score():
return 'You got ' + str((counter / length*100)) + '%'
In order to return the full string and avoid the x variable.
It is a little longer but what I think cleaner.
You can test each part without main.
main contains the algorithm.
from random import choice
from string import digits
def main() -> None:
score = 0
questions_limit = 10
for i in range(questions_limit):
first_operand = get_random_operand()
second_operand = get_random_operand()
expected_answer = first_operand + second_operand
question = get_question(first_operand, second_operand)
actual_answer = get_actual_answer(question)
correct = is_correct(expected_answer, actual_answer)
print_result(correct)
score = get_score(score, correct)
score_percentage = get_score_percentage(score, questions_limit)
print_score(score_percentage)
def get_random_operand() -> int:
return int(choice(digits))
def get_question(first_operand: int, second_operand: int) -> str:
return 'What is ' + str(first_operand) + ' + ' + str(second_operand) + ' ?\n>>'
def get_actual_answer(question: str) -> int:
return int(input(question))
def is_correct(expected_answer: int, actual_answer: int) -> bool:
return expected_answer == actual_answer
def print_result(correct: bool) -> None:
message = "Correct!" if correct else "Wrong!"
print(message)
def get_score(score: int, correct: bool) -> int:
if correct:
score +=1
return score
def get_score_percentage(score, questions_limit) -> str:
return str(score / questions_limit * 100)
def print_score(score: str) -> None:
print('You got ' + score + '%')
if __name__ == '__main__':
main()
If you were wanting to have the questions and answers in the same array then I would suggest doing something like:
for i in range(0,10,2):
if answer == questions[i+1]:
print("correct")
However the length of the array should be made to match having a question for each answer. The 2 at the end of range will mean the iterator(i) goes up by 2 each loop
It does not directly answer your question, but I'd suggest that you use the global keyword much less:
For answer you don't need it at all, because you use answer nowhere outside of main.
For length I would instead suggest you define length = 10 below nums at the top of your code and then replace all occurrences of 10 by length (which I would rather call n_questions).
That way you can easily change the number of questions with one single change of your code, and as you know that the loop in que will run up to length, there is no need to count length up.
Having counter global in main in okayish, although many would argue that it'd be better practice to return counter in main and define score to accept counter (better n_correct, for example) as argument like this (reusing Alfa Rojos answer):
def score(counter):
return 'You got ' + str((counter / length*100)) + '%'
I didn't completely rewrite it, but I would move everything to one loop, much cleaner for changes that way and have a counter that counts the number the user gets correct.
Here is a partial rewrite of your function que
def que():
for i in range(10):
num0,num1 = int(random.choice(nums)), int(random.choice(nums))
ans = num0 + num1
ques.append(ans)
anss.append(ans)
length = len(ques)
return length
I am working on creating an easygui/python calculator math program and i keep getting this error
Traceback (most recent call last):
File "C:\Python27\Scripts\MathHelper.py", line 83, in <module>
MathType()
TypeError: 'str' object is not callable
I can't figure out why it is happening. I believe it is with the global variable I try to call and change but i can't figure out how to stop the error. I know my code is kind of messy right now i am trying to work a proof of concept.
#MathType == what kind of math to compute. IE. Subtraction or addition
#Selection == Yes or no
math = 1
MathType = "Addition"
loop = 1
import easygui
def start():
print("startMessage")
MathType = easygui.msgbox(msg="Hello and welcome to my Math Helper.",
title = "Welcome")
startMessage = "0"
#End of start
#
#
#
def MathType():
global MathType
print("Math Type Gathered")
MathType = easygui.buttonbox("Select the type of Math you would like to compute:",
title = "Math Selection",
choices = ["Addition", "Subtraction", "Shut Down"] )
#End of MathType
#
#
#
def Addition():
num1 = easygui.enterbox(msg = "Please enter the first Number.",
title = "Addition")
#print(num1)
num2 = easygui.enterbox(msg = "Please enter the second number. "+num1+" + ___ = ___",
title = "Addition")
#print(num2)
easygui.msgbox("Here is your equation: "+num1+" + "+num2+" = ___ ",
title = "Equation")
NUM1 = int(num1)
NUM2 = int(num2)
numFinal = (NUM1 + NUM2)
NUM3 = str(numFinal)
easygui.msgbox(msg="Your answer is: "+NUM3+"",
title="Final")
#print(numFinal)
#End of Addition
#
#
def Subtraction():
num1 = easygui.enterbox(msg = "Please enter the first Number.",
title = "Subtraction")
#print(num1)
num2 = easygui.enterbox(msg = "Please enter the second number. "+num1+" - ___ = ___",
title = "Subtraction")
#print(num2)
easygui.msgbox("Here is your equation: "+num1+" - "+num2+" = ___ ",
title = "Equation")
NUM1 = int(num1)
NUM2 = int(num2)
numFinal = (NUM1 - NUM2)
NUM3 = numFinal
easygui.msgbox(msg="Your answer is: "+NUM3+"",
title="Final")
#print(numFinal)
#End of Subtraction
#
#
def MathFinder():
if MathType == "Addition":
print("Addition")
Addition()
elif MathType == "Subtraction":
print("Subtraction")
Subtraction()
elif MathType == "Shut Down":
exit()
start()
while loop == 1:
MathType()
MathFinder()
At line 4 you have MathType = "Addition"
At line 18 you have def MathType():
The error tells you that it can't call a string.
MathType() is actually MathType = "Addition" which is a string and not a function.
Please try to prevent using the same name for your functions, variables etc.
You have two types of 'MathType', one is a string and other is a function.
You have a function and a string variable named MathType.
class Factor:
def __init__(self, a, b, c):
self.a = a
self.b = b
self.c = c
def commonFactor(self):
global cfa
cfa = self.a
cfb = self.b
while cfb:
cfa, cfb = cfb, cfa % cfb
return cfa
def simplifyIntegers(self):
self.a = int(self.a / cfa)
self.b = int(self.b / cfa)
self.c = int(self.c / cfa)
return self.c
def coefficients(self):
if self.a == 1:
coe1 = 1
coe2 = 1
else:
coe1 = self.a
coe2 = 1
return self.coe1
def getFactors(self):
positivec = abs(self.c)
global result
result = set()
for i in range(1, int(positivec ** 0.5) + 1):
div, mod = divmod(positivec, i)
if mod == 0:
result |= {i, div}
return result
def numbers(self):
if self.c < 0:
poslist = [int(x) for x in result]
neglist = [-(x) for x in poslist]
numpos = poslist[0]
numneg = neglist[-1]
for i in poslist:
number = numpos + numneg
poslist.remove(numpos)
neglist.remove(numneg)
if number == self.b:
num1 = numpos
num2 = numneg
return num1
elif len(poslist) > 0:
numpos = poslist[0]
numneg = neglist[-1]
else:
print("This equation can not be fully factored.")
if self.c > 0:
poslist1 = [int(x) for x in result]
poslist2 = [int(x) for x in result]
neglist1 = [-(x) for x in poslist1]
neglist2 = [-(x) for x in poslist1]
numpos1 = poslist1[0]
numpos2 = poslist2[-1]
numneg1 = neglist1[0]
numneg2 = neglist2[-1]
for i in poslist1:
number = numpos1 + numpos2
poslist1.remove(numpos1)
poslist2.remove(numpos2)
if number == self.b:
num1 = numpos1
num2 = numpos2
return num1
elif len(poslist1) > 0:
numpos1 = poslist1[0]
numpos2 = poslist2[-1]
else:
print("This equation can not be factored.")
for i in neglist1:
number = numneg1 + numneg2
neglist1.remove(numneg1)
neglist2.remove(numneg2)
if number == self.b:
num1 = numneg1
num2 = numneg2
return num1
elif len(neglist1) > 0:
numpos1 = neglist1[0]
numpos2 = neglist2[-1]
else:
print("This equation can not be factored.")
def factoredForm(self):
cfa = str(cfa)
coe1 = str(coe1)
num1 = str(num1)
coe2 = str(coe2)
num2 = str(num2)
equation = (cfa,"(",coe1,"x + ",num1,")(",coe2,"x + ",num2,")")
return equation
a = input("What is A?")
a = int(a)
b = input("What is B?")
b = int(b)
c = input("What is C?")
c = int(c)
e = Factor(a,b,c)
print(e.factoredForm())
I keep getting this error-
UnboundLocalError: local variable 'cfa' referenced before assignment
I have looked at quite a bit of things talking about how to fix it, but none of those seemed to have offered something to fix this. I have making the variables global, but that still doesn't work and anything else didn't work any better. This is my program I made to factor quadratics if you need to know what it is doing. Thanks to anyone that can help.
Here it looks like you are trying to create a local cfa which is a str version of the global cfa.
def factoredForm(self):
cfa = str(cfa)
You can't mix both types of access in the same scope. You should use a different name for the local variable.
Alternatively you could write the function like this
def factoredForm(self):
return map(str, (cfa, "(", coe1, "x + " ,num1, ")(", coe2, "x + " ,num2 ,")"))
These statements:
cfa = str(cfa)
coe1 = str(coe1)
num1 = str(num1)
coe2 = str(coe2)
num2 = str(num2)
suggest that you want all of these variables as instance variables (not globals). I think you have find each use and change the way you access them.