aboutsummaryrefslogtreecommitdiff
path: root/calculette_aoo/lib/build.ml
diff options
context:
space:
mode:
Diffstat (limited to 'calculette_aoo/lib/build.ml')
-rw-r--r--calculette_aoo/lib/build.ml135
1 files changed, 135 insertions, 0 deletions
diff --git a/calculette_aoo/lib/build.ml b/calculette_aoo/lib/build.ml
new file mode 100644
index 0000000..ddefe67
--- /dev/null
+++ b/calculette_aoo/lib/build.ml
@@ -0,0 +1,135 @@
+type build = {
+ a : Carac.t
+ ; m : Carac.t
+ ; rm : Carac.t
+ ; pm : Carac.t
+ ; fm : Carac.t
+}
+
+type env = {
+ cout_sort : int
+ ; degat_sort : int
+ ; max_tours : float
+ ; 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
+ | 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.))
+
+let eval : build -> env -> float * float =
+ 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
+ in
+
+ let degats =
+ float (Carac.value a * (env.degat_sort + Carac.value m - 5))
+ *. get_chance env (Carac.value fm - env.fm_oponent)
+ in
+ (degats, nb_tour)
+
+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
+ 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
+ let prod = Carac.value build.a * sum in
+ Format.fprintf out "@;%d A × %d = %d@;" (Carac.value build.a) sum prod;
+ Format.fprintf out "%d × %.2f = %.2f" prod delta (delta *. float prod);
+ ()
+
+let cost : build -> int =
+ fun { a; m; rm; pm; fm } ->
+ Carac.(cout a + cout m + cout rm + cout pm + cout fm)
+
+let repr : env -> Format.formatter -> build -> unit =
+ fun env formatter build ->
+ let degats, nb_tour = eval build env in
+
+ Format.fprintf formatter
+ {|Caractéristiques retenues :
+- A : %a
+- M : %a
+- FM: %a
+- RM: %a
+- PM: %a
+|}
+ 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@;\
+ (@[<v 2>%a@])@;"
+ degats
+ (int_of_float (nb_tour *. degats))
+ nb_tour (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
+
+(* Upgrade each caracteristic and keep only the values in range *)
+let upgrade : env -> build -> build list =
+ fun env build ->
+ [
+ { build with a = Carac.incr build.a }
+ ; { build with m = Carac.incr build.m }
+ ; { build with rm = Carac.incr build.rm }
+ ; { build with pm = Carac.incr build.pm }
+ ; { build with pm = Carac.incr ~step:3 build.pm }
+ ; { build with pm = Carac.incr ~step:10 build.pm }
+ ; { build with fm = Carac.incr build.fm }
+ ]
+ |> List.filter (fun f -> cost f <= env.cost_max)
+
+let rec traverse env (last_cost, last_score) = function
+ | [] -> failwith "Invalid data"
+ | hd :: [] -> hd
+ | hd :: tl ->
+ let score' = score env hd and cost' = cost hd in
+ if cost' > last_cost && score' < last_score then
+ traverse env (last_cost, last_score) tl
+ else
+ (* Get the new elements to add and filter them if they do not provide
+ anything better *)
+ let new_builds =
+ upgrade env hd
+ |> List.filter (fun build ->
+ List.for_all
+ (fun element ->
+ cost build > cost element
+ || score env build > score env element)
+ tl)
+ in
+
+ (* For each new element, remove all the obsolete builds *)
+ traverse env (cost', score') (List.rev_append tl new_builds)