Powered by AppSignal & Oban Pro

AoC 2022 Day 13

2022/day13.livemd

AoC 2022 Day 13

Mix.install([:kino])

defmodule Utils do
  def split(line, sep \\ "") do
    String.split(line, sep, trim: true)
  end

  def split_all_lines(text, sep \\ "") do
    text
    |> String.split("\n", trim: true)
    |> Enum.map(&split(&1, sep))
  end

  def to_numbers(number) when is_binary(number) do
    String.to_integer(number)
  end

  def to_numbers(numbers) when is_list(numbers) do
    Enum.map(numbers, &to_numbers/1)
  end

  def to_matrix(text, sep \\ "") do
    text
    |> split_all_lines(sep)
    |> then(fn data ->
      for {row, r} <- Enum.with_index(data), {col, c} <- Enum.with_index(row) do
        {{r, c}, col}
      end
    end)
    |> Map.new()
  end
end

Setup

import Utils
input = Kino.Input.textarea("Input:")
text = Kino.Input.read(input)
data =
  split_all_lines(text, "\n")
  |> List.flatten()
  |> Enum.map(&(&1 |> Code.eval_string() |> elem(0)))
  |> Enum.chunk_every(2)

P1

defmodule P1 do
  def compare([h1 | l1], [h2 | l2]) when is_integer(h1) and is_integer(h2) do
    cond do
      h1 < h2 -> :lt
      h1 > h2 -> :gt
      true -> compare(l1, l2)
    end
  end

  def compare([h1 | l1], [h2 | l2]) when is_list(h1) and is_list(h2) do
    if (comp = compare(h1, h2)) == :eq do
      compare(l1, l2)
    else
      comp
    end
  end

  def compare([], [_ | _]) do
    :lt
  end

  def compare([_ | _], []) do
    :gt
  end

  def compare([], []) do
    :eq
  end

  def compare([h1 | l1], [h2 | l2])
      when is_list(h1) and is_integer(h2) do
    compare([h1 | l1], [[h2] | l2])
  end

  def compare([h1 | l1], [h2 | l2])
      when is_integer(h1) and is_list(h2) do
    compare([[h1] | l1], [h2 | l2])
  end
end

for {[left, right], index} <- Enum.with_index(data, 1), P1.compare(left, right) == :lt do
  index
end
|> Enum.sum()

P2

defmodule P2 do
  def sort(list) do
    Enum.sort(list, P1)
  end
end

a = [[2]]
b = [[6]]
sorted = [a, b | Enum.flat_map(data, & &1)] |> P2.sort()

[
  Enum.find_index(sorted, fn v -> v == a end) + 1,
  Enum.find_index(sorted, fn v -> v == b end) + 1
]
|> Enum.product()