|
| 1 | +open Utils |
| 2 | + |
| 3 | +let parse input = |
| 4 | + let len = String.length input in |
| 5 | + String.split_on_char ',' (String.sub input 0 (len - 1)) |
| 6 | + |> List.map (fun s -> ( |
| 7 | + let l = String.length s in |
| 8 | + let i = String.index_from s 0 '-' in |
| 9 | + (int_of_string (String.sub s 0 i), int_of_string (String.sub s (i+1) (l - i - 1))) |
| 10 | + )) |
| 11 | + |
| 12 | +let rec concat_n n x s = |
| 13 | + if n = 0 then 0 |
| 14 | + else (concat_n (n - 1) x s) * s + x |
| 15 | + |
| 16 | +(* Add all the passwords that are a sequence of d digits repeating rep times in the [a; b] range to list *) |
| 17 | +let invalid_in_range_length_repeat list a b d rep = |
| 18 | + let shift = p10 d in |
| 19 | + let limit = p10 (d * rep) in |
| 20 | + let start = max (a / (p10 (d * rep - d))) (shift / 10) in |
| 21 | + let rec aux acc x = |
| 22 | + let r = concat_n rep x shift in |
| 23 | + if r <= b && r < limit then if r >= a then ( |
| 24 | + aux (r :: acc) (x + 1) |
| 25 | + ) else aux acc (x + 1) else acc |
| 26 | + in |
| 27 | + aux list start |
| 28 | +(* Add all the passwords that are a sequence of d digits repeated at least twice in the [a; b] range to list *) |
| 29 | +let invalid_in_range_length ?(part1=true) list a b d = |
| 30 | + let da, db = ilog10 a + 1, ilog10 b + 1 in |
| 31 | + let rep_min = max ((da + d - 1) / d) 2 in |
| 32 | + let rep_max = if part1 then 2 else db / d in |
| 33 | + let rec aux list rep = |
| 34 | + if rep > rep_max then list |
| 35 | + else aux (invalid_in_range_length_repeat list a b d rep) (rep + 1) |
| 36 | + in |
| 37 | + aux list rep_min |
| 38 | + |
| 39 | +(* Add all the passwords that are a sequence of digits repeated at least twice in the [a; b] range to list *) |
| 40 | +let invalid_in_range ?(part1=true) (a, b) = |
| 41 | + let db = ilog10 b + 1 in |
| 42 | + let rec aux list d = if d > (db / 2) then list else ( |
| 43 | + aux (invalid_in_range_length ~part1: part1 list a b d) (d+1)) in |
| 44 | + aux [] 1 |> List.sort_uniq compare |> List.fold_left (+) 0 |
| 45 | + |
| 46 | +let solve_part1 = List.fold_left (fun a r -> a + invalid_in_range r) 0 |
| 47 | +let solve_part2 = List.fold_left (fun a r -> a + invalid_in_range ~part1: false r) 0 |
| 48 | + |
| 49 | +let day02 input = |
| 50 | + let ranges = parse input in |
| 51 | + let part1 = solve_part1 ranges in |
| 52 | + let part2 = solve_part2 ranges in |
| 53 | + (string_of_int part1, string_of_int part2) |
| 54 | + |
| 55 | + |
0 commit comments