MathGame_V2/main.ml

507 lines
16 KiB
OCaml

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 *)