diff options
author | Sébastien Dailly <sebastien@dailly.me> | 2024-02-24 11:31:28 +0100 |
---|---|---|
committer | Sébastien Dailly <sebastien@dailly.me> | 2024-02-24 11:31:28 +0100 |
commit | ef9beb0814c36cda979a4ed7e9175e72e69540ac (patch) | |
tree | c2852b1dd5df53f5d78e9e952f29360d50126e06 /calculette_aoo/lib | |
parent | 9e7f27c60a425e2baa67cd459d8509a43b1d123d (diff) |
New application: build upgrade helper for aoo
Diffstat (limited to 'calculette_aoo/lib')
-rw-r--r-- | calculette_aoo/lib/build.ml | 135 | ||||
-rw-r--r-- | calculette_aoo/lib/build.mli | 35 | ||||
-rw-r--r-- | calculette_aoo/lib/carac.ml | 40 | ||||
-rw-r--r-- | calculette_aoo/lib/carac.mli | 17 | ||||
-rw-r--r-- | calculette_aoo/lib/dune | 2 |
5 files changed, 229 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) diff --git a/calculette_aoo/lib/build.mli b/calculette_aoo/lib/build.mli new file mode 100644 index 0000000..3e2e690 --- /dev/null +++ b/calculette_aoo/lib/build.mli @@ -0,0 +1,35 @@ +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 +} + +val buil_freq_table : int -> int -> (int * float) list +(** Build a list with the differents percentages to hit *) + +val cost : build -> int +(** Get the cost for a build *) + +val score : env -> build -> float +(** Get the score for the build *) + +val traverse : env -> int * float -> build list -> build +(** Test differents upgrade configuration and present the best one with the + constraints given in [env]. + + The costt for the upgrade will not exceed the property [env.cost_max] + *) + +val upgrade : env -> build -> build list +val repr : env -> Format.formatter -> build -> unit diff --git a/calculette_aoo/lib/carac.ml b/calculette_aoo/lib/carac.ml new file mode 100644 index 0000000..a48c734 --- /dev/null +++ b/calculette_aoo/lib/carac.ml @@ -0,0 +1,40 @@ +type cout_carac = int * int * int + +type t = { + value : int + ; couts : cout_carac + ; bonus : int +} + +let create : ?bonus:int -> int -> cout_carac -> t = + fun ?(bonus = 0) value couts -> { value; couts; bonus } + +let incr ?(step = 1) t = { t with bonus = t.bonus + step } + +(* +Evaluate the cost for the successives upgrades. + +I’m pretty sure this can be transformed into a linear function, but I do not see how… + + c0 * t.bonus ++ max 0 ((((t.bonus - 1) * 2) - 1) * c1) ++ ? + + *) +let cout : t -> int = + fun t -> + let c0, c1, c2 = t.couts in + let rec c acc t = + match t with + | 0 -> acc + | 1 -> acc + c0 + | 2 -> c (acc + c0 + c1) (t - 1) + | 3 -> c (acc + c0 + (c1 * 2)) (t - 1) + | n -> c (acc + c0 + (c1 * 2) + ((n - 3) * c2)) (t - 1) + in + c 0 t.bonus + +let value t = t.value + t.bonus + +let repr : Format.formatter -> t -> unit = + fun out t -> Format.fprintf out "%d (+%d)" (value t) t.bonus diff --git a/calculette_aoo/lib/carac.mli b/calculette_aoo/lib/carac.mli new file mode 100644 index 0000000..f364c81 --- /dev/null +++ b/calculette_aoo/lib/carac.mli @@ -0,0 +1,17 @@ +type t +type cout_carac = int * int * int + +val create : ?bonus:int -> int -> cout_carac -> t + +val cout : t -> int +(** Get the cost for the upgrades for this property *) + +val value : t -> int +(** Get the value (including upgrades) for this property *) + +val incr : ?step:int -> t -> t +(** Increment this property. + step is default 1. + *) + +val repr : Format.formatter -> t -> unit diff --git a/calculette_aoo/lib/dune b/calculette_aoo/lib/dune new file mode 100644 index 0000000..54b5a85 --- /dev/null +++ b/calculette_aoo/lib/dune @@ -0,0 +1,2 @@ +(library + (name aoo)) |