open Printf;; let rec list_of_lines in_file = try let line = input_line in_file in line :: list_of_lines(in_file) with End_of_file -> close_in in_file; [] let rec split_on_empty_line lines = match lines with | head :: tail -> if String.length head = 0 then ([], tail) else let rest_of_list, remaining_lines = split_on_empty_line tail in (head :: rest_of_list, remaining_lines) | _ -> ([], lines) let rec split_by_empty_lines lines = if List.length lines = 0 then [] else let line, remainder = split_on_empty_line lines in line :: split_by_empty_lines remainder let rec sum_columns_inner arr lst = match lst with | head :: tail -> String.iteri (fun i v -> if v = '#' then arr.(i) <- arr.(i) + 1) head; sum_columns_inner arr tail | _ -> () let sum_columns elem_len lst = let arr = Array.make elem_len 0 in sum_columns_inner arr lst; Array.to_list arr let parse_schematic_fold (locks, keys) schematic = match schematic with | head :: tail -> begin let heights = match (List.rev tail) with | last :: rest -> sum_columns (String.length head) rest | _ -> raise (Invalid_argument "Invalid schematic") in if head.[0] = '.' then (locks, heights :: keys) else (heights :: locks, keys) end | _ -> raise (Invalid_argument "Invalid schematic") let rec heights_fit key lock = match (key, lock) with | (head1 :: tail1, head2:: tail2) -> if head1 + head2 > 5 then false else heights_fit tail1 tail2 | ([], []) -> true | _ -> raise (Invalid_argument "Key lengths don't match") let () = let f = open_in "input.txt" in let schematics = list_of_lines f |> split_by_empty_lines in let locks, keys = List.fold_left parse_schematic_fold ([], []) schematics in let result = locks |> List.map (fun lock -> keys |> List.map (fun key -> if heights_fit key lock then 1 else 0) |> List.fold_left Int.add 0) |> List.fold_left Int.add 0 in printf "%d\n" result