diff options
Diffstat (limited to 'calculette_aoo/lib/build.ml')
-rw-r--r-- | calculette_aoo/lib/build.ml | 135 |
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) |