invocable all link strings # for csort, deletec procedure main() help() repeat { every (n := "") ||:= (1 to 4, string(1+?8)) writes("Your four digits are : ") every writes(!n," ") write() e := trim(read()) | fail case e of { "q"|"quit": return "?"|"help": help() default: { e := deletec(e,' \t') # no whitespace d := deletec(e,~&digits) # just digits if csort(n) ~== csort(d) then # and only the 4 given digits write("Invalid repsonse.") & next if e ? (ans := eval(E()), pos(0)) then # parse and evaluate if ans = 24 then write("Congratulations you win!") else write("Your answer was ",ans,". Try again.") else write("Invalid expression.") } } } end procedure eval(X) #: return the evaluated AST if type(X) == "list" then { x := eval(get(X)) while x := get(X)(real(x), real(eval(get(X) | stop("Malformed expression.")))) } return \x | X end procedure E() #: expression put(lex := [],T()) while put(lex,tab(any('+-*/'))) do put(lex,T()) suspend if *lex = 1 then lex[1] else lex # strip useless [] end procedure T() #: Term suspend 2(="(", E(), =")") | # parenthesized subexpression, or ... tab(any(&digits)) # just a value end procedure help() return write( "Welcome to 24\n\n", "Combine the 4 given digits to make 24 using only + - * / and ( ).\n ", "All operations have equal precedence and are evaluated left to right.\n", "Combining (concatenating) digits is not allowed.\n", "Enter 'help', 'quit', or an expression.\n") end