open Core (* Take text input from file and process accordingly *) let process_input input = String.split_lines input |> Array.of_list (* Fill in solutions for each part *) let count_unique_chars word = let counter = Hashtbl.create (module Char) in let update_counter x = Hashtbl.update counter x ~f:(function | Some num -> succ num | None -> 1) in String.iter word ~f:update_counter; counter let part_1 input = let ids = process_input input in let counts = Array.map ids ~f:count_unique_chars in let has_count hashtbl count = Hashtbl.exists hashtbl ~f:(fun x -> count = x) in let (count2, count3) = Array.fold ~init:(0, 0) ~f:(fun (a, b) x -> ((if has_count x 2 then succ a else a), (if has_count x 3 then succ b else b))) counts in count2 * count3 let string_diff string1 string2 = String.foldi string1 ~init:[] ~f:(fun index accum ch -> if compare_char ch string2.[index] <> 0 then index::accum else accum) let part_2 input = let ids = process_input input in let pairs = Array.cartesian_product ids ids |> Array.filter ~f:(fun (a, b) -> compare_string a b <> 0) |> Array.find ~f:(fun (a, b) -> string_diff a b |> List.length = 1) in match pairs with | Some (a, b) -> String.foldi a ~init:"" ~f:(fun index acc ch -> if compare_char ch b.[index] = 0 then String.concat [acc; String.make 1 ch] else acc) | None -> ""