From fe13ea5ce39b24b2d49b43c384ed01b013d683db Mon Sep 17 00:00:00 2001 From: Sébastien Dailly Date: Mon, 4 Mar 2024 21:07:51 +0100 Subject: calculette_aoo: now evaluate the exact frequency, some corrections --- calculette_aoo/index.html | 30 +++++++++++++++- calculette_aoo/js/dune | 1 + calculette_aoo/js/main.ml | 77 ++++++++++++++++++++++++++++++++++++++++- calculette_aoo/lib/build.ml | 58 ++++++++++++------------------- calculette_aoo/lib/build.mli | 2 +- calculette_aoo/lib/dune | 4 ++- calculette_aoo/lib/roll.ml | 81 ++++++++++++++++++++++++++++++++++++++++++++ dune-project | 25 +++++++++++--- 8 files changed, 233 insertions(+), 45 deletions(-) create mode 100644 calculette_aoo/lib/roll.ml diff --git a/calculette_aoo/index.html b/calculette_aoo/index.html index 6dd2955..e4e015a 100644 --- a/calculette_aoo/index.html +++ b/calculette_aoo/index.html @@ -70,7 +70,33 @@ textarea { table tr td input { width: 2em; text-align: center} table tr td input.wellplaced { background-color: lightgreen;} table tr td input.misplaced { background-color: gold;} -tr:first-child { outline: thin solid; } + +th, td { + border: 1px solid rgb(160 160 160); + padding: 8px 10px; +} + +th[scope='col'] { + background-color: #505050; + color: #fff; +} + +th[scope='row'] { + background-color: #d6ecd4; +} + +td { text-align: center; } + + tr:nth-of-type(even) { + background-color: #eee; + } + +table { + border-collapse: collapse; + border: 2px solid rgb(140 140 140); + letter-spacing: 1px; +} + /* Responsive layout - when the screen is less than 700px wide, make the two columns stack on top of each other instead of next to each other */ @media screen and (max-width: 700px) { @@ -175,6 +201,8 @@ tr:first-child { outline: thin solid; }

Résultats

+

Tables

+
diff --git a/calculette_aoo/js/dune b/calculette_aoo/js/dune index 8732ae0..b2ece9c 100644 --- a/calculette_aoo/js/dune +++ b/calculette_aoo/js/dune @@ -3,6 +3,7 @@ (libraries brr note.brr + zarith_stubs_js application aoo ) diff --git a/calculette_aoo/js/main.ml b/calculette_aoo/js/main.ml index 9a63d12..3106041 100644 --- a/calculette_aoo/js/main.ml +++ b/calculette_aoo/js/main.ml @@ -1,4 +1,5 @@ open Brr +open StdLabels let ( let=? ) : 'a option -> ('a -> unit) -> unit = fun f opt -> Option.iter opt f @@ -18,6 +19,12 @@ let cout_fm = (100, 50, 30) let get_element_by_id id = Jstr.of_string id |> Brr.Document.find_el_by_id Brr.G.document +let distance_table fm = + Array.init 4 ~f:(fun i -> + Array.init 7 ~f:(fun i -> max 1 ((i + 4) * 4)) + |> Aoo.Roll.against (fm + i) + |> Array.map ~f:(fun v -> Q.to_float v *. 100.)) + let get_int_element id = Jstr.of_string id |> Brr.Document.find_el_by_id Brr.G.document @@ -51,7 +58,7 @@ let eval _ = let env : Aoo.Build.env = { cost_max = get_int_element "xp" + cost - ; max_tours = float (get_int_element "tours") + ; max_tours = get_int_element "tours" ; cout_sort = get_int_element "cost" ; degat_sort = get_int_element "dammage" ; fm_oponent @@ -77,6 +84,74 @@ let eval _ = let=? result_element = get_element_by_id "result" in El.set_children result_element [ El.txt' result ]; + + (* Update the oposition table *) + let=? div_table = get_element_by_id "tables_div" in + let difficulties = + let fm = fm_element + fm_bonus in + let table = distance_table fm in + Brr.El.tr + [ + Brr.El.th [ Brr.El.txt' "Distance" ] + ; Brr.El.th + [ + Brr.El.txt' "% de toucher (FM" + ; Brr.El.txt @@ Jstr.of_int @@ fm + ; Brr.El.txt' ")" + ] + ; Brr.El.th + [ + Brr.El.txt' "% de toucher (FM" + ; Brr.El.txt @@ Jstr.of_int @@ (fm + 1) + ; Brr.El.txt' ")" + ] + ; Brr.El.th + [ + Brr.El.txt' "% de toucher (FM" + ; Brr.El.txt @@ Jstr.of_int @@ (fm + 2) + ; Brr.El.txt' ")" + ] + ; Brr.El.th + [ + Brr.El.txt' "% de toucher (FM" + ; Brr.El.txt @@ Jstr.of_int @@ (fm + 3) + ; Brr.El.txt' ")" + ] + ] + :: List.init ~len:7 ~f:(fun i -> + Brr.El.tr + (Brr.El.td [ Brr.El.txt (Jstr.of_int (i + 5)) ] + :: List.init ~len:4 ~f:(fun j -> + let cell = + Jstr.of_float ~frac:2 table.(j).(i) |> Brr.El.txt + in + Brr.El.td [ cell ]))) + in + + let table_opposition = + Brr.El.table + @@ Brr.El.tr + [ + Brr.El.th [ Brr.El.txt' "FM" ] + ; Brr.El.th + [ + Brr.El.txt' "% de toucher l’adversaire" + ; Brr.El.txt' " (FM " + ; Brr.El.txt @@ Jstr.of_int env.fm_oponent + ; Brr.El.txt' ")" + ] + ] + :: List.map env.frequencies ~f:(fun (v, value) -> + Brr.El.tr + [ + Brr.El.td [ Brr.El.txt (Jstr.of_int v) ] + ; Brr.El.td + [ Brr.El.txt (Jstr.of_float ~frac:3 (value *. 100.)) ] + ]) + and table_distance = Brr.El.table difficulties in + + El.set_children div_table [ table_opposition; table_distance ]; + () let main () = diff --git a/calculette_aoo/lib/build.ml b/calculette_aoo/lib/build.ml index ddefe67..5c2ac0b 100644 --- a/calculette_aoo/lib/build.ml +++ b/calculette_aoo/lib/build.ml @@ -9,54 +9,41 @@ type build = { type env = { cout_sort : int ; degat_sort : int - ; max_tours : float + ; max_tours : int ; fm_oponent : int ; cost_max : int ; frequencies : (int * float) list } -let roll_and_accumulate dices = - Seq.repeat () |> Seq.take dices - |> Seq.fold_left (fun res _ -> res + (1 + Random.int 3)) 0 - -let delta_carac level thresold = - Seq.repeat () |> Seq.take 10000 - |> Seq.fold_left - (fun acc _ -> - if roll_and_accumulate thresold > roll_and_accumulate level then acc - else acc + 1) - 0 - let get_chance : env -> int -> float = fun env delta -> match List.assoc_opt delta env.frequencies with - | None -> 1.0 + | None -> 1. | Some v -> v (** Build a list with the differents percentages to hit *) let buil_freq_table from thresold = - let () = Random.self_init () in - List.init 6 (fun i -> - (from - thresold + i, float (delta_carac (from + i) thresold) /. 10000.)) + List.init 10 (fun i -> + (from + i, Roll.compare (from + i) thresold |> Q.to_float)) -let eval : build -> env -> float * float = +let eval : build -> env -> float * int = fun { a; m; rm; pm; fm } env -> - let cout_tour = (Carac.value a * env.cout_sort) - Carac.value rm in - let nb_tour = - if cout_tour > 0 then - float (Carac.value pm) /. float cout_tour |> Float.min env.max_tours - else env.max_tours + let mp_available = Carac.value pm + ((env.max_tours - 1) * Carac.value rm) in + + (* How many attacks can be done using this cost ? (rounded down) *) + let nb_attacks = + min (env.max_tours * Carac.value a) (mp_available / env.cout_sort) in let degats = - float (Carac.value a * (env.degat_sort + Carac.value m - 5)) - *. get_chance env (Carac.value fm - env.fm_oponent) + float (nb_attacks * (env.degat_sort + Carac.value m - 5)) + *. get_chance env (Carac.value fm) in - (degats, nb_tour) + (degats, nb_attacks) let repr_degats : env -> Format.formatter -> build -> unit = fun env out build -> - let delta = get_chance env (Carac.value build.fm - env.fm_oponent) in + let delta = get_chance env (Carac.value build.fm) in Format.fprintf out "%d A × (%d du sorts + %d M - %d M) × %.2f %%" (Carac.value build.a) env.degat_sort (Carac.value build.m) 5 (delta *. 100.); let sum = env.degat_sort + Carac.value build.m - 5 in @@ -71,7 +58,7 @@ let cost : build -> int = let repr : env -> Format.formatter -> build -> unit = fun env formatter build -> - let degats, nb_tour = eval build env in + let degats, nb_attacks = eval build env in Format.fprintf formatter {|Caractéristiques retenues : @@ -84,18 +71,17 @@ let repr : env -> Format.formatter -> build -> unit = Carac.repr build.a Carac.repr build.m Carac.repr build.fm Carac.repr build.rm Carac.repr build.pm; Format.fprintf formatter - "@[Le magicien fera %.2f degats par tour pour un total de %d sur %.2f \ - tours@;\ + "@[Le magicien fera %.2f degats par attaque pour un total de %.2f (via %d \ + attaques)@;\ (@[%a@])@;" - degats - (int_of_float (nb_tour *. degats)) - nb_tour (repr_degats env) build; + (degats /. float_of_int nb_attacks) + degats nb_attacks (repr_degats env) build; Format.fprintf formatter "Le cout de ce build est de %d@]@." (cost build) let score : env -> build -> float = fun env build -> let d, v = eval build env in - d *. v + d (* Upgrade each caracteristic and keep only the values in range *) let upgrade : env -> build -> build list = @@ -125,9 +111,7 @@ let rec traverse env (last_cost, last_score) = function upgrade env hd |> List.filter (fun build -> List.for_all - (fun element -> - cost build > cost element - || score env build > score env element) + (fun element -> score env build > score env element) tl) in diff --git a/calculette_aoo/lib/build.mli b/calculette_aoo/lib/build.mli index 3e2e690..7e39b71 100644 --- a/calculette_aoo/lib/build.mli +++ b/calculette_aoo/lib/build.mli @@ -9,7 +9,7 @@ type build = { type env = { cout_sort : int ; degat_sort : int - ; max_tours : float + ; max_tours : int ; fm_oponent : int ; cost_max : int ; frequencies : (int * float) list diff --git a/calculette_aoo/lib/dune b/calculette_aoo/lib/dune index 54b5a85..176147c 100644 --- a/calculette_aoo/lib/dune +++ b/calculette_aoo/lib/dune @@ -1,2 +1,4 @@ (library - (name aoo)) + (name aoo) + (libraries zarith) + ) diff --git a/calculette_aoo/lib/roll.ml b/calculette_aoo/lib/roll.ml new file mode 100644 index 0000000..00d8465 --- /dev/null +++ b/calculette_aoo/lib/roll.ml @@ -0,0 +1,81 @@ +open StdLabels + +(** Evaluate the coefficient for the product of two polynamials *) +let mul p1 p2 = + let n1 = Array.length p1 and n2 = Array.length p2 in + let n = n1 + n2 in + let res = Array.make n 0 in + for i = 0 to n1 - 1 do + for j = 0 to n2 - 1 do + res.(i + j + 1) <- res.(i + j + 1) + (p1.(i) * p2.(j)) + done + done; + res + +(** Apply a power function over a polynomial *) +let pow p1 n = + let result = ref p1 in + for _ = 1 to n - 1 do + result := mul !result p1 + done; + !result + +(** Evaluate the odd to win agains a give difficulty *) +let against : int -> int array -> Q.t array = + fun n difficulties -> + match n with + | 0 -> Array.map ~f:(fun _ -> Q.zero) difficulties + | _ -> + (* Create the polynomial with the odd ratio for the given caracteristic *) + let arr = Array.make 3 1 in + let frequencies = pow arr n in + let ratio = Z.(of_int 3 ** n) in + + let get_chances difficulty = + (* Evaluate the ratio to win the roll *) + let chances = ref Z.zero in + for i = difficulty - 1 to Array.length frequencies - 1 do + (* The index in the table is the odd to get exactly this value in the roll. + Here, we just add every value in the array from the index strarting from + the given difficulty. *) + chances := Z.(!chances + of_int frequencies.(i)) + done; + Q.make !chances ratio + in + Array.map ~f:get_chances difficulties + +(** Compare two caracteristics. + [compare v1 v2] will evaluate the odds to win if the player has the + caracteristics [v1] against the openent [v2]. + + In case of equality, the win is given to [v1] *) +let compare : int -> int -> Q.t = + fun carac1 carac2 -> + let arr = Array.make 3 1 in + let z3 = Z.of_int 3 in + + let ordinal1 = Z.(z3 ** carac1) + and ordinal2 = Z.(z3 ** carac2) + (*Number of possibles values for each caracteristc *) + and elements1 = 3 * carac1 + and elements2 = 3 * carac2 in + + (* The number of iterations to do is elements1 × elements2. For every iteration of elements2, we have ordinal1 points to get. *) + let cases = Z.(ordinal1 * ordinal2) in + + let frequencies_1 = pow arr carac1 |> Array.map ~f:(fun v -> Z.(of_int v)) + and frequencies_2 = pow arr carac2 |> Array.map ~f:(fun v -> Z.(of_int v)) in + + (* Now, compare for each values the probabily to win *) + let res = ref Z.zero in + let () = + for i = 0 to elements1 - 1 do + for j = 0 to elements2 - 1 do + if i >= j then + (* Number of times this combinaison is occuring *) + let freq = Z.(frequencies_1.(i) * frequencies_2.(j)) in + Z.(res := !res + freq) + done + done + in + Q.make !res cases diff --git a/dune-project b/dune-project index 090795c..20e33c1 100755 --- a/dune-project +++ b/dune-project @@ -9,7 +9,8 @@ (synopsis "Calligraphy app") (depends (ocaml (>= 4.10.0)) - (brr (>= 0.0.1)) + (brr (>= 0.0.6)) + (note (>= 0.0.3)) (gg (>= 0.9.3)) ) ) @@ -19,7 +20,8 @@ (synopsis "Text editor") (depends (ocaml (>= 4.10.0)) - (brr (>= 0.0.1)) + (brr (>= 0.0.6)) + (note (>= 0.0.3)) ) ) @@ -28,7 +30,8 @@ (synopsis "CSS Merger") (depends (ocaml (>= 4.10.0)) - (brr (>= 0.0.1)) + (brr (>= 0.0.6)) + (note (>= 0.0.3)) (css-parser (>= 0.2.4)) ) ) @@ -38,7 +41,8 @@ (synopsis "Motus solver") (depends (ocaml (>= 4.10.0)) - (brr (>= 0.0.1)) + (brr (>= 0.0.6)) + (note (>= 0.0.3)) (ppx_deriving (>= 5.2.1)) ) ) @@ -52,3 +56,16 @@ ) ) (using menhir 2.1) + +(package + (name optim_aooo) + (synopsis "aoo solver") + (depends + (ocaml (>= 4.10.0)) + (brr (>= 0.0.6)) + (note (>= 0.0.3)) + (ppx_deriving (>= 5.2.1)) + (zarith) + (zarith_stubs_js) + ) + ) -- cgit v1.2.3