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()