@@ 0,0 1,51 @@
+open Printf
+open Scanf
+
+let rec rest_of_entry chan =
+ match (try (input_line chan) with End_of_file -> "") with
+ | "" -> ""
+ | line -> line ^ " " ^ (rest_of_entry chan)
+
+let valid_field fd_name contents =
+ let in_range lb ub num = lb <= num && num <= ub in
+ let eye_colors = [ "amb"; "blu"; "brn"; "gry"; "grn"; "hzl"; "oth" ] in
+ try match (fd_name, contents) with
+ | "byr", s -> sscanf s "%4d%!" (in_range 1920 2002)
+ | "iyr", s -> sscanf s "%4d%!" (in_range 2010 2020)
+ | "eyr", s -> sscanf s "%4d%!" (in_range 2020 2030)
+ | "hgt", s -> sscanf s "%d%2s%!" (fun d s ->
+ (in_range 150 193 d) && s = "cm" || (in_range 59 76 d) && s = "in")
+ | "ecl", s -> List.mem s eye_colors
+ | "hcl", s -> String.length s = 7 && sscanf s "#%_6x%!" true
+ | "pid", s -> String.length s = 9 && sscanf s "%_9d%!" true
+ | _ -> false
+ with e -> false
+
+let is_valid2 ent = List.for_all (fun e -> sscanf e "%[^:]:%s" valid_field) ent
+let filter_cid ent = List.filter (fun f -> "cid:" <> String.sub f 0 4) ent
+
+let rec read_from chan =
+ let to_list str = List.filter ((<>) "") (String.split_on_char ' ' str) in
+ match (try Some (input_line chan) with End_of_file -> None) with
+ | Some line ->
+ let entry_str = line ^ " " ^ (rest_of_entry chan) in
+ (to_list entry_str) :: read_from chan
+ | None -> []
+
+let _ =
+ let in_chan = open_in "day_4.in" in
+
+ let lst = read_from in_chan in
+ close_in in_chan;
+
+ let nocid = lst |> List.map filter_cid in
+ let valid1 = nocid |> List.filter (fun e -> List.length e = 7) in
+
+ let out_chan1 = open_out "day_4_1.out" in
+ valid1 |> List.length |> fprintf out_chan1 "%d\n";
+ close_out out_chan1;
+
+ let out_chan2 = open_out "day_4_2.out" in
+ valid1 |> List.filter is_valid2 |> List.length |> fprintf out_chan2 "%d\n" ;
+ close_out out_chan2;
+ ()