(* Common util. Should probably put this in a module or something.. *) let get_one_line file = try Some (input_line file) with End_of_file -> None let get_lines file = let rec input lines = match get_one_line file with Some line -> input (line :: lines) | None -> List.rev lines in input [] let read_file file = let channel = open_in(file) in get_lines channel let (<<) f g x = f(g(x)) let (>>) f g x = g(f(x)) let rec take n (x :: xs) = (* take the first n elements *) match n with | 0 -> [] | n -> x :: (take (n-1) xs) let rec drop n l = (* drop the first n elemnts *) match n with | 0 -> l | n -> drop (n-1) @@ List.tl l let sub_list start length = (* sub list from start *) take length >> drop start let list_sum = List.fold_left (+) 0 let list_max l = List.fold_left (fun acc x -> if x > acc then x else acc) (List.hd l) l let list_min l = List.fold_left (fun acc x -> if x < acc then x else acc) (List.hd l) l let range start len = (* makes a new list from start with length len *) List.init len (fun x -> x + 0) |> List.map (fun x -> x + start) let flip f x y = f y x (* --- *) let has_adders l target = (* do any 2 elements of l add up to target *) match List.find_opt (fun x -> match List.find_opt (fun y -> x != y && x + y = target) l with | Some _ -> true | None -> false ) l with | Some _ -> true | None -> false let rec first_without_adders pre lines = let x :: xs = lines in (* match out the head and tail *) let cur = List.nth lines pre in (* grab the first row after the preamble *) let sub = take pre lines in (* grab the preamble sublist *) if has_adders sub cur (* chechk for adders *) then first_without_adders pre xs (* if it has adders, recurse with the tail of the original list *) else cur (* no adders! return this one *) let rec all_sub_lists = function (* all combinations of sub-lists *) | [] -> [] | xs -> range 0 (List.length xs) |> List.map (fun len' -> sub_list 0 len' xs) |> flip List.append (all_sub_lists @@ List.tl xs) let () = let lines = read_file "day9.txt" |> List.map int_of_string in let first = lines |> first_without_adders 25 in Printf.printf "first without 2 adders %i\n" first; let all_subs = all_sub_lists lines in let our_range = List.find (fun l -> list_sum l = first) all_subs in let our_sum = (list_max our_range) + (list_min our_range) in Printf.printf "sum %i\n" our_sum;