module type Part = sig type t val parse_line: string -> t val ok: t -> bool end let parse_line' f str = Scanf.sscanf str "%d - %d %c : %s" f module Part1: Part = struct type t = {min: int; max: int; char: char; pass: string} let parse_line = parse_line' (fun min max char pass -> {min; max; char; pass}) let count c str = let res = ref 0 in String.iter (fun d -> if c = d then incr res) str; !res let ok {min; max; char; pass} = let res = count char pass in res >= min && res <= max end module Part2: Part = struct type t = {pos1: int; pos2: int; char: char; pass: string} let parse_line = parse_line' (fun pos1 pos2 char pass -> {pos1 = pos1 - 1; pos2 = pos2 - 1; char; pass}) let ok {pos1; pos2; char; pass} = (pass.[pos1] = char) <> (pass.[pos2] = char) end module type Main = sig val run: string -> unit end module Main(P: Part)(): Main = struct open P let count_all = ref 0 let count_ok = ref 0 let check l = incr count_all; if ok l then incr count_ok let run input = Bracket.infile_iter_lines input ~line:parse_line ~iter:check; Printf.printf "%d out of %d ok\n" !count_ok !count_all end let main' (module P: Part) = let module M = Main(P)() in M.run let mains = [|main' (module Part1); main' (module Part2)|] let main = function | [part; input] -> mains.(int_of_string part - 1) input | _ -> Usage.exit "2 " let%expect_test "part 1" = mains.(0) "../../data/day2"; [%expect{| 607 out of 1000 ok |}] let%expect_test "part 2" = mains.(1) "../../data/day2"; [%expect{| 321 out of 1000 ok |}]