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

Day 2 - Advent of Code 2024

advent-of-code/2024/day-2.livemd

Day 2 - Advent of Code 2024

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

Setup

input = Kino.Input.textarea("Paste in your input:", default: "7 6 4 2 1
1 2 7 8 9
9 7 6 2 1
1 3 2 4 5
8 6 4 4 1
1 3 6 7 9
")

Part 1

defmodule Report do
  defstruct [:levels, :safe]

  def new(levels) when is_binary(levels) do
    levels
    |> String.splitter([" ", "\n"], trim: true)
    |> Enum.map(&String.to_integer/1)
    |> new()
  end

  def new(levels) do
    safe =
      levels
      |> Stream.chunk_every(2, 1, :discard)
      |> Stream.map(fn
        [prev_level, prev_level] -> :stuck
        [prev_level, next_level] when abs(prev_level - next_level) > 3 -> :too_far
        [prev_level, next_level] when prev_level < next_level -> :up
        [prev_level, next_level] when prev_level > next_level -> :down
      end)
      |> Enum.reduce_while(nil, fn
        :stuck, _ -> {:halt, :unsafe}
        :too_far, _ -> {:halt, :unsafe}
        direction, nil -> {:cont, direction}
        direction, direction -> {:cont, direction}
        _direction, _opposite_direction -> {:halt, :unsafe}
      end)
      |> case do
        :unsafe -> false
        _ -> true
      end

    %Report{levels: levels, safe: safe}
  end

  def safe?(%Report{safe: true}), do: true
  def safe?(_), do: false
end
reports =
  input
  |> Kino.Input.read()
  |> String.splitter("\n", trim: true)
  |> Stream.map(&amp;Report.new/1)

reports
|> Stream.filter(&amp;Report.safe?/1)
|> Enum.count()

Part 2

defmodule Report.ProblemDampener do
  def dampen(%Report{safe: true} = report), do: report
  
  def dampen(%Report{levels: levels} = report) do
    0..(Enum.count(levels) - 1)
    |> Stream.map(fn removal_index ->
      levels
      |> List.delete_at(removal_index)
      |> Report.new()
    end)
    |> Enum.find(&amp;Report.safe?/1)
    |> case do
      nil -> report
      dampened -> dampened
    end
  end
end
reports
|> Stream.map(&amp;Report.ProblemDampener.dampen/1)
|> Stream.filter(&amp;Report.safe?/1)
|> Enum.count()