Powered by AppSignal & Oban Pro

Day 13

2022/day13.livemd

Day 13

Section

defmodule Day13 do
  def parse_input(path) do
    path
    |> File.stream!()
    |> Stream.map(&String.trim/1)
    |> Stream.reject(&(&1 == ""))
    |> Stream.map(&Code.eval_string/1)
    |> Enum.map(&elem(&1, 0))
  end

  def part1(input) do
    input
    |> Enum.chunk_every(2)
    |> Enum.with_index(1)
    |> Enum.filter(fn {[a, b], _} -> compare(a, b) in [:lt, :eq] end)
    |> Enum.map(&elem(&1, 1))
    |> Enum.sum()
  end

  @driver [
    [[2]],
    [[6]]
  ]

  def part2(input) do
    @driver
    |> Kernel.++(input)
    |> Enum.sort(fn a, b -> compare(a, b) in [:lt, :eq] end)
    |> Enum.with_index(1)
    |> Enum.filter(fn {packet, _} -> packet in @driver end)
    |> Enum.map(&elem(&1, 1))
    |> Enum.product()
  end

  defp compare([], []), do: :eq
  defp compare([], [_ | _]), do: :lt
  defp compare([_ | _], []), do: :gt

  defp compare([h1], [h2]) when is_integer(h1) and is_integer(h2) do
    cond do
      h1 > h2 -> :gt
      h1 < h2 -> :lt
      true -> :eq
    end
  end

  defp compare([h1 | t1], [h2 | t2]) do
    case compare(List.wrap(h1), List.wrap(h2)) do
      :eq -> compare(t1, t2)
      x -> x
    end
  end
end
input = Day13.parse_input("#{__DIR__}/day13.txt")
Day13.part1(input)
Day13.part2(input)