diff options
Diffstat (limited to 'lib/day10.ml')
| -rw-r--r-- | lib/day10.ml | 110 |
1 files changed, 110 insertions, 0 deletions
diff --git a/lib/day10.ml b/lib/day10.ml new file mode 100644 index 0000000..06be150 --- /dev/null +++ b/lib/day10.ml @@ -0,0 +1,110 @@ +(* + * SPDX-FileCopyrightText: Copyright 2025 Alexandre Jesus <https://adbjesus.com> + * + * SPDX-License-Identifier: GPL-3.0-or-later + *) + +open Glpk.C.Functions +open Glpk.C.Types + +type machine = { lights : int; buttons : int list list; ibuttons : int list; joltage : int list } + +let parse_machine s = + let a = String.split_on_char ' ' s in + let lights = + List.hd a + |> String.fold_left + (fun acc c -> + match c with + | '.' -> acc * 2 + | '#' -> (acc * 2) + 1 + | '[' | ']' -> acc + | _ -> failwith (Printf.sprintf "Wrong data: %s" s)) + 0 + in + let nlights = String.length (List.hd a) - 2 in + let parse_button s = + if s.[0] = '(' then + let sub = String.sub s 1 (String.length s - 2) in + Some (String.split_on_char ',' sub |> List.map int_of_string) + else None + in + let parse_ibutton b = + b + |> List.map (fun v -> + let v = nlights - v - 1 in + Int.shift_left 1 v) + |> List.fold_left ( + ) 0 + in + let buttons = List.filter_map parse_button (List.tl a) in + let ibuttons = List.map parse_ibutton buttons in + let joltage = List.rev a |> List.hd in + let joltage = String.sub joltage 1 (String.length joltage - 2) in + let joltage = String.split_on_char ',' joltage |> List.map int_of_string in + { lights; buttons; ibuttons; joltage } + +let print_machines machines = + List.iter + (fun machine -> + Printf.printf "%d ->" machine.lights; + List.iter (Printf.printf " %d") machine.ibuttons; + Printf.printf " ->"; + List.iter (Printf.printf " %d") machine.joltage; + Printf.printf "\n") + machines + +let parse ch = ch |> In_channel.input_lines |> List.map parse_machine + +let part1 ch = + let machines = parse ch in + let solve machine = + let rec fn v c bs = + if v = machine.lights then c + else + match bs with + | [] -> Int.max_int + | b :: bt -> Int.min (fn (Int.logxor v b) (c + 1) bt) (fn v c bt) + in + fn 0 0 machine.ibuttons + in + List.map solve machines |> List.fold_left ( + ) 0 |> Printf.printf "%d\n" + +let part2 ch = + let machines = parse ch in + let solve machine = + let p = glp_create_prob () in + let n = List.length machine.joltage in + let m = List.length machine.buttons in + glp_set_obj_dir p glp_min; + glp_add_rows p n; + machine.joltage + |> List.to_seq + |> Seq.map Float.of_int + |> Seq.iteri (fun i v -> glp_set_row_bnds p (i + 1) glp_fx v v); + glp_add_cols p m; + for i = 1 to m do + glp_set_col_bnds p i glp_lo 0.0 0.0; + glp_set_col_kind p i glp_iv; + glp_set_obj_coef p i 1.0; + done; + (machine.buttons + |> List.iteri + (fun i b -> + let len = List.length b in + let ind = 0 :: (List.map (( + ) 1) b) |> Ctypes.CArray.of_list Ctypes.int in + let vals = Ctypes.CArray.make Ctypes.double ~initial:1.0 (len + 1) in + glp_set_mat_col p (i + 1) len (Ctypes.CArray.start ind) (Ctypes.CArray.start vals) + )); + glp_simplex p Ctypes.null; + glp_intopt p Ctypes.null; + (if (glp_mip_status p) <> glp_opt then + failwith "Infeasible ILP"); + let ans = glp_mip_obj_val p in + glp_delete_prob p; + Int.of_float (ans +. 0.1) + in + ignore (glp_term_out glp_off); + machines + |> List.map solve + |> List.fold_left ( + ) 0 + |> Printf.printf "%d\n" |
