MathGame_V2/maeth.ml

240 lines
7.5 KiB
OCaml

open Graphics ;;
Random.self_init () ;;
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 print_calc (f : operation) (x0 : int) (y0 : int) (size : int) =
set_line_width 3 ;
set_color black ;
let x = ref x0 in
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) 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 ;
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)) /. !Csts.time_to_ans_f) ;
true
end
else begin
Csts.combo := 0 ;
false
end ;;