advent_of_code/elixir/livebook/2024/day11.livemd
2025-01-04 23:29:33 -05:00

1.7 KiB

AOC 2024 Day 11

Section

input = """
""" |> String.trim()

defmodule Blink do
  def blink(stones) do
    blink(stones |> Map.to_list(), %{})
  end

  def blink([], acc), do: acc

  def blink([{0, n} | rest], acc) do
    blink(rest, acc |> Map.update(1, n, &(&1 + n)))
  end

  def blink([{stone, n} | rest], acc) do
    case even_digits?(stone) do
      {true, x} ->
        left = left(stone, div(x, 2))
        right = stone - shift_left(left, div(x, 2))

        blink(
          rest,
          acc
          |> Map.update(left, n, &(&1 + n))
          |> Map.update(right, n, &(&1 + n))
        )

      _ ->
        blink(
          rest,
          acc |> Map.update(stone * 2024, n, &(&1 + n))
        )
    end
  end

  def split_n(n, m) do
    {left(n, m), right(n, m)}
  end

  def left(n, 0), do: n

  def left(n, m) do
    left(div(n, 10), m - 1)
  end

  def right(n, m) do
    left = left(n, m)
    right = n - shift_left(left, m)
    right
  end

  def shift_left(n, 0), do: n

  def shift_left(n, m) do
    shift_left(n * 10, m - 1)
  end

  def even_digits?(0), do: {false, 1}

  def even_digits?(n) do
    even_digits?(n, 0)
  end

  def even_digits?(0, a), do: {rem(a, 2) == 0, a}
  def even_digits?(n, a), do: even_digits?(div(n, 10), a + 1)

  def solve(input, n) do
    input = input |> String.split(" ") |> Enum.map(&String.to_integer/1) |> Enum.frequencies()
    for _ <- 1..n, reduce: input do
      acc -> Blink.blink(acc)
    end
    |> Map.values()
    |> Enum.sum()
  end

  def part1(input), do: solve(input, 25)
  def part2(input), do: solve(input, 75)
end
Blink.part1(input)
Blink.part2(input)