diff --git a/bin/day2424.ml b/bin/day2424.ml new file mode 100644 index 0000000..064d190 --- /dev/null +++ b/bin/day2424.ml @@ -0,0 +1,95 @@ +type op = And | Or | Xor +type gate = { in1 : string; in2 : string; op : op; out : string } + +module StringMap = Map.Make (String) + +let get_wire_value str = + let re = Str.regexp {|\(.+\): \([01]\)|} in + let _ = Str.search_forward re str 0 in + let v = if Str.matched_group 2 str = "0" then 0 else 1 in + (Str.matched_group 1 str, v) + +let get_gate_op = function + | "AND" -> And + | "OR" -> Or + | "XOR" -> Xor + | _ -> failwith "get_gate_op" + +let[@warning "-32"] string_of_op = function + | And -> "AND" + | Or -> "OR" + | Xor -> "XOR" + +let get_gate_config str = + let re = Str.regexp {|\(.+\) \(AND\|OR\|XOR\) \(.+\) -> \(.+\)|} in + let _ = Str.search_forward re str 0 in + let in1 = Str.matched_group 1 str in + let op = get_gate_op (Str.matched_group 2 str) in + let in2 = Str.matched_group 3 str in + let out = Str.matched_group 4 str in + { in1; in2; op; out } + +let initial_wires_of_strings = + let rec impl acc = function + | "" :: t -> (acc, t) + | h :: t -> + let wire, v = get_wire_value h in + impl (StringMap.add wire v acc) t + | _ -> failwith "initial_wires_of_strings" + in + impl StringMap.empty + +let gates_from_strings = + let rec impl acc = function + | [] -> acc + | h :: t -> impl (get_gate_config h :: acc) t + in + impl [] + +let config_of_file fname = + let lst = Aoc.strings_of_file fname in + let wires, lst = initial_wires_of_strings lst in + let gates = gates_from_strings lst in + (wires, gates) + +let process_gate wires gate = + match + ( gate.op, + StringMap.find_opt gate.in1 wires, + StringMap.find_opt gate.in2 wires ) + with + | And, Some a, Some b -> if a = 1 && b = 1 then Some 1 else Some 0 + | Or, Some a, Some b -> if a = 1 || b = 1 then Some 1 else Some 0 + | Xor, Some a, Some b -> if a <> b then Some 1 else Some 0 + | _, _, _ -> None + +let process_gates wires = + let rec impl wires acc = function + | [] -> (wires, acc) + | h :: t -> begin + match process_gate wires h with + | None -> impl wires (h :: acc) t + | Some x -> + let wires = StringMap.add h.out x wires in + impl wires acc t + end + in + impl wires [] + +let rec repeat_to_end wires gates = + let wires, gates = process_gates wires gates in + if gates = [] then wires + else begin + Printf.printf "Gate size: %d\n" (List.length gates); + repeat_to_end wires gates + end + +let calc_value = Fun.flip (List.fold_right (fun x acc -> x + (2 * acc))) 0 + +let part1 (wires, gates) = + let wires = repeat_to_end wires gates in + let zmap = StringMap.filter (fun k _ -> k.[0] = 'z') wires in + let zlst = StringMap.bindings zmap |> List.map snd in + calc_value zlst + +let _ = Aoc.main config_of_file [ (string_of_int, part1) ] diff --git a/bin/dune b/bin/dune index 6f1ef9a..23c4cc1 100644 --- a/bin/dune +++ b/bin/dune @@ -22,7 +22,8 @@ day2420 day2421 day2422 - day2423) + day2423 + day2424) (names day2401 day2402 @@ -46,5 +47,6 @@ day2420 day2421 day2422 - day2423) + day2423 + day2424) (libraries str aoc))