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))