open StdLabels type t = float * string module CharSet = Set.Make (Char) let compare_words : string -> ref:string * CharSet.t -> Validity.t array option = fun w1 ~ref -> let wordRef = fst ref in let l1 = String.length w1 in if l1 <> String.length wordRef then None else let result = Array.init l1 ~f:(fun i -> let c1 = String.get w1 i and c2 = String.get wordRef i in let state = if Char.equal c1 c2 then Validity.Wellplaced else if CharSet.mem c1 (snd ref) then Validity.Misplaced else Validity.Missing in state ) in Some result let get_entropy max_element words_number arr = let entropy = ref 0. in for idx = 0 to max_element - 1 do let content = Float.of_int (Bigarray.Array1.get arr idx) in if content > 0. then let ratio = content /. words_number in entropy := !entropy -. (ratio *. Float.log2 ratio) done; entropy let analyse : int -> catalog:Wordlist.t -> Wordlist.t -> t = fun base ~catalog words -> (* If we have only two elements, just pick one of them *) if Wordlist.list_size words <= 2 then (0.5, Option.get @@ Wordlist.pick words) else let words_number = Float.of_int (Wordlist.list_size catalog) in (* Each result from the game is stored as an integer, and we create an array with as many elements as we have possibilities. *) let max_element = Float.to_int @@ (Validity.elements ** Float.of_int base) in let arr = Bigarray.Array1.create Bigarray.Int Bigarray.C_layout max_element in match Wordlist.pick words with | None -> (0., "") | Some v -> let score, word, _ = Seq.fold_left (fun (score, word, already_picked) word_ref -> (* Reinitialize the array (we use the same in the successive iterations) *) Bigarray.Array1.fill arr 0; let set_ref = String.to_seq word_ref |> CharSet.of_seq in Seq.iter (fun w2 -> let result = compare_words ~ref:(word_ref, set_ref) w2 in match result with | None -> () | Some r -> let idx = Validity.index_of_result r in let content = Bigarray.Array1.get arr idx in Bigarray.Array1.set arr idx (succ content) ) (Wordlist.words words); let entropy = get_entropy max_element words_number arr in (* If get more information that we had, use this word. Choose this word to if it belongs to the final list (it gives a small chance to pick the right oneā€¦) *) let is_better, already_picked = if !entropy > score then (true, false) else if (not already_picked) && !entropy == score && Wordlist.mem word_ref words then (true, true) else (false, already_picked) in if is_better then ( Printf.printf "Q. of information when selecting %s : %f\n" word_ref !entropy; (!entropy, word_ref, already_picked) ) else (score, word, already_picked) ) (-0., v, false) (Wordlist.words catalog) in (score, word)