The 24 Game tests one's mental arithmetic.



Task
Write a program that randomly chooses and displays four digits, each from 1 ──► 9 (inclusive) with repetitions allowed.

The program should prompt for the player to enter an arithmetic expression using just those, and all of those four digits, used exactly once each. The program should check then evaluate the expression.

The goal is for the player to enter an expression that (numerically) evaluates to 24.

 Only the following operators/functions are allowed: multiplication, division, addition, subtraction
 Division should use floating point or rational arithmetic, etc, to preserve remainders.
 Brackets are allowed, if using an infix expression evaluator.
 Forming multiple digit numbers from the supplied digits is disallowed. (So an answer of 12+12 when given 1, 2, 2, and 1 is wrong).
 The order of the digits when given does not have to be preserved.


Notes
 The type of expression evaluator used is not mandated. An RPN evaluator is equally acceptable for example.
 The task is not for the program to generate the expression, or test whether an expression is even possible.


Related tasks
 24 game/Solve


Reference
 The 24 Game on h2g2.


evalAddSub = function()
    result = evalMultDiv
    while true
        if not tokens then return result
        op = tokens[0]
        if op != "+" and op != "-" then return result
        tokens.pull  // (discard operator)
        rhs = evalMultDiv
        if result == null or rhs == null then return null
        if op == "+" then result = result + rhs
        if op == "-" then result = result - rhs
    end while
end function
 
evalMultDiv = function()
    result = evalAtom
    while true
        if not tokens then return result
        op = tokens[0]
        if op != "*" and op != "/" then return result
        tokens.pull  // (discard operator)
        rhs = evalAtom
        if result == null or rhs == null then return null
        if op == "*" then result = result * rhs
        if op == "/" then result = result / rhs
    end while
end function
 
evalAtom = function()
    if tokens[0] == "(" then
        tokens.pull
        result = evalAddSub
        if not tokens or tokens.pull != ")" then
            print "Unbalanced parantheses"
            return null
        end if
        return result
    end if
    num = val(tokens.pull)
    idx = availableDigits.indexOf(num)
    if idx == null then
        print str(num) + " is not available"
        return null
    else
        availableDigits.remove idx
    end if
    return num
end function
 
choices = []
for i in range(1, 4)
    choices.push ceil(rnd*9)
end for
result = null
while result != 24
    availableDigits = choices[0:]  // (clones the list)
    print "Using only the digits " + availableDigits + ","
    tokens = input("enter an expression that comes to 24: ").replace(" ","").values
    result = evalAddSub
    if availableDigits then
        print "You forgot to use: " + availableDigits
        result = null
    end if
    if result != null then print "That equals " + result + "."
end while
print "Great job!"