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

AoC 2022 Day 13

2022/day13/solution.livemd

AoC 2022 Day 13

Get input

Mix.install([
  {:kino, "~> 0.8.0"}
])
input = Kino.Input.textarea("Input")

Module for comparing signals

defmodule Signal do
  def compare({left, right, i}) do
    compare_lists(left, right, i)
  end

  defp compare_lists([], [_r | _], i), do: i
  defp compare_lists([_l | _], [], _i), do: nil
  defp compare_lists(same, same, _i), do: :cont

  defp compare_lists([l | l_rest], [r | r_rest], i) do
    result =
      case {l, r} do
        {l, r} when is_integer(l) and is_integer(r) -> compare_ints(l, r, i)
        {l, r} when is_integer(l) -> compare_lists([l], r, i)
        {l, r} when is_integer(r) -> compare_lists(l, [r], i)
        _ -> compare_lists(l, r, i)
      end

    if result == :cont, do: compare_lists(l_rest, r_rest, i), else: result
  end

  defp compare_ints(same, same, _i), do: :cont

  defp compare_ints(l, r, i) do
    if l < r, do: i, else: nil
  end

  def sort(left, right) do
    compare_lists(left, right, true) != nil
  end

  def decoder_key(sorted, d1, d2) do
    first = Enum.find_index(sorted, &amp;(&amp;1 == d1)) + 1
    second = Enum.find_index(sorted, &amp;(&amp;1 == d2)) + 1
    first * second
  end
end

Part 1

lines =
  input
  |> Kino.Input.read()
  |> String.split("\n", trim: true)

pairs =
  lines
  |> Enum.chunk_every(2)
  |> Enum.with_index(1)
  |> Enum.map(fn {[l, r], i} ->
    {result_l, _} = Code.eval_string(l)
    {result_r, _} = Code.eval_string(r)
    {result_l, result_r, i}
  end)
pairs
|> Enum.map(&amp;Signal.compare(&amp;1))
|> Enum.reject(&amp;is_nil(&amp;1))
|> Enum.sum()

Part 2

signals =
  lines
  |> Enum.map(&amp;elem(Code.eval_string(&amp;1), 0))
d1 = [[2]]
d2 = [[6]]

# Decoder key
[d1, d2 | signals]
|> Enum.sort(&amp;Signal.sort/2)
|> Signal.decoder_key(d1, d2)