aoc2020/day2.ml

71 lines
1.6 KiB
OCaml

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 <part> <infile>"
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 |}]