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

Day 02

2024/day-02.livemd

Day 02

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

example_input =
  Kino.Input.textarea("example input:")
  |> Kino.render()

real_input = Kino.Input.textarea("real input:")

Common

defmodule AOC do
  def parse(input) do
    input
    |> Kino.Input.read()
    |> String.split("\n", trim: true)
    |> Enum.map(fn line ->
      line |> String.split() |> Enum.map(&String.to_integer/1)
    end)
  end
end

Part 1

defmodule Part1 do
  def process(input) do
    input
    |> Enum.filter(&safe?(Enum.chunk_every(&1, 2, 1, :discard)))
    |> length()
  end

  defp safe?([[a, b] | _] = line) when a > b do
    line
    |> Enum.map(fn [a, b] -> a - b end)
    |> Enum.all?(&amp;(1 <= &amp;1 and &amp;1 <= 3))
  end

  defp safe?([[a, b] | _] = line) when a < b do
    line
    |> Enum.map(fn [a, b] -> b - a end)
    |> Enum.all?(&amp;(1 <= &amp;1 and &amp;1 <= 3))
  end

  defp safe?(_line), do: false
end

real_input
|> AOC.parse()
|> Part1.process()

Part 2

defmodule Part2 do
  def process(input) do
    input
    |> Enum.filter(&amp;safeish?/1)
    |> length()
  end

  defp safeish?(line) do
    0..(length(line) - 1)
    |> Enum.map(&amp;List.delete_at(line, &amp;1))
    |> Enum.any?(&amp;(Enum.chunk_every(&amp;1, 2, 1, :discard) |> safe?()))
  end

  defp safe?([[a, b] | _] = line) when a > b do
    line
    |> Enum.map(fn [a, b] -> a - b end)
    |> Enum.all?(&amp;(1 <= &amp;1 and &amp;1 <= 3))
  end

  defp safe?([[a, b] | _] = line) when a < b do
    line
    |> Enum.map(fn [a, b] -> b - a end)
    |> Enum.all?(&amp;(1 <= &amp;1 and &amp;1 <= 3))
  end

  defp safe?(_line), do: false
end

real_input
|> AOC.parse()
|> Part2.process()