🏡 index : ~doyle/aoc.git

#!/usr/bin/env nix-shell

(*
#!nix-shell --pure -i ocaml -p ocaml
*)

let rec read_input acc =
  try
    read_input
      ( (read_line () |> String.split_on_char ' ' |> List.map int_of_string)
      :: acc )
  with End_of_file -> acc

let rec is_ordered = function
  | [], _ | [_], _ ->
      true
  | x :: y :: rest, None ->
      is_ordered (y :: rest, Some (x > y))
  | x :: y :: rest, Some gt ->
      if (gt && x > y) || ((not gt) && x < y) then
        is_ordered (y :: rest, Some gt)
      else false

let rec adjacent_within_bounds = function
  | [] | [_] ->
      true
  | x :: y :: rest ->
      let diff = Int.abs (y - x) in
      if diff >= 1 && diff <= 3 then adjacent_within_bounds (y :: rest)
      else false

let is_valid x =
  let unordered_pairs = is_ordered (x, None) in
  let unbounded_adjacent = adjacent_within_bounds x in
  unordered_pairs && unbounded_adjacent

let part1 input = List.filter is_valid input |> List.length

let part2 input =
  let rec remove_at n = function
    | [] ->
        []
    | h :: t ->
        if n = 0 then t else h :: remove_at (n - 1) t
  in
  let rec bruteforce n x =
    if List.length x = n then false
    else if is_valid (remove_at n x) then true
    else bruteforce (n + 1) x
  in
  let is_valid' x = is_valid x || bruteforce 0 x in
  List.filter is_valid' input |> List.length

let input = read_input []

let () = input |> part1 |> print_int

let () = print_endline ""

let () = input |> part2 |> print_int