316 lines
10 KiB
OCaml
316 lines
10 KiB
OCaml
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 -> () ;; |