open Base type line = { lower_bound : int; upper_bound : int; char : char; password : string; } let parse_password line = match String.split line ~on:' ' with | [range; char; password] -> (match String.lsplit2 range ~on:'-' with | Some (left_str, right_str) -> { lower_bound = Int.of_string(left_str); upper_bound = Int.of_string(right_str); char = String.get char 0; password = password } | None -> failwith (Printf.sprintf "Ill-formed range: %s" range)) | _ -> failwith (Printf.sprintf "Ill-formed line: %s" line) let parse_file filename = let open Stdio.In_channel in let lines = with_file ~f:input_lines filename in List.map ~f:parse_password lines let old_validate line = let char_count = String.count ~f:(fun c -> phys_equal c line.char) line.password in char_count >= line.lower_bound && char_count <= line.upper_bound let new_validate line = let first_letter = String.get line.password (line.lower_bound - 1) in let second_letter = String.get line.password (line.upper_bound - 1) in Bool.(<>) (Char.(=) first_letter line.char) (Char.(=) second_letter line.char)