90 lines
2.8 KiB
OCaml
90 lines
2.8 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 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
|
|
|
|
(* Ordering map is a map that indexes int and maps it into a set of ints,
|
|
the indexed element must be before each of the elements of the mapped set*)
|
|
module IntMap = Map.Make(Int)
|
|
module IntSet = Set.Make(Int)
|
|
|
|
let rec parse_ordering lines ordering_map =
|
|
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 ordering_map in
|
|
parse_ordering tail new_map
|
|
else
|
|
(tail, ordering_map)
|
|
| _ -> (lines, ordering_map)
|
|
|
|
let parse in_file =
|
|
let lines = list_of_lines in_file in
|
|
let lines_rest, ordering_map = parse_ordering lines IntMap.empty in
|
|
let entries = List.map (fun str -> List.rev @@ parse_int_list ',' str) lines_rest in
|
|
(ordering_map, entries)
|
|
|
|
let rec is_good ordering_map already_appeared entry =
|
|
match entry with
|
|
| head :: tail -> begin
|
|
let new_already_appeared = IntSet.add head already_appeared in
|
|
match IntMap.find_opt head ordering_map with
|
|
| Some set ->
|
|
let intersect = IntSet.inter set new_already_appeared in
|
|
if IntSet.is_empty intersect then
|
|
is_good ordering_map new_already_appeared tail
|
|
else
|
|
false
|
|
| None ->
|
|
is_good ordering_map new_already_appeared tail
|
|
end
|
|
| _ -> true
|
|
|
|
let get_middle_element lst =
|
|
List.nth lst (List.length lst / 2)
|
|
|
|
let ordering_less_than ordering_map x1 x2 =
|
|
match IntMap.find_opt x1 ordering_map with
|
|
| Some x1_set -> x1_set |> IntSet.find_opt x2 |> Option.is_some
|
|
| None -> false
|
|
|
|
let ordering_function ordering_map x1 x2 =
|
|
if ordering_less_than ordering_map x1 x2 then (-1)
|
|
else if ordering_less_than ordering_map x2 x1 then 1
|
|
else 0
|
|
|
|
let fix_ordering ordering_map lst =
|
|
List.sort (ordering_function ordering_map) lst
|
|
|
|
let rec summarise_entries ordering_map acc elem =
|
|
if is_good ordering_map IntSet.empty elem then
|
|
let v = get_middle_element elem in
|
|
(fst acc + v, snd acc)
|
|
else
|
|
let new_elem = fix_ordering ordering_map elem in
|
|
let v = get_middle_element new_elem in
|
|
(fst acc, snd acc + v)
|
|
|
|
let () =
|
|
let f = open_in "input.txt" in
|
|
let ordering_map, entries = parse f in
|
|
let result, result2 = List.fold_left (summarise_entries ordering_map) (0, 0) entries in
|
|
printf "%d\n%d\b" result result2 |