(* 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 explode s = (* convert a string to a list of chars *) let rec exp i l = if i < 0 then l else exp (i - 1) (s.[i] :: l) in exp (String.length s - 1) [];; let implode l = String.of_seq (List.to_seq l) let (<<) f g x = f(g(x)) let (>>) f g x = g(f(x)) let flip f x y = f y x (* --- *) let rec find_idx x = function (* find index of x *) | [] -> raise (Failure "Not Found") | h :: t -> if x = h then 0 else 1 + find_idx x t let rec last = function | [] -> raise (Failure "Empty List") | x :: [] -> x | x :: xs -> last xs let hash = Hashtbl.create 1000 let rec go idx last num = (* Printf.printf "\nidx: %i. last num: %i\n" idx num; *) if idx = last - 1 then num else let next = try let idx' = Hashtbl.find hash num in let new_num = idx - idx' in new_num with Not_found _ -> 0 in let _ = Hashtbl.replace hash num idx in go (idx+1) last next let () = let nums = read_file "day15.txt" |> flip List.nth 0 (* grab the first line *) |> String.split_on_char ',' |> List.map int_of_string in List.iter (Printf.printf "%i ") nums; print_newline (); (* pluck out the last number to start things off *) let rev = List.rev nums in let x :: xs = rev in let nums' = List.rev xs in let starting_idx = List.length xs in (* Add the initial list to our hash *) List.iteri (fun i x -> Hashtbl.add hash x i;) nums'; let final = go starting_idx 2020 x in Printf.printf "after 2020: %i\n" final; Hashtbl.clear hash; List.iteri (fun i x -> Hashtbl.add hash x i;) nums'; let final' = go starting_idx 30000000 x in Printf.printf "after 30000000: %i\n" final';