vkryukov
Advent of Code 2025 - Day 8
Nice little problem. The right data structure is half the solution!
defmodule Y2025.Day08 do
def pairs(enum) do
l = enum |> Enum.with_index()
for {a, i} <- l, {b, j} <- l, i < j, do: {a, b}
end
def norm([x1, y1, z1], [x2, y2, z2]),
do: (x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2) + (z1 - z2) * (z1 - z2)
defmodule Circuits do
def new(enum), do: Enum.into(enum, %{}, fn x -> {x, MapSet.new([x])} end)
def fuze(circuits, c1, c2) do
s1 = circuits[c1]
s2 = circuits[c2]
if s1 == s2 do
circuits
else
s = MapSet.union(s1, s2)
s |> Enum.reduce(circuits, fn el, circuits -> Map.put(circuits, el, s) end)
end
end
def product_top_3_sizes(circuits) do
circuits
|> Enum.uniq_by(&elem(&1, 1))
|> Enum.map(fn {_, v} -> MapSet.size(v) end)
|> Enum.sort(:desc)
|> Enum.take(3)
|> Enum.product()
end
end
def parse(s), do: s |> String.split("\n") |> Enum.map(&parse_line/1) |> Circuits.new()
def parse_line(s), do: s |> String.trim() |> String.split(",") |> Enum.map(&String.to_integer/1)
def fuze_while(circuits, start, fun) do
Map.keys(circuits)
|> pairs()
|> Enum.map(fn {a, b} -> {a, b, norm(a, b)} end)
|> Enum.sort_by(&elem(&1, 2))
|> Enum.reduce_while(start, fun)
end
def part1(s, n) do
circuits = parse(s)
fuze_while(circuits, {circuits, 0}, fn {c1, c2, _}, {circuits, count} ->
if count == n do
{:halt, circuits |> Circuits.product_top_3_sizes()}
else
{:cont, {Circuits.fuze(circuits, c1, c2), count + 1}}
end
end)
end
def part2(s) do
circuits = parse(s)
n = map_size(circuits)
fuze_while(circuits, circuits, fn {c1, c2, _}, circuits ->
if MapSet.union(circuits[c1], circuits[c2]) |> MapSet.size() == n do
{:halt, List.first(c1) * List.first(c2)}
else
{:cont, Circuits.fuze(circuits, c1, c2)}
end
end)
end
end
Trending in Challenges
Other Trending Topics
Hey, I’m Jesse and I’m the main contributor behind Dexter, a full-featured, lightning-fast Elixir LSP optimized for large codebases. It s...
New
Beam Bots (or just BB for short) is a framework for building fault-tolerant robotics applications in Elixir using familiar OTP patterns. ...
New
Hello everyone. After busy few months I am happy to announce v0.1.0 of Emerge & Solve.
They are GUI (Emerge) and State management (S...
New
Emily is an Elixir library that runs Nx computations on Apple’s MLX. Install it as the default Nx backend and Nx, defn, Axon, Nx.Serving,...
New
I just stumbled on a newly redesigned elixir-lang.org. :tada: It looks like @Software_Mansion did the work, and I think it is generally a...
New
@hugobarauna and I (Alex Koutmos) have been hard at work on writing a book on Nerves that takes you from simply blinking LEDs to building...
New
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #phoenix_html
- #iex
- #blog-post
- #graphql
- #genstage
- #ai
- #elixirconf-us
- #websockets
- #supervisor
- #advent-of-code
- #distillery
- #processes
- #api
- #forms
- #metaprogramming
- #performance
- #security











First 10 of 13 Posts
bjorng
I implemented a union-find algorithm to group junction boxes into circuits. The combined runtime for both part is 0.4 seconds on my computer.
lkuty
hauleth
Parse
Setup
Part 1
Part 2
Not the most performant implementation (each part runs in about 3s on my machine), but it is good enough. It probably could use some clever algorithms, but I didn’t want to spend too much time on it.
EDIT: I have improved squashing of sets to make it run in 30ms each (sans creating and sorting list of pairs).
Aetherus
My code is almost the same as yours, except one difference: I added an ID (generated with
make_ref()) to eachMapSet.t()so that I don’t have to compare two whole sets, instead I just compare their ID.lud
My solution takes 680ms, which is slow, I compute all distances upfront like many of you
I think I could optimize by keeping a double index position=>group and group=>positions to speed up the circuit merging, but I’m too lazy today
hauleth
If you copy set instead of constructing it 2 separately, then
==will be as fast for maps as it is for refs. So in this case:Will be immediate.
Aetherus
Is it also O(1) when comparing a and b using
==whena != b?hauleth
AFAIK - no, but I think that in most cases it will be negligible. I would need to check how exactly map equality is implemented.
rvnash
Fun!
Did the following:
Enum.count(circuits) == 1do statement. I don’t need the count, just need to know if it is 1 or not. Is there a faster way to see if an Enum has 1 element?Processing time is about 250ms for part1 and part2.
sevenseacat
https://github.com/sevenseacat/advent_of_code/blob/main/lib/y2025/day08.ex
My initial implementation was really silly - find the closest pair each time, and then update a list of MapSets - before I was like ohhhhhh this is a graph problem isn’t it?
So I precomputed all of the distances between each pair of junction boxes, started mucking around with graphs - looking at my solution now I think I over-optimized it and it works by chance (just because all nodes are connected to something, doesn’t mean they’re all in one big circuit…) but hey I’ll take it!
(The previous version I had is probably more accurate - on each join, checking if
length(Graph.components(graph)) == 1)