aboutsummaryrefslogtreecommitdiff
path: root/calculette_aoo
diff options
context:
space:
mode:
Diffstat (limited to 'calculette_aoo')
-rw-r--r--calculette_aoo/index.html30
-rw-r--r--calculette_aoo/js/dune1
-rw-r--r--calculette_aoo/js/main.ml77
-rw-r--r--calculette_aoo/lib/build.ml58
-rw-r--r--calculette_aoo/lib/build.mli2
-rw-r--r--calculette_aoo/lib/dune4
-rw-r--r--calculette_aoo/lib/roll.ml81
7 files changed, 212 insertions, 41 deletions
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; }
<h2>Résultats</h2>
<textarea id="result" >
</textarea>
+ <h2>Tables</h2>
+ <div id="tables_div" class="row"/>
</div>
</body>
</html>
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)@;\
(@[<v 2>%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