let get_one_line file = try Some (input_line file) with End_of_file -> None let get_lines file = let rec input lines = match get_one_line file with Some line -> input (line :: lines) | None -> List.rev lines in input [] (* --- *) type password_set = { min : int; max : int; chr : char; pw : string };; let line_to_set line = (* convert a line from the file into a password_set *) let [rng; chr; pw] = String.split_on_char ' ' line in (* split on spaces *) let chr = String.get chr 0 in (* strip colon and convert to char *) let [min; max] = List.map int_of_string (String.split_on_char '-' rng) in (* pull out the min and max from the range, map to Int *) { min; max; chr; pw } (* stolen from SO.. *) let explode s = (* convert a string to a list of chars *) let rec exp i l = if i < 0 then l else exp (i - 1) (s.[i] :: l) in exp (String.length s - 1) [];; let char_count el str = List.length (List.filter (fun c -> c == el) (explode str)) let is_valid_day1_password set = let count = char_count set.chr set.pw in (*Printf.printf "%s %c count: %i min: %i, max: %i, in range: %b\n" set.pw set.chr count set.min set.max (count >= set.min && count <= set.max);*) count >= set.min && count <= set.max let is_valid_day2_password set = let is_valid = ((String.get set.pw (set.min-1)) == set.chr) <> ((String.get set.pw (set.max-1)) == set.chr) in (*Printf.printf "%s %c min: %i, max: %i, char-at-min: %c, char-at-max: %c, valid: %b\n" set.pw set.chr set.min set.max (String.get set.pw (set.min-1)) (String.get set.pw (set.max-1)) is_valid;*) is_valid let file = "day2.txt" let channel = open_in(file) let lines = get_lines channel let sets = List.map line_to_set lines let valid_day1_passwords = List.filter is_valid_day1_password sets;; Printf.printf "valid day1 password count: %i\n" (List.length valid_day1_passwords) let valid_day2_passwords = List.filter is_valid_day2_password sets;; Printf.printf "valid day2 password count: %i\n" (List.length valid_day2_passwords)