90 lines
2.9 KiB
Text
90 lines
2.9 KiB
Text
type expression =
|
|
| Const of float
|
|
| Sum of expression * expression (* e1 + e2 *)
|
|
| Diff of expression * expression (* e1 - e2 *)
|
|
| Prod of expression * expression (* e1 * e2 *)
|
|
| Quot of expression * expression (* e1 / e2 *)
|
|
|
|
let rec eval = function
|
|
| Const c -> c
|
|
| Sum (f, g) -> eval f +. eval g
|
|
| Diff(f, g) -> eval f -. eval g
|
|
| Prod(f, g) -> eval f *. eval g
|
|
| Quot(f, g) -> eval f /. eval g
|
|
|
|
let rec extract acc = function
|
|
| Const c -> (c::acc)
|
|
| Sum (f, g) -> (extract acc f) @ (extract [] g)
|
|
| Diff(f, g) -> (extract acc f) @ (extract [] g)
|
|
| Prod(f, g) -> (extract acc f) @ (extract [] g)
|
|
| Quot(f, g) -> (extract acc f) @ (extract [] g)
|
|
|
|
open Genlex
|
|
|
|
let lexer = make_lexer ["("; ")"; "+"; "-"; "*"; "/"]
|
|
|
|
let rec parse_expr = parser
|
|
[< e1 = parse_mult; e = parse_more_adds e1 >] -> e
|
|
and parse_more_adds e1 = parser
|
|
[< 'Kwd "+"; e2 = parse_mult; e = parse_more_adds (Sum(e1, e2)) >] -> e
|
|
| [< 'Kwd "-"; e2 = parse_mult; e = parse_more_adds (Diff(e1, e2)) >] -> e
|
|
| [< >] -> e1
|
|
and parse_mult = parser
|
|
[< e1 = parse_simple; e = parse_more_mults e1 >] -> e
|
|
and parse_more_mults e1 = parser
|
|
[< 'Kwd "*"; e2 = parse_simple; e = parse_more_mults (Prod(e1, e2)) >] -> e
|
|
| [< 'Kwd "/"; e2 = parse_simple; e = parse_more_mults (Quot(e1, e2)) >] -> e
|
|
| [< >] -> e1
|
|
and parse_simple = parser
|
|
| [< 'Int i >] -> Const(float i)
|
|
| [< 'Float f >] -> Const f
|
|
| [< 'Kwd "("; e = parse_expr; 'Kwd ")" >] -> e
|
|
|
|
|
|
let parse_expression = parser [< e = parse_expr; _ = Stream.empty >] -> e
|
|
|
|
let read_expression s = parse_expression(lexer(Stream.of_string s))
|
|
|
|
|
|
let () =
|
|
Random.self_init();
|
|
print_endline "
|
|
The 24 Game
|
|
|
|
Given any four digits in the range 1 to 9, which may have repetitions,
|
|
Using just the +, -, *, and / operators; and the possible use of
|
|
brackets, (), show how to make an answer of 24.
|
|
|
|
An answer of 'q' will quit the game.
|
|
An answer of '!' will generate a new set of four digits.
|
|
Otherwise you are repeatedly asked for an expression until it evaluates to 24
|
|
|
|
Note: you cannot form multiple digit numbers from the supplied digits,
|
|
so an answer of 12+12 when given 1, 2, 2, and 1 would not be allowed.\n";
|
|
|
|
let sort = List.sort compare in
|
|
let digits = ref [] in
|
|
let digit_set () =
|
|
let ar = Array.init 4 (fun _ -> 1 + Random.int 9) in
|
|
digits := Array.to_list(Array.map float_of_int ar);
|
|
print_string "The four digits: ";
|
|
List.iter (Printf.printf " %g") !digits;
|
|
print_newline();
|
|
in
|
|
|
|
digit_set();
|
|
while true do
|
|
print_string "Expression: ";
|
|
let str = read_line() in
|
|
if str = "q" then exit 0;
|
|
if str = "!" then digit_set()
|
|
else begin
|
|
let expr = read_expression str in
|
|
let res = eval expr in
|
|
Printf.printf " = %g\n%!" res;
|
|
if res = 24.
|
|
&& (sort !digits) = (sort (extract [] expr))
|
|
then (print_endline "Congratulations!"; digit_set())
|
|
else print_endline "Try again"
|
|
end
|
|
done
|