77 lines
2.2 KiB
OCaml
77 lines
2.2 KiB
OCaml
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 |