diff --git a/day4.ml b/day4.ml new file mode 100644 index 0000000..5eb1ed8 --- /dev/null +++ b/day4.ml @@ -0,0 +1,74 @@ +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 map = String.split_on_char ' ' s + |> List.map (String.split_on_char ':') + |> List.map (fun [k; v] -> (k, v)) in + try Some + { byr = int_of_string (List.assoc "byr" map) + ; iyr = int_of_string (List.assoc "iyr" map) + ; eyr = int_of_string (List.assoc "eyr" map) + ; hgt = List.assoc "hgt" map + ; hcl = List.assoc "hcl" map + ; ecl = List.assoc "ecl" map + ; pid = List.assoc "pid" map + ; cid = List.assoc_opt "cid" map + } + 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 filename |> part1)) +let () = + print_endline (string_of_int (read_file_rev filename |> part2))