open Graphics ;; Random.self_init () ;; exception Reset ;; type operation = Val of int | Sum of operation * operation | Diff of operation * operation | Prod of operation * operation | Exp of operation * int ;; let rec calculate = function | Val k -> k | Exp (op, k) -> Math.pw (calculate op) k | Sum (f, g) -> (calculate f) + (calculate g) | Diff (f, g) -> (calculate f) - (calculate g) | Prod (f, g) -> (calculate f) * (calculate g) ;; let generate_random_calc ?plus_w:(pw=10) ?minus_w:(mw=8) ?prod_w:(uw=2) ?exp_w:(ew=0) (length : int) (inf : int) (sup : int) = let sum = pw + mw + uw + ew in let rec aux = function | 0 | 1 -> Val (inf + Random.int (sup - inf)) | k -> let r = Random.int sum in if r < pw then begin if Random.int 2 = 0 then Sum(aux 0, aux (k-1)) else Sum(aux (k-1), aux 0) end else if r < pw+mw then begin if Random.int 2 = 0 then Diff(aux 0, aux (k-1)) else Diff(aux (k-1), aux 0) end else if r < pw+mw+uw then begin if Random.int 2 = 0 then Prod(aux 0, aux (k-1)) else Prod(aux (k-1), aux 0) end else begin Exp(aux (k-1), 2 + Random.int 2) end in aux length ;; let draw_bracket_open ?retval:(rv=Drawing.fodder) (x : int) (y : int) (size : int) = moveto (x + size/4) (y+5*size/4) ; lineto (x) (y+size/2) ; lineto (x) (y-size/2) ; lineto (x + size/4) (y-5*size/4) ; rv := x + size/4 +6 ;; let draw_bracket_close ?retval:(rv=Drawing.fodder) (x : int) (y : int) (size : int) = moveto (x) (y+5*size/4) ; lineto (x + size/4) (y+size/2) ; lineto (x + size/4) (y-size/2) ; lineto (x) (y-5*size/4) ; rv := x + size/4 +6 ;; let draw_sign ?retval:(rv=Drawing.fodder) (x : int) (y : int) (len : int) = function | '+' -> 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)|] ; | 'x' -> Drawing.draw_letter x y 'x' len ; | _ -> failwith "incorrect\n" ;; let require_bracket = function | Val _ -> false | _ -> true ;; let int_of_bool = function | true -> 1 | false -> 0 ;; let fm_length (fm : operation) (size : int) = let rec aux = function | Val k -> size*11/7*(1 + Math.ln_b 10 k) | Exp(f, k) -> size*11/7 (* not implemented*) | Sum(f, g) | Diff(f, g) | Prod(f, g) -> size*10/7 + (int_of_bool (require_bracket f) + int_of_bool (require_bracket g))*(size/2+12) + aux f + aux g (* sign + brackets + recursive calls *) in aux fm ;; let print_calc (f : operation) (x0 : int) (y0 : int) (size : int) = set_line_width 3 ; let fmlen = fm_length f size in let x = ref (x0) in set_color (rgb 192 192 0) ; fill_rect (x0 -6) (y0 - size - 6) (fmlen+12) (2*size + 12) ; set_color black ; let rec aux = function | Val k -> Drawing.draw_integer_alignedleft !x y0 k size ~retval:x ; (*Printf.printf "%d --> \n" !x ;*) | Exp (f, k) -> () | Sum (f, g) -> if require_bracket f then draw_bracket_open !x y0 size ~retval:x ; aux f ; if require_bracket f then draw_bracket_close !x y0 size ~retval:x ; draw_sign !x y0 size '+' ~retval:x ; x := !x + size*10/7 ; if require_bracket g then draw_bracket_open !x y0 size ~retval:x ; aux g ; if require_bracket g then draw_bracket_close !x y0 size ~retval:x ; | Diff (f, g) -> if require_bracket f then draw_bracket_open !x y0 size ~retval:x ; aux f ; if require_bracket f then draw_bracket_close !x y0 size ~retval:x ; draw_sign !x y0 size '-' ~retval:x ; x := !x + size*10/7 ; if require_bracket g then draw_bracket_open !x y0 size ~retval:x ; aux g ; if require_bracket g then draw_bracket_close !x y0 size ~retval:x ; | Prod (f, g) -> if require_bracket f then draw_bracket_open !x y0 size ~retval:x ; aux f ; if require_bracket f then draw_bracket_close !x y0 size ~retval:x ; draw_sign !x y0 (size/2) 'x' ~retval:x ; x := !x + size*10/7 ; if require_bracket g then draw_bracket_open !x y0 size ~retval:x ; aux g ; if require_bracket g then draw_bracket_close !x y0 size ~retval:x ; in aux f ;; let init_odds () = match !(Csts.difficulty) with | 1 -> Csts.plus_ch := 10 ; Csts.minus_ch := 0 ; Csts.prod_ch := 0 ; | 2 -> Csts.plus_ch := 0 ; Csts.minus_ch := 1 ; Csts.prod_ch := 0 ; | 3 -> Csts.plus_ch := 7 ; Csts.minus_ch := 5 ; Csts.prod_ch := 0 ; | 4 -> Csts.plus_ch := 5 ; Csts.minus_ch := 5 ; Csts.prod_ch := 0 ; | 5 -> Csts.plus_ch := 5 ; Csts.minus_ch := 5 ; Csts.prod_ch := 1 ; | 6 -> Csts.plus_ch := 6 ; Csts.minus_ch := 4 ; Csts.prod_ch := 1 ; | 7 -> Csts.plus_ch := 7 ; Csts.minus_ch := 2 ; Csts.prod_ch := 2 ; | 8 -> Csts.plus_ch := 7 ; Csts.minus_ch := 2 ; Csts.prod_ch := 3 ; | 9 -> Csts.plus_ch := 6 ; Csts.minus_ch := 1 ; Csts.prod_ch := 4 ; | 10 -> Csts.plus_ch := 5 ; Csts.minus_ch := 0 ; Csts.prod_ch := 5 ; | _ -> failwith "unsupported\n" ;; let sign = function | k when k < 0 -> -1 | _ -> 1 ;; let update_ans () = if key_pressed () then begin match Char.code (read_key ()) with | 45 (* minus *) -> Csts.ans := !Csts.ans * (-1) | 32 (* space *) | 8 (* del *) -> let s = sign !Csts.ans in Csts.ans := !Csts.ans * s ; Csts.ans := !Csts.ans / 10 ; Csts.ans := !Csts.ans * s ; | k when k >= 48 && k <= 57 (* digit *) -> let s = sign !Csts.ans in Csts.ans := !Csts.ans * s ; Csts.ans := 10 * !Csts.ans + k - 48 ; Csts.ans := !Csts.ans * s ; | x -> ()(*Printf.printf "%d -> %c\n" x (Char.chr x)*) end ;; let grad_color (remt : float) (initt : float) = set_color (rgb (int_of_float (255. *. remt /. initt)) (int_of_float (255. *. (1. -. (remt /. initt)))) 0) ;; let maeth_main () = let start = Unix.gettimeofday () in let cur = ref (Unix.gettimeofday ()) in let found = ref false in let equ = generate_random_calc ~plus_w:(!Csts.plus_ch) ~minus_w:(!Csts.minus_ch) ~prod_w:(!Csts.prod_ch) !Csts.calc_length !Csts.n_inf !Csts.n_sup in let resu = calculate equ in while not !found && (!cur -. start <= !Csts.time_to_ans_f) && (!cur -. !Csts.start_0) <= !Csts.total_time_f do auto_synchronize false ; clear_graph () ; set_color black ; print_calc equ (10) (Csts.__height__/2) 15 ; Drawing.draw_string_centered (Csts.__width__/2) (Csts.__height__/3) "Answer" 50 ; Drawing.draw_integer (Csts.__width__/2) (Csts.__height__/3 - 100) !Csts.ans 75 ; fill_rect (Csts.__width__ - 70) (Csts.__height__/4) 70 (Csts.__height__/2) ; set_color (rgb 129 255 0) ; fill_rect (Csts.__width__ - 60) (Csts.__height__/4 + 10) 50 (max 0 (Csts.__height__/2 - 20 - int_of_float (float_of_int (Csts.__height__/2 - 20) *. (!cur -. !Csts.start_0) /. !Csts.total_time_f))) ; grad_color (!cur -. start) (!Csts.time_to_ans_f) ; fill_rect 0 (7*Csts.__height__/8) (int_of_float ((float_of_int Csts.__width__) *. (!cur -. start) /. !Csts.time_to_ans_f)) (Csts.__height__/8+1) ; set_color (rgb 192 192 0) ; Drawing.draw_string 10 (Csts.__height__ - 40) "Score" 35 ; set_color (rgb 128 128 0) ; Drawing.draw_integer_alignedleft (10+(5+1)*35*10/7) (Csts.__height__ - 40) !Csts.score 35 ; set_color (rgb 0 128 128) ; Drawing.draw_integer_alignedright (Csts.__width__ - 20) (10+35) !Csts.combo 35 ; set_color (rgb 0 192 192) ; Drawing.draw_string (Csts.__width__ - 20 - 35*(5+1 + Math.ln_b 10 !Csts.combo)*11/7) (10+35) "Combo" 35 ; auto_synchronize true ; update_ans () ; if !Csts.ans = resu then found := true ; Unix.sleepf Csts.sleep_d ; cur := Unix.gettimeofday () ; done ; Csts.ans := 0 ; incr Csts.n_ans ; if (!cur -. !Csts.start_0) > !Csts.total_time_f then true else if !found then begin incr Csts.combo ; Csts.max_combo := max (!Csts.max_combo) !Csts.combo ; Csts.score := !Csts.score + int_of_float ( (float_of_int !Csts.max_score) *. (!Csts.time_to_ans_f -. (!cur -. start) /. 2.) /. !Csts.time_to_ans_f *. (1. +. Float.sqrt (float_of_int !Csts.combo)) ) ; (* give 50% of max pts for correct answer + up to 50% more for speed *) true end else begin Csts.combo := 0 ; incr Csts.misses ; false end ;; let result_screen () = try while true do auto_synchronize false ; clear_graph () ; set_color black ; Drawing.draw_string_centered (Csts.__width__/2) (Csts.__height__ - 60) "Press space to return to main" 22 ; set_color (rgb 192 192 0) ; Drawing.draw_string (Csts.__width__/6) (Csts.__height__/2 + 140) "Score" 20 ; set_color (rgb 255 255 0) ; Drawing.draw_integer_alignedleft (Csts.__width__/6+20*(5+1)*10/7) (Csts.__height__/2 + 140) !Csts.score 20 ; set_color (rgb 0 192 0) ; Drawing.draw_string (Csts.__width__/6) (Csts.__height__/2 + 70) "Max Combo" 20 ; set_color (rgb 0 255 0) ; Drawing.draw_integer_alignedleft (Csts.__width__/6+20*(9+1)*10/7) (Csts.__height__/2 + 70) !Csts.max_combo 20 ; set_color (rgb 0 192 32) ; Drawing.draw_string (Csts.__width__/6) (Csts.__height__/2) "Combo" 20 ; set_color (rgb 0 255 32) ; Drawing.draw_integer_alignedleft (Csts.__width__/6+20*(5+1)*10/7) (Csts.__height__/2) !Csts.combo 20 ; set_color (rgb 192 0 0) ; Drawing.draw_string (Csts.__width__/6) (Csts.__height__/2 - 70) "Misses" 20 ; set_color (rgb 255 0 0) ; Drawing.draw_integer_alignedleft (Csts.__width__/6+20*(6+1)*10/7) (Csts.__height__/2 - 70) !Csts.misses 20 ; set_color (rgb 0 0 192) ; Drawing.draw_string (Csts.__width__/6) (Csts.__height__/2 - 140) "Accuracy" 20 ; set_color (rgb 0 0 192) ; Drawing.draw_integer_alignedleft (Csts.__width__/6+20*(8+1)*10/7) (Csts.__height__/2 - 140) (int_of_float (1000. *. (float_of_int (!Csts.n_ans - !Csts.misses)) /. (float_of_int !Csts.n_ans))) 20 ; if !Csts.misses = 0 then begin set_color (rgb 0 255 0) ; Drawing.draw_string_centered (Csts.__width__/2) (40) "FC" 35 end ; auto_synchronize true ; Unix.sleepf Csts.sleep_d ; if key_pressed () && (read_key ()) == ' ' then raise Reset done; () with | Reset -> () ;;