aboutsummaryrefslogtreecommitdiff
path: root/motus/lib
diff options
context:
space:
mode:
authorSébastien Dailly <sebastien@dailly.me>2022-02-24 08:59:44 +0100
committerSébastien Dailly <sebastien@dailly.me>2022-02-24 13:39:39 +0100
commitc2bd6982e5ed845293a38ae600c239cd50924d76 (patch)
tree4e68d4e7f9c2b9d5ae597f54961891332fc0e985 /motus/lib
parent89dbb39c3fcd188ef7acf092061d756046b2c5d4 (diff)
Update code, added tests
Diffstat (limited to 'motus/lib')
-rw-r--r--motus/lib/dune1
-rw-r--r--motus/lib/validity.ml98
-rw-r--r--motus/lib/validity.mli20
-rw-r--r--motus/lib/wordlist.ml (renamed from motus/lib/persistence.ml)35
-rw-r--r--motus/lib/wordlist.mli (renamed from motus/lib/persistence.mli)11
5 files changed, 140 insertions, 25 deletions
diff --git a/motus/lib/dune b/motus/lib/dune
index b958922..a892e2b 100644
--- a/motus/lib/dune
+++ b/motus/lib/dune
@@ -2,6 +2,7 @@
(name
motus_lib
)
+ (preprocess (pps ppx_deriving.enum))
)
diff --git a/motus/lib/validity.ml b/motus/lib/validity.ml
new file mode 100644
index 0000000..ae85f04
--- /dev/null
+++ b/motus/lib/validity.ml
@@ -0,0 +1,98 @@
+open StdLabels
+
+(* Enclose the type definition into a warning removval in order to hide some
+ auto-generated values *)
+[@@@warning "-32"]
+
+type t =
+ | Wellplaced
+ | Misplaced
+ | Missing
+[@@deriving enum]
+
+[@@@warning "+32"]
+
+let m = Float.of_int (1 + max)
+
+(** Get the index of a validity result *)
+let index_of_result : t array -> int =
+ fun elems ->
+ let _, value =
+ Array.fold_left elems ~init:(0., 0.) ~f:(fun (pos, acc) content ->
+ let v = Float.of_int (to_enum content) in
+ let acc' = acc +. (v *. (m ** pos)) in
+ (pos +. Float.one, acc') )
+ in
+ Float.to_int value
+
+
+let index_to_result : base:int -> int -> t array =
+ fun ~base n ->
+ let rec _f acc n i =
+ let next = Float.round (n /. m)
+ and rem = Float.(to_int @@ rem n m) in
+
+ match (rem, i) with
+ | _, 0 -> Array.of_list acc
+ | n, _ ->
+ ( match of_enum n with
+ | None -> Array.of_list acc
+ | Some v -> _f (v :: acc) next (i - 1) )
+ in
+ _f [] (Float.of_int n) base
+
+
+(** Build a sequence of all the possible status for a given number of letters *)
+let sequence : int -> t array Seq.t =
+ fun base ->
+ let max_element = Float.to_int @@ (m ** Float.of_int base) in
+
+ Seq.unfold
+ (fun n ->
+ if n < max_element then Some (index_to_result ~base n, n + 1) else None )
+ 0
+
+
+let compare_words : string -> ref:string -> t array option =
+ fun w1 ~ref ->
+ let l1 = String.length w1 in
+ if l1 <> String.length ref
+ then None
+ else
+ let result =
+ Array.init l1 ~f:(fun i ->
+ let c1 = String.get w1 i
+ and c2 = String.get ref i in
+
+ let state =
+ if Char.equal c1 c2
+ then Wellplaced
+ else if String.contains ref c1
+ then Misplaced
+ else Missing
+ in
+ state )
+ in
+ Some result
+
+
+let to_criteria : char -> int -> t -> Criteria.t list -> Criteria.t list =
+ fun c i t acc ->
+ match t with
+ | Wellplaced -> Criteria.add (Criteria.Contain (c, Some i)) acc
+ | Missing -> Criteria.add (Criteria.NotContain (c, None)) acc
+ | Misplaced ->
+ Criteria.add
+ (Criteria.NotContain (c, Some i))
+ (Criteria.add (Criteria.Contain (c, None)) acc)
+
+
+let to_criterias : string -> t array -> Criteria.t list =
+ fun word t ->
+ let l, _ =
+ Array.fold_left t ~init:([], 0) ~f:(fun (acc, i) t ->
+ let acc = to_criteria (String.get word i) i t acc in
+ (acc, i + 1) )
+ in
+
+ List.rev l
diff --git a/motus/lib/validity.mli b/motus/lib/validity.mli
new file mode 100644
index 0000000..dfd876c
--- /dev/null
+++ b/motus/lib/validity.mli
@@ -0,0 +1,20 @@
+type t =
+ | Wellplaced
+ | Misplaced
+ | Missing
+
+val sequence : int -> t array Seq.t
+(** Build a sequence of all the possible status for a given number of letters *)
+
+val index_of_result : t array -> int
+(** Get the index of a validity result *)
+
+val index_to_result : base:int -> int -> t array
+
+val compare_words : string -> ref:string -> t array option
+
+val to_criteria : char -> int -> t -> Criteria.t list -> Criteria.t list
+
+val to_criterias : string -> t array -> Criteria.t list
+(** Convert the validity result into a Criteria list, in the context of a given
+ word *)
diff --git a/motus/lib/persistence.ml b/motus/lib/wordlist.ml
index 6116653..45fc73a 100644
--- a/motus/lib/persistence.ml
+++ b/motus/lib/wordlist.ml
@@ -5,39 +5,34 @@ let () = Random.self_init ()
type t =
{ number : int
; element : string list
- ; freq : (char, int) Hashtbl.t
}
-let empty_data () = { number = 0; element = []; freq = Hashtbl.create 26 }
+let empty_data () = { number = 0; element = [] }
+
+let update_freq : (char, int) Hashtbl.t -> char -> unit =
+ fun freq c ->
+ match Hashtbl.find_opt freq c with
+ | None -> Hashtbl.add freq c 1
+ | Some value -> Hashtbl.replace freq c (value + 1)
+
(** Evaluate the score for each char (lower is better) *)
let extract_freq : t -> (char * int) list =
fun data ->
+ let freq = Hashtbl.create 26 in
+ List.iter data.element ~f:(fun word ->
+ String.iter word ~f:(fun c -> update_freq freq c) );
+
let number_2 = data.number / 2 in
- Hashtbl.fold (fun k v acc -> (k, abs (v - number_2)) :: acc) data.freq []
+ Hashtbl.fold (fun k v acc -> (k, abs (v - number_2)) :: acc) freq []
(* Sort the list for a pretty printing *)
|> List.sort ~cmp:(fun v1 v2 -> snd v1 - snd v2)
-let update_freq : (char, int) Hashtbl.t -> char -> unit =
- fun freq c ->
- match Hashtbl.find_opt freq c with
- | None -> Hashtbl.add freq c 1
- | Some value -> Hashtbl.replace freq c (value + 1)
-
-
let add_word : Criteria.t list -> t -> string -> t =
fun filters data word ->
match List.for_all ~f:(Criteria.check_filter word) filters with
- | true ->
- let len = String.length word in
- let chars =
- List.init ~len ~f:(fun n -> String.get word n)
- |> List.sort_uniq ~cmp:Char.compare
- in
-
- List.iter ~f:(update_freq data.freq) chars;
- { data with number = data.number + 1; element = word :: data.element }
+ | true -> { number = data.number + 1; element = word :: data.element }
| false -> data
@@ -87,7 +82,7 @@ let pick_next_word : t -> (char * int) list -> string * int =
let remove_word : t -> string -> t =
fun t word ->
let element = List.filter ~f:(fun w -> not (String.equal w word)) t.element in
- { t with element; number = t.number - 1 }
+ { element; number = t.number - 1 }
let words : t -> string list = fun { element; _ } -> element
diff --git a/motus/lib/persistence.mli b/motus/lib/wordlist.mli
index f5625e4..766fbdf 100644
--- a/motus/lib/persistence.mli
+++ b/motus/lib/wordlist.mli
@@ -7,12 +7,15 @@ val list_size : t -> int
val empty_data : unit -> t
-val extract_freq : t -> (char * int) list
-(** Evaluate the score for each char (lower is better) *)
-
val add_word : Criteria.t list -> t -> string -> t
(** Add a new word in the list. Check are made against the differents criteria in order to ensure that the word is valid *)
+val remove_word : t -> string -> t
+(** Remove a word from this list *)
+
+val extract_freq : t -> (char * int) list
+(** Evaluate the score for each char (lower is better) *)
+
val pick_next_word : t -> (char * int) list -> string * int
(** Get the word which with the most information in it.
@@ -20,5 +23,3 @@ The information is the score given to each character, representing each
frequency in the whole word list (lower is better). If the same letter is
present many times, we consider that succeding letters does not give any more
informations (do not consider the position here) *)
-
-val remove_word : t -> string -> t