open Printf;; open String;; open Map;; 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 is_not_empty lst = match lst with | [] -> false | _ -> true let rec parse_int_list sep str = let list1 = (List.filter (fun a -> length a != 0) (String.split_on_char sep str)) in List.map int_of_string list1 module IntMap = Map.Make(Int) module IntSet = Set.Make(Int) let rec parse_ordering lines must_be_before = match lines with | head :: tail -> if length head > 0 then let elems = parse_int_list '|' head in let e1 = List.hd elems in let e2 = List.nth elems 1 in let update_fun prev = match prev with | Some set -> Some (IntSet.add e1 set) | None -> Some (IntSet.add e1 IntSet.empty) in let new_map = IntMap.update e2 update_fun must_be_before in parse_ordering tail new_map else (tail, must_be_before) | _ -> (lines, must_be_before) let parse in_file = let lines = list_of_lines in_file in let lines_rest, must_be_before = parse_ordering lines IntMap.empty in let entries = List.map (fun str -> List.rev @@ parse_int_list ',' str) lines_rest in (must_be_before, entries) let rec is_good must_be_before already_appeared entry = match entry with | head :: tail -> begin let new_already_appeared = IntSet.add head already_appeared in match IntMap.find_opt head must_be_before with | Some set -> let intersect = IntSet.inter set new_already_appeared in if IntSet.is_empty intersect then is_good must_be_before new_already_appeared tail else false | None -> is_good must_be_before new_already_appeared tail end | _ -> true let rec summarise_good_entries must_be_before entries = match entries with | head :: tail -> if is_good must_be_before IntSet.empty head then List.nth head (List.length head / 2) + summarise_good_entries must_be_before tail else summarise_good_entries must_be_before tail | _ -> 0 let () = let f = open_in "input.txt" in let must_be_before, entries = parse f in let result = summarise_good_entries must_be_before entries in printf "%d\n" result