46 lines
1.4 KiB
OCaml
46 lines
1.4 KiB
OCaml
|
let read_file_rev name =
|
||
|
let ic = open_in name in
|
||
|
let try_read () =
|
||
|
try Some (input_line ic)
|
||
|
with End_of_file -> None in
|
||
|
let rec loop acc =
|
||
|
match try_read () with
|
||
|
| Some s -> loop (s::acc)
|
||
|
| None -> close_in ic; acc in
|
||
|
loop []
|
||
|
|
||
|
|
||
|
let count_good_passwords f l =
|
||
|
let is_conforming f entry =
|
||
|
let [term; pass] = String.split_on_char ':' entry in
|
||
|
let [rep; letter] = String.split_on_char ' ' term in
|
||
|
let [minr; maxr] = List.map int_of_string (String.split_on_char '-' rep) in
|
||
|
f pass minr maxr letter.[0] in
|
||
|
List.map (is_conforming f) l
|
||
|
|> List.map (fun b -> if b then 1 else 0)
|
||
|
|> List.fold_left (+) 0
|
||
|
|
||
|
|
||
|
let part1_f pass minr maxr letter =
|
||
|
let count = List.length (String.split_on_char letter pass) - 1 in
|
||
|
minr <= count && count <= maxr
|
||
|
|
||
|
let part2_f pass first second letter =
|
||
|
let position_matches pass pos letter =
|
||
|
match String.get pass pos with
|
||
|
| c -> c = letter
|
||
|
| _ -> false in
|
||
|
(position_matches pass first letter) <> (position_matches pass second letter)
|
||
|
|
||
|
|
||
|
let do_count filename = function
|
||
|
| 1 -> read_file_rev filename |> count_good_passwords part1_f
|
||
|
| 2 -> read_file_rev filename |> count_good_passwords part2_f
|
||
|
|
||
|
|
||
|
let () =
|
||
|
print_endline (string_of_int (do_count "day2.input" 1))
|
||
|
|
||
|
let () =
|
||
|
print_endline (string_of_int (do_count "day2.input" 2))
|