Powered by AppSignal & Oban Pro

Day 13: Distress Signal

2022/day13.livemd

Day 13: Distress Signal

Mix.install([:kino, :jason])

Section

input = Kino.Input.textarea("input")
pairs =
  input
  |> Kino.Input.read()
  |> String.split("\n\n")
  |> Enum.map(fn line ->
    [left, right] = String.split(line, "\n")

    {Jason.decode!(left), Jason.decode!(right)}
  end)
defmodule Packet do
  def compare([], []), do: :eq
  def compare([], [_ | _]), do: :lt
  def compare([_ | _], []), do: :gt

  def compare([x | left], [y | right]) do
    case compare(x, y) do
      :eq -> compare(left, right)
      neq -> neq
    end
  end

  def compare(left, right) when is_list(left), do: compare(left, [right])
  def compare(left, right) when is_list(right), do: compare([left], right)
  def compare(left, right) when left == right, do: :eq
  def compare(left, right) when left < right, do: :lt
  def compare(left, right) when left > right, do: :gt
end
pairs
|> Enum.with_index(1)
|> Enum.reduce(0, fn {{left, right}, i}, sum ->
  if Packet.compare(left, right) == :lt, do: sum + i, else: sum
end)
divider_packets = [
  [[2]],
  [[6]]
]

pairs
|> Enum.flat_map(fn {left, right} -> [left, right] end)
|> Enum.concat(divider_packets)
|> Enum.sort(Packet)
|> then(fn ordered ->
  divider_packets
  |> Enum.map(fn p -> Enum.find_index(ordered, &(&1 == p)) + 1 end)
  |> Enum.product()
end)