Advent of Code 2024 - Day 11

I used libgraph yet again!

The graph building part:

defmodule AoC2024.Day11 do
  import Integer
  import Bitwise
  
  def build_graph(stones) do
    do_build_graph(Graph.new(type: :directed), stones)
  end

  defp do_build_graph(graph, stones) do    
    not_seen = stones -- Graph.vertices(graph)

    if not_seen == [] do
      graph
    else
      graph = Graph.add_vertices(graph, not_seen)
  
      edges =
        for stone <- stones, neighbor <- transform(stone) do
          {stone, neighbor}
        end
        |> Enum.frequencies()
        |> Enum.map(fn {{from, to}, label} ->
          Graph.Edge.new(from, to, label: label)
        end)
  
      neighbors = edges |> Enum.map(& &1.v2) |> Enum.uniq()
      graph = do_build_graph(graph, neighbors)
  
      Graph.add_edges(graph, edges)
    end
  end

  defp transform(0), do: [1]

  defp transform(n) do
    len = floor(:math.log10(n)) + 1

    if is_even(len) do
      d = 10 ** (len >>> 1)
      [div(n, d), rem(n, d)]
    else
      [n * 2024]
    end
  end
end

The problem solving part:

graph = AoC2024.Day11.build_graph(stones)

stones
|> Enum.frequencies()
|> Stream.iterate(fn freqs ->
  for {num, freq} <- freqs, edge <- Graph.out_edges(graph, num), reduce: %{} do
    freqs2 -> Map.update(freqs2, edge.v2, freq * edge.label, & &1 + freq * edge.label)
  end
end)
|> Enum.at(25)  # <-- change this to 75 to solve Part 2
|> Map.values()
|> Enum.sum()