aoc2020/day4.ml

73 lines
2.6 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 line =
match try_read () with
| Some "" -> loop ((String.trim line)::acc) ""
| Some s -> loop acc (String.concat " " [line; s])
| None -> close_in ic; (String.trim line)::acc in
loop [] ""
type passport =
{ byr: int (* Birth Year *)
; iyr: int (* Issue Year*)
; eyr: int (* Expiration Year *)
; hgt: string (* Height *)
; hcl: string (* Hair Color *)
; ecl: string (* Eye Color *)
; pid: string (* Passport ID *)
; cid: string option (* Country ID *)
}
let passport_of_string s =
let hmap = String.split_on_char ' ' s
|> List.map (String.split_on_char ':')
|> List.filter_map (fun el -> match el with [k; v] -> Some (k, v) | _ -> None) in
try Some
{ byr = int_of_string (List.assoc "byr" hmap)
; iyr = int_of_string (List.assoc "iyr" hmap)
; eyr = int_of_string (List.assoc "eyr" hmap)
; hgt = List.assoc "hgt" hmap
; hcl = List.assoc "hcl" hmap
; ecl = List.assoc "ecl" hmap
; pid = List.assoc "pid" hmap
; cid = List.assoc_opt "cid" hmap
}
with Not_found -> None
let is_height_ok pspt =
try
let h = int_of_string (List.hd (String.split_on_char 'c' pspt.hgt)) in
h >= 150 && h <= 193
with _ ->
try
let h = int_of_string (List.hd (String.split_on_char 'i' pspt.hgt)) in
h >= 59 && h <= 76
with _ -> false
let part1 l =
List.filter_map passport_of_string l |> List.length
let part2 l =
List.filter_map passport_of_string l
|> List.filter (fun p -> p.byr >= 1920 && p.byr <= 2002
&& p.iyr >= 2010 && p.iyr <= 2020
&& p.eyr >= 2020 && p.eyr <= 2030
&& Str.string_match (Str.regexp {|^[0-9]+\(cm\|in\)$|}) p.hgt 0
&& is_height_ok p
&& Str.string_match (Str.regexp {|^#[0-9a-f]+$|}) p.hcl 0
&& String.length p.hcl = 7
&& List.mem p.ecl ["amb"; "blu"; "brn"; "gry"; "grn"; "hzl"; "oth"]
&& String.length p.pid = 9
&& Str.string_match (Str.regexp {|^[0-9]+$|}) p.pid 0)
|> List.length
let () = print_endline (string_of_int (read_file_rev "day4.input" |> part1))
let () = print_endline (string_of_int (read_file_rev "day4.input" |> part2))