Powered by AppSignal & Oban Pro
Would you like to see your link here? Contact us

Advent of Code 2024 - Day 2

lib/day_2.livemd

Advent of Code 2024 - Day 2

Mix.install([
  {:kino, "~> 0.14.2"}
])

Input

file_input = Kino.Input.file("day_2.txt")
file = Kino.Input.read(file_input)
path = Kino.Input.file_path(file.file_ref)

parse_number_list = fn input ->
  String.split(input)
  |> Enum.map(&String.to_integer/1)
end


puzzle_input = File.stream!(path, :line) 
  |> Stream.map(&String.trim/1) 
  |> Stream.map(parse_number_list)
  |> Enum.to_list()

Part One

The engineers are trying to figure out which reports are safe. The Red-Nosed reactor safety systems can only tolerate levels that are either gradually increasing or gradually decreasing. So, a report only counts as safe if both of the following are true:

The levels are either all increasing or all decreasing.
Any two adjacent levels differ by at least one and at most three.
is_safe = fn report -> 
  sorted = Enum.sort(report)
  is_asc = sorted == report
  is_desc = Enum.sort(report, :desc) == report
  is_uniq = report == Enum.uniq(report)
  [h|t] = sorted

  {_, max_diff} = Enum.reduce(sorted, {h, 0}, fn x, {previous, max_difference} ->
    difference = abs(previous - x)
    {x, max(difference, max_difference)}
  end)
  
  (is_asc || is_desc) &amp;&amp; max_diff <= 3 &amp;&amp; is_uniq
  end
Enum.filter(puzzle_input, is_safe)
|> Enum.count()

Part Two

The Problem Dampener is a reactor-mounted module that lets the reactor safety systems tolerate a single bad level in what would otherwise be a safe report. It’s like the bad level never happened!

Now, the same rules apply as before, except if removing a single level from an unsafe report would make it safe, the report instead counts as safe.

Enum.filter(puzzle_input, fn report ->
  sub_lists = for i <- 0 .. length(report), do: List.delete_at(report, i)
  Enum.count(sub_lists, is_safe) > 0
end)
|> Enum.count()