open Graphics ;; Random.self_init () ;; (* Dynamic getchar function *) let get1char () = let termio = Unix.tcgetattr Unix.stdin in let () = Unix.tcsetattr Unix.stdin Unix.TCSADRAIN { termio with Unix.c_icanon = false } in let res = input_char stdin in Unix.tcsetattr Unix.stdin Unix.TCSADRAIN termio; res (* Some digit display functions *) let rec ln10 n = match n with | k when k < 0 -> failwith "Are you sure about that ?" | k when k < 10 -> 0 | k -> 1 + ln10 (k/10) ;; let delta i j = if i = j then 1 else 0 ;; let abs n = if n > 0 then n else -n ;; let draw_integer x0 y n0 len = (* 7-seg display *) set_line_width (max 1 (len/4)); let n = ref n0 in let size = ln10 (abs n0) in let offset = ref (size*(len*11/7)/2) in let initial_i = ref 1 in if !n < 0 then begin offset := (size+1)*(len*11/7)/2; let x = x0 + !offset - (size+1)*(len*11/7) in draw_poly_line [|(x-len/2, y); (x+len/2, y)|]; n := !n * (-1); decr initial_i ; end; for i = !initial_i to (size + !initial_i) do let x = x0 + !offset - i*(len*11/7) in if Array.mem (!n mod 10) [|0; 4; 5; 6; 7; 8; 9|] then draw_poly_line [|(x-len/2, y+len); (x-len/2, y)|]; if Array.mem (!n mod 10) [|0; 2; 3; 5; 6; 7; 8; 9|] then draw_poly_line [|(x-len/2, y+len); (x+len/2, y+len)|]; if Array.mem (!n mod 10) [|0; 1; 2; 3; 4; 7; 8; 9|] then draw_poly_line [|(x+len/2, y+len); (x+len/2, y)|]; if Array.mem (!n mod 10) [|2; 3; 4; 5; 6; 8; 9|] then draw_poly_line [|(x-len/2, y); (x+len/2, y)|]; if Array.mem (!n mod 10) [|0; 1; 3; 4; 5; 6; 7; 8; 9|] then draw_poly_line [|(x+len/2, y-len); (x+len/2, y)|]; if Array.mem (!n mod 10) [|0; 2; 3; 5; 6; 8; 9|] then draw_poly_line [|(x-len/2, y-len); (x+len/2, y-len)|]; if Array.mem (!n mod 10) [|0; 2; 6; 8|] then draw_poly_line [|(x-len/2, y-len); (x-len/2, y)|]; n := !n/10; done ;; let draw_integer_alignedleft x0 y n0 len = (* 7-seg display 2 *) set_line_width (max 1 (len/4)); let n = ref n0 in let size = ln10 (abs n0) in let cur_x = ref (x0 + size*(len*11/7)) in if !n < 0 then begin n := !n * (-1); draw_poly_line [|(x0, y); (x0+len, y)|]; cur_x := !cur_x + (len*11/7) end; for i = 0 to size do let x = !cur_x in if Array.mem (!n mod 10) [|0; 4; 5; 6; 7; 8; 9|] then draw_poly_line [|(x, y+len); (x, y)|]; if Array.mem (!n mod 10) [|0; 2; 3; 5; 6; 7; 8; 9|] then draw_poly_line [|(x, y+len); (x+len, y+len)|]; if Array.mem (!n mod 10) [|0; 1; 2; 3; 4; 7; 8; 9|] then draw_poly_line [|(x+len, y+len); (x+len, y)|]; if Array.mem (!n mod 10) [|2; 3; 4; 5; 6; 8; 9|] then draw_poly_line [|(x, y); (x+len, y)|]; if Array.mem (!n mod 10) [|0; 1; 3; 4; 5; 6; 7; 8; 9|] then draw_poly_line [|(x+len, y-len); (x+len, y)|]; if Array.mem (!n mod 10) [|0; 2; 3; 5; 6; 8; 9|] then draw_poly_line [|(x, y-len); (x+len, y-len)|]; if Array.mem (!n mod 10) [|0; 2; 6; 8|] then draw_poly_line [|(x, y-len); (x, y)|]; n := !n/10; cur_x := !cur_x - (len*11/7); done ;; let decode_letter x y len arr = set_line_width 3; if arr.(0) = 1 then draw_poly_line [|(x, y+len); (x, y)|]; if arr.(1) = 1 then draw_poly_line [|(x, y-len); (x, y)|]; if arr.(2) = 1 then draw_poly_line [|(x, y+len); (x+len, y+len)|]; if arr.(3) = 1 then draw_poly_line [|(x, y+len); (x+len, y)|]; if arr.(4) = 1 then draw_poly_line [|(x, y); (x+len, y+len)|]; if arr.(5) = 1 then draw_poly_line [|(x, y); (x+len, y)|]; if arr.(6) = 1 then draw_poly_line [|(x, y); (x+len, y-len)|]; if arr.(7) = 1 then draw_poly_line [|(x, y-len); (x+len, y)|]; if arr.(8) = 1 then draw_poly_line [|(x+len, y-len); (x, y-len)|]; if arr.(9) = 1 then draw_poly_line [|(x+len, y+len); (x+len, y)|]; if arr.(10) = 1 then draw_poly_line [|(x+len, y-len); (x+len, y)|];; let draw_letter x y c len = match c with |'a'|'A' -> decode_letter x y len [|1; 1; 1; 0; 0; 1; 0; 0; 0; 1; 1|] |'b'|'B' -> decode_letter x y len [|1; 1; 0; 0; 0; 1; 0; 0; 1; 0; 1|] |'c'|'C' -> decode_letter x y len [|1; 1; 1; 0; 0; 0; 0; 0; 1; 0; 0|] |'d'|'D' -> decode_letter x y len [|0; 0; 1; 0; 0; 0; 0; 0; 1; 1; 1|]; draw_poly_line [|(x+len/2, y+len); (x+len/2, y-len)|] |'e'|'E' -> decode_letter x y len [|1; 1; 1; 0; 0; 1; 0; 0; 1; 0; 0|] |'f'|'F' -> decode_letter x y len [|1; 1; 1; 0; 0; 1; 0; 0; 0; 0; 0|] |'g'|'G' -> decode_letter x y len [|1; 1; 1; 0; 0; 0; 0; 0; 1; 0; 1|] |'h'|'H' -> decode_letter x y len [|1; 1; 0; 0; 0; 1; 0; 0; 0; 1; 1|] |'i'|'I' -> draw_poly_line [|(x+len/2, y+len); (x+len/2, y-len)|]; |'j'|'J' -> decode_letter x y len [|0; 1; 0; 0; 0; 0; 0; 0; 1; 1; 1|] |'k'|'K' -> decode_letter x y len [|1; 1; 0; 0; 1; 0; 1; 0; 0; 0; 0|] |'l'|'L' -> decode_letter x y len [|1; 1; 0; 0; 0; 0; 0; 0; 1; 0; 0|] |'m'|'M' -> decode_letter x y len [|1; 1; 0; 0; 0; 0; 0; 0; 0; 1; 1|]; draw_poly_line [|(x, y+len); (x+len/2, y)|]; draw_poly_line [|(x+len/2, y); (x+len, y+len)|] |'n'|'N' -> decode_letter x y len [|1; 1; 0; 1; 0; 0; 0; 0; 0; 1; 1|] |'o'|'O' -> decode_letter x y len [|1; 1; 1; 0; 0; 0; 0; 0; 1; 1; 1|] |'p'|'P' -> decode_letter x y len [|1; 1; 1; 0; 0; 1; 0; 0; 0; 1; 0|] |'q'|'Q' -> decode_letter x y len [|1; 0; 1; 0; 0; 1; 0; 0; 0; 1; 1|] |'r'|'R' -> decode_letter x y len [|1; 1; 1; 0; 0; 1; 1; 0; 0; 1; 0|] |'s'|'S' -> decode_letter x y len [|1; 0; 1; 0; 0; 1; 0; 0; 1; 0; 1|] |'t'|'T' -> decode_letter x y len [|1; 1; 0; 0; 0; 1; 0; 0; 1; 0; 0|] |'u'|'U' -> decode_letter x y len [|1; 1; 0; 0; 0; 0; 0; 0; 1; 1; 1|] |'v'|'V' -> decode_letter x y len [|1; 1; 0; 0; 0; 0; 0; 1; 0; 1; 0|] |'w'|'W' -> decode_letter x y len [|1; 1; 0; 0; 0; 0; 1; 1; 0; 1; 1|] |'x'|'X' -> draw_poly_line [|(x, y+len); (x+len, y-len)|]; draw_poly_line [|(x, y-len); (x+len, y+len)|] |'y'|'Y' -> decode_letter x y len [|1; 0; 0; 0; 0; 1; 0; 1; 0; 1; 0|] |'z'|'Z' -> decode_letter x y len [|0; 1; 1; 0; 1; 0; 0; 0; 1; 0; 0|] | _ -> () ;; let draw_string x0 y s len = let cur_x = ref x0 in for i = 0 to String.length s -1 do draw_letter !cur_x y s.[i] len; cur_x := !cur_x + (len*10/7) done;; (* Arithmetical functions *) type calcul = Val of int | Plus of calcul * calcul | Minus of calcul * calcul | Exp of calcul * int | (* u^n *) Multiply of calcul * calcul ;; let print_sign c x y len = match c with | '+' -> draw_poly_line [|(x, y); (x+len, y)|]; draw_poly_line [|(x+len/2, y+len/2); (x+len/2, y-len/2)|] | '-' -> draw_poly_line [|(x, y); (x+len, y)|] | '*' -> draw_poly_line [|(x+len/4, y+len/2); (x+3*len/4, y-len/2)|]; draw_poly_line [|(x+len/4, y-len/2); (x+3*len/4, y+len/2)|] | '^' -> () (* TODO *) | '(' -> moveto (x+len) (y+len+len/5); set_line_width (max 1 (len/4)); set_color black ; curveto (x+len/2, y) (x+len/2, y) (x+len, y-len-len/5) | ')' -> moveto (x) (y+len+len/5); set_line_width (max 1 (len/4)); set_color black ; curveto (x+len/2, y) (x+len/2, y) (x, y-len-len/5) | _ -> () ;; let print_math fm x0 y0 size = let current_x = ref x0 in let current_y = ref y0 in let rec aux f = match f with | Val x -> current_x := !current_x + size/3; draw_integer_alignedleft (!current_x) !current_y x size; current_x := !current_x + (size*(2 + ln10 (abs x))); current_x := !current_x + size/3 | Plus (a, b) -> aux a; print_sign '+' !current_x !current_y size; current_x := !current_x + size*11/7; aux b | Minus (a, b) -> aux a; print_sign '-' !current_x !current_y size; current_x := !current_x + size*11/7; aux b | Multiply (a, b) -> aux a; print_sign '*' !current_x !current_y size; current_x := !current_x + size*11/7; aux b | Exp (a, n) -> () in aux fm ;; let generate_tier_1 length inf sup = let rec aux n = match (Random.int 2) with | 0 -> begin match n with | 0 -> Val (1 + Random.int (sup-inf) + inf) | 1 -> Val (1 + Random.int (sup-inf) + inf) | k -> Plus (aux (k-1), Val (1 + Random.int (sup-inf) + inf)) end | 1 -> begin match n with | 0 -> Val (1 + Random.int (sup-inf) + inf) | 1 -> Val (1 + Random.int (sup-inf) + inf) | k -> Minus (aux (k-1), Val (1 + Random.int (sup-inf) + inf)) end | _ -> failwith "Never happen" in aux length ;; let generate_tier_2 length inf sup mreduction = let rec aux n = match (Random.int 3) with | 0 -> begin match n with | 0 -> Val (1 + Random.int (sup-inf) + inf) | 1 -> Val (1 + Random.int (sup-inf) + inf) | k -> Plus (aux (k-1), Val (1 + Random.int (sup-inf) + inf)) end | 1 -> begin match n with | 0 -> Val (1 + Random.int (sup-inf) + inf) | 1 -> Val (1 + Random.int (sup-inf) + inf) | k -> Minus (aux (k-1), Val (1 + Random.int (sup-inf) + inf)) end | 2 -> begin match n with | 0 -> Val (1 + Random.int (sup-inf) + inf) | 1 -> Val (1 + Random.int (sup-inf) + inf) | k -> Plus (Multiply (Val ((1 + Random.int (sup-inf) + inf)/mreduction), Val ((1 + Random.int (sup-inf) + inf)/mreduction)), aux (k-2)) end | _ -> failwith "Never happen" in aux length ;; let rec pw x n = match n with | 0 -> 1 | 1 -> x | k when k mod 2 = 0 -> let res = pw x (n/2) in res*res | k -> let res = pw x (n/2) in res*res*x ;; (* Boi *) let rec eval_exp fm = match fm with | Plus (a, b) -> Plus (eval_exp a, eval_exp b) | Minus (a, b) -> Minus (eval_exp a, eval_exp b) | Multiply (a, b) -> Multiply (eval_exp a, eval_exp b) | Val x -> Val x | Exp (a, n) -> Val (pw (evaluate a) n) and eval_mult fm = match fm with | Plus (a, b) -> Plus (eval_mult a, eval_mult b) | Minus (a, b) -> Minus (eval_mult a, eval_mult b) | Val x -> Val x | Exp (a, n) -> Exp(eval_mult a, n) | Multiply (a, b) -> Val ((evaluate a) * (evaluate b)) and eval_plus fm = match fm with | Val x -> x | Plus (a, b) -> (evaluate a) + (evaluate b) | Minus (a, b) -> (evaluate a) - (evaluate b) | Exp (a, n) -> failwith "_Impossible" | Multiply (a, b) -> failwith "Impossible_" and evaluate fm = eval_plus (eval_mult (eval_exp fm)) ;; (* Game config *) exception Exit ;; let update_char_settings code buf pointer ndiff = match code with | k when k >= 48 && k <= 57 -> (* Integer *) if !buf >= 0 then begin buf := !buf * 10; buf := !buf + code - 48; end else begin buf := !buf * (-1); buf := !buf * 10; buf := !buf + code - 48; buf := !buf * (-1); end; true | 10 -> raise Exit | 115 -> (* s *) set_color white; fill_circle 20 (800 - !pointer * 90) 10; pointer := (!pointer + 1) mod ndiff; set_color (rgb 32 192 32); fill_circle 20 (800 - !pointer * 90) 10; false | 122 -> (* z *) set_color white; fill_circle 20 (800 - !pointer * 90) 10; decr pointer; if !pointer < 0 then pointer := ndiff -1; set_color (rgb 32 192 32); fill_circle 20 (800 - !pointer * 90) 10; false | 127 -> (* Delete *) if !buf >= 0 then begin buf := !buf / 10 end else begin buf := !buf * (-1); buf := !buf / 10; buf := !buf * (-1); end; true | _ -> false ;; type game_setting = {mutable inf : int; mutable sup : int; mutable diff : int; mutable count : int} ;; type modifiers = {mutable brackets : bool; mutable timed : bool} ;; let settings_menu () = open_graph " 1000x1000"; set_window_title "Math"; let setting = {inf = 1 ; sup = 100 ; diff = 1; count = 8} in let ft = ref true in try Stdlib.print_endline "-------------------------"; let ptr = ref 0 in let buffer = ref 0 in while true do let c = get1char () in let code = Char.code c in if !ft || update_char_settings code buffer ptr 4 then begin ft := false; if !ptr = 0 then setting.inf <- !buffer else if !ptr = 1 then setting.sup <- !buffer else if !ptr = 2 then setting.diff <- !buffer else if !ptr = 3 then setting.count <- !buffer; open_graph " 1000x1000"; set_window_title "Math"; set_color (rgb 32 192 32); fill_circle 20 (800 - !ptr * 90) 10; set_color black; (*draw_string 10 950 "abcdefghijklmnopqrstuvwxyz" 20; *) draw_string 40 800 "min value" 20; draw_integer_alignedleft 400 800 setting.inf 20; draw_string 40 710 "max value" 20; draw_integer_alignedleft 400 710 setting.sup 20; draw_string 40 620 "difficulty" 20; draw_integer_alignedleft 400 620 setting.diff 20; draw_string 40 530 "num count" 20; draw_integer_alignedleft 400 530 setting.count 20; end; set_color black; done; failwith "Not possible" with | Exit -> setting ;; (* Core functions *) (* Main *) let update_char_main code buf = match code with | k when k >= 48 && k <= 57 -> (* Integer *) if !buf >= 0 then begin buf := !buf * 10; buf := !buf + code - 48; end else begin buf := !buf * (-1); buf := !buf * 10; buf := !buf + code - 48; buf := !buf * (-1); end; true | 45 -> (* Minus sign *) buf := !buf * (-1); true | 127 -> (* Delete *) if !buf >= 0 then begin buf := !buf / 10 end else begin buf := !buf * (-1); buf := !buf / 10; buf := !buf * (-1); end; true | _ -> false ;; let main stng = open_graph " 1000x1000"; set_window_title "Math"; let buffer = ref 0 in let ft = ref true in try let math = ref (generate_tier_2 stng.count stng.inf stng.sup 5) in let answer = ref (evaluate !math) in let clock = ref 0 in let frames = ref 0 in while true do let ch = get1char () in let chint = Char.code ch in if !ft || update_char_main chint buffer then begin ft := false; open_graph " 1000x1000"; set_window_title "Math"; if !answer = !buffer then begin math := (generate_tier_2 6 1 100 5); answer := evaluate !math; buffer := 0; end; print_math !math 10 900 15; draw_integer_alignedleft 10 800 !answer 15; draw_integer_alignedleft 10 300 !buffer 20; end; Unix.sleepf 0.025; incr frames; if !frames >= 40 then begin Stdlib.print_endline "EEE"; frames := 0; incr clock; set_color white; draw_poly_line [|(0, 0); (1000, 0); (1000, 60); (0, 60)|]; set_color black; draw_integer 500 30 !clock 30; end; done; with | exn -> close_graph (); raise exn ;; let setting = settings_menu () ;; main setting ;; (* ocamlfind ocamlc -linkpkg -package unix -linkpkg -package graphics main.ml *)