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.


; useful constants
make "false 1=0
make "true  1=1
make "lf char 10
make "sp char 32
 
; non-digits legal in expression
make "operators (lput sp [+ - * / \( \)])
 
; display help message
to show_help :digits
  type lf
  print sentence quoted [Using only these digits:] :digits 
  print sentence quoted [and these operators:] [* / + -]
  print quoted [\(and parentheses as needed\),]
  print quoted [enter an arithmetic expression 
     which evaluates to exactly 24.]
  type lf
  print quoted [Enter \"!\" to get fresh numbers.]
  print quoted [Enter \"q\" to quit.]
  type lf
end
 
make "digits []
make "done false
until [done] [
 
  if empty? digits [
    make "digits (map [(random 9) + 1] [1 2 3 4])
  ]
 
  (type "Solution sp "for sp digits "? sp )
  make "expression readrawline
 
  ifelse [expression = "?] [
 
    show_help digits
 
  ] [ifelse [expression = "q] [
 
    print "Bye!
    make "done true
 
  ] [ifelse [expression = "!] [
 
    make "digits []
 
  ] [
    make "exprchars ` expression
    make "allowed (sentence digits operators)
 
    ifelse (member? false (map [[c] member? c allowed] exprchars)) [
      (print quoted [Illegal character in input.])
    ] [
      catch "error [
        make "syntax_error true
        make "testval (run expression)
        make "syntax_error false
      ]
      ifelse syntax_error [
        (print quoted [Invalid expression.])
      ] [
        ifelse (testval = 24) [
          print quoted [You win!]
          make "done true
        ] [
          (print (sentence 
            quoted [Incorrect \(got ] testval quoted [instead of 24\).]))
        ]
      ]
    ]
  ]]]
] 
bye