Advent of Code 2024 - Day 2

Part 1:

all =
  puzzle_input
  |> String.split("\n", trim: true)
  |> Enum.map(fn line ->
    line
    |> String.split(" ", trim: true)
    |> Enum.map(&String.to_integer/1)
  end)

safe? = fn levels ->
  Enum.reduce_while(levels, {nil, nil}, fn a, acc ->
    case acc do
      {nil, _} ->
        {:cont, {a, nil}}

      {b, nil} when abs(a - b) in [1, 2, 3] and a < b ->
        {:cont, {a, :decrease}}

      {b, nil} when abs(a - b) in [1, 2, 3] and a > b ->
        {:cont, {a, :increase}}

      {b, :decrease} when abs(a - b) in [1, 2, 3] and a < b ->
        {:cont, {a, :decrease}}

      {b, :increase} when abs(a - b) in [1, 2, 3] and a > b ->
        {:cont, {a, :increase}}

      _ ->
        {:halt, :invalid}
    end
  end)
  |> case do
    :invalid -> false
    _ -> true
  end
end

for levels <- all do
  safe?.(levels)
end
|> Enum.count(& &1)

Part 2:

all =
  puzzle_input
  |> String.split("\n", trim: true)
  |> Enum.map(fn line ->
    line
    |> String.split(" ", trim: true)
    |> Enum.map(&String.to_integer/1)
  end)

damp = fn levels ->
  levels
  |> Enum.with_index()
  |> Enum.map(fn {_, i} -> List.delete_at(levels, i) end)
end

safe? = fn levels ->
  Enum.reduce_while(levels, {nil, nil}, fn a, acc ->
    case acc do
      {nil, _} ->
        {:cont, {a, nil}}

      {b, nil} when abs(a - b) in [1, 2, 3] and a < b ->
        {:cont, {a, :decrease}}

      {b, nil} when abs(a - b) in [1, 2, 3] and a > b ->
        {:cont, {a, :increase}}

      {b, :decrease} when abs(a - b) in [1, 2, 3] and a < b ->
        {:cont, {a, :decrease}}

      {b, :increase} when abs(a - b) in [1, 2, 3] and a > b ->
        {:cont, {a, :increase}}

      _ ->
        {:halt, :invalid}
    end
  end)
  |> case do
    :invalid -> false
    _ -> true
  end
end

for levels <- all do
  safe?.(levels) || Enum.any?(damp.(levels), fn level -> safe?.(level) end)
end
|> Enum.count(& &1)