|
1 | 1 | open Utils |
2 | 2 |
|
3 | | -let day10 input = |
4 | | - ("TODO", "TODO") |
| 3 | +let parse_int_list s = String.split_on_char ',' s |> List.map int_of_string |
| 4 | +let parse_lights s = |
| 5 | + String.fold_right (fun c a -> match c with |
| 6 | + | '#' -> 2 * a + 1 |
| 7 | + | '.' -> 2 * a |
| 8 | + | _ -> a) s 0 |
| 9 | +let parse_buttons s = |
| 10 | + String.split_on_char ' ' (trim_end_nl s) |
| 11 | + |> List.map (fun s -> |
| 12 | + parse_int_list (String.sub s 1 (String.length s - 2)) |
| 13 | + |> List.fold_left (fun a d -> a + Int.shift_left 1 d) 0) |
| 14 | + |
| 15 | +let parse input = |
| 16 | + let input = trim_end_nl input in |
| 17 | + String.split_on_char '\n' input |
| 18 | + |> List.map (fun l -> |
| 19 | + let a, b = string_split_once " " l in |
| 20 | + let b, c = string_split_once "{" b in |
| 21 | + let c = String.sub c 0 (String.length c - 1) in |
| 22 | + |
| 23 | + String.length a - 2, |
| 24 | + parse_lights a, |
| 25 | + parse_buttons b |> Array.of_list, |
| 26 | + parse_int_list c |> Array.of_list) |
| 27 | + |
| 28 | +type 'a control = Continue of 'a | Stop of 'a |
| 29 | + |
| 30 | +let select i a = |
| 31 | + let rec aux i o = |
| 32 | + if i = 0 then [] |
| 33 | + else if Int.logand i 1 = 1 then a.(o) :: aux (Int.shift_right i 1) (o + 1) |
| 34 | + else aux (Int.shift_right i 1) (o + 1) in |
| 35 | + aux i 0 |
| 36 | + |
| 37 | +let bin_of_int n = |
| 38 | + if n = 0 then "0" else |
| 39 | + let rec aux n = if n = 0 then "" else aux (n / 2) ^ if n mod 2 = 0 then "0" else "1" in |
| 40 | + aux n |
| 41 | + |
| 42 | +let turn_on (n, lights, buttons, _) = |
| 43 | + let k = Array.length buttons in |
| 44 | + let m = Int.shift_left 1 k in |
| 45 | + range 0 (m - 1) |
| 46 | + |> List.filter (fun i -> List.fold_left Int.logxor 0 (select i buttons) = lights) |
| 47 | + |> List.map Ocaml_intrinsics.Int.count_set_bits |
| 48 | + |> List.fold_left min (k + 1) |
5 | 49 |
|
| 50 | +let fold_bin f acc bin = |
| 51 | + let rec aux off bin acc = |
| 52 | + if bin = 0 then acc |
| 53 | + else |
| 54 | + let skip = Ocaml_intrinsics.Int.count_trailing_zeros bin in |
| 55 | + aux (off + skip + 1) (Int.shift_right bin (skip + 1)) (f acc (off + skip)) |
| 56 | + in aux 0 bin acc |
6 | 57 |
|
| 58 | +let string_of_button b = "(" ^ (fold_bin (fun a i -> string_of_int i :: a) [] b |> String.concat ",") ^ ")" |
| 59 | +let string_of_buttons bs = String.concat " " @@ List.map string_of_button @@ Array.to_list bs |
| 60 | +let string_of_joltages jolts = "{" ^ (String.concat " " @@ List.map string_of_int @@ Array.to_list jolts) ^ "}" |
| 61 | + |
| 62 | +let push_button b jolts = |
| 63 | + fold_bin (fun _ i -> jolts.(i) <- jolts.(i) - 1) () b |
| 64 | + |
| 65 | +let can_press b jolts = fold_bin (fun f i -> f && jolts.(i) >= 1) true b |
| 66 | + |
| 67 | +let min_joltage (_, _, buttons, joltage) = |
| 68 | + let k = Array.length buttons in |
| 69 | + let constraints = Array.mapi |
| 70 | + (fun i j -> |
| 71 | + range 0 (k - 1) |
| 72 | + |> List.filter (fun l -> Int.logand buttons.(l) (Int.shift_left 1 i) = 1), |
| 73 | + j |
| 74 | + ) joltage in |
| 75 | + failwith "" |
| 76 | + |
| 77 | +let solve_part1 machines = |
| 78 | + List.map turn_on machines |> List.fold_left (+) 0 |
| 79 | +let solve_part2 machines = |
| 80 | + List.map min_joltage machines |> List.fold_left (+) 0 |
| 81 | + |
| 82 | +let day10 input = |
| 83 | + let machines = parse input in |
| 84 | + let part1 = solve_part1 machines in |
| 85 | + let part2 = solve_part2 machines in |
| 86 | + (string_of_int part1, string_of_int part2) |
0 commit comments