MathGame_V2/maeth.ml

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 -> () ;;