Creating code which generates random mathematical problem for user to solve. Can't figure out the algorithm for calculating correct answer

Just learned a bit of phyton language. While having fun with phyton I got stuck on algorithm problem. Couldn’t figure out how to make mathematical notations, stored in array as strings, as real mathematical processes (adding, subtracting, etc.) Also, mathematical notations should follow the order of operations as in math (multiplication/division, addition/subtraction). Could somebody try to write an algorithm in section (NOT FINISHED!) without changing overall code. Variable problem_solved should have the answer for the generated problem. Would be very greatful. Maybe this site has brilliant minds.

If it’s not possible due to a fact how this code is written, let me know :). I’m eager to learn.

Codes purpose: generates random mathematical problem for user to solve.

from random import randint

#constants
opperators = ["+","-","*","/"]

#variable for program to continue
user_proceed = True

#asking user for the maximum amount of numbers
val = False
while val == False:
    try:
        count_max = int(input("Maximum amount of numbers: "))
        if(count_max < 2):
            print("Has to be greater than 1. ", end = '')
        else:
            #limits user's ability to pick infinite amount of numbers
            if(count_max > 20):
                print("Hold your horses. Pick something a bit easier. ", end = '')
            else:
                val = True
    except ValueError:
        print("That's not a valid number! ", end = '')

#program will repeat if procced will be true
while user_proceed == True:

    #generating the count of numbers and opperators
    count_num = randint(2,count_max)
    count_opp = count_num - 1

    #creating arrays for numbers and opperators
    num = [None] * count_num
    opp = [None] * count_opp

    #generating random numbers for problem
    i = -1
    for x in num:
        i = i+1
        if x == None:
            num[i] = randint(1,20) 
        #print(numbers[i]) #for testing purpose

    #generating problem for user to solve
    problem_str = ""
    i = -1
    for x in num:
        i = i+1
        if i == count_opp:
            problem_str = problem_str + str(num[i])
        else:
            opp[i] = opperators[randint(0,3)]
            problem_str = problem_str + str(num[i]) + opp[i]
            #print(opp[i]) #for testing purpose
        #print(problem_str) #for testing purpose


    #calculating solution to the problem (NOT FINISHED!)
    problem_solved = 0

    #asking user for his solution
    print(f"Solve this problem: {problem_str}")
    val = False
    while val == False:
        try:
            user_solution = float(input("Answer: "))
            val = True
        except ValueError:
            print("That's not a valid number! ", end = '')

    #checking if user got the right answer
    if user_solution == problem_solved:
        print("Correct!")
    else:
        print(f"Wrong! The answer is {problem_solved}")

    #asking user to try again
    print("Try again? ", end='')
    val = False
    while val == False:
        user_answer = input("Yes/No: ")
        if(user_answer != "Yes" and user_answer != "No"):
            print("I don't understand. ", end = '')
        else:
            val = True
            if user_answer == "Yes":
                user_proceed = True
            else:
                user_proceed = False

>Solution :

First of all, you did not clarify why the without changing overall code. Variable problem_solved should have the answer for the generated problem rule exists. Are you doing some algorithm problem on some site? Or just created your own problem for fun? If so, why don’t you want to change the part of your code?

Secondly, there are two answers for your problem. First one is simple but not a very safe option in the long run. Python has an exec function that executes a string as code. So you can just do-

exec(f"problem_solved = {problem_str}")

but it is fundamentally a bad idea because you might want to add some imaginary operation or maybe change how operators are represented in Python (^ instead of ** for example). In that case exec will no longer work.

Harder way, change the problem to postfix/prefix notation so that the priority of operations are resolved (more helpful if you use parenthesis in your expression). Then calculate them. And if you use functional breakdowns to create your program, you would not need to change your existing code much.

...
...
problem_solved = solved(problem_str)
...
...

def solved(problem_str):
    postfix = to_postfix(problem_str)
    ...

def to_postfix(problem_str):
    ...

You can look at Shunting-Yard algorithm for changing infix to postfix. And this stack page has kinda good discussion on how to calculate postfix notation using Python.

Edit: Fixed exec function usage

Leave a Reply