Nim
view code
type
AOCSolution[T,U] = tuple[part1: T, part2: U]
Vec3 = tuple[x,y,z: int]
Node = ref object
pos: Vec3
cid: int
proc dist(a,b: Vec3): float =
sqrt(float((a.x-b.x)^2 + (a.y-b.y)^2 + (a.z-b.z)^2))
proc solve(input: string, p1_limit: int): AOCSolution[int, int] =
let boxes = input.splitLines().mapIt:
let parts = it.split(',')
let pos = Vec3 (parseInt parts[0], parseInt parts[1], parseInt parts[2])
Node(pos: pos, cid: -1)
var dists: seq[(float, (Node, Node))]
for i in 0 .. boxes.high - 1:
for j in i+1 .. boxes.high:
dists.add (dist(boxes[i].pos, boxes[j].pos), (boxes[i], boxes[j]))
var curcuits: Table[int, HashSet[Node]]
var curcuitID = 0
dists.sort(cmp = proc(a,b: (float, (Node, Node))): int = cmp(a[0], b[0]))
for ind, (d, nodes) in dists:
var (a, b) = nodes
let (acid, bcid) = (a.cid, b.cid)
if acid == -1 and bcid == -1: # new curcuit
a.cid = curcuitID
b.cid = curcuitID
curcuits[curcuitId] = [a, b].toHashSet
inc curcuitID
elif bcid == -1: # add to a
b.cid = acid
curcuits[acid].incl b
elif acid == -1: # add to b
a.cid = bcid
curcuits[bcid].incl a
elif acid != bcid: # merge two curcuits
for node in curcuits[bcid]:
node.cid = acid
curcuits[acid].incl curcuits[bcid]
curcuits.del bcid
if ind+1 == p1_limit:
result.part1 = curcuits.values.toseq.map(len).sorted()[^3..^1].prod
if not(acid == bcid and acid != -1): result.part2 = a.pos.x * b.pos.x
Runtime: 364 ms
Part 1:
I compute all pairs of Euclidean distances between 3D points, sort them, then connect points into circuits, using, what I think is called a UnionβFind algorithm (circuits grow or merge). After exactly 1000 connections (including redundant ones), I take the three largest circuits and multiply their sizes.
Part 2:
While iterating through the sorted connections, I also calculate the product of each pair xβcoordinates. The last product is a result for part 2.
Problems I encountered while doing this puzzle:
- I've changed a dozen of data structures, before settled on curcuitIDs and
ref objects stored in a HashTable (~ 40 min) - I did a silly mistake of mutating the fields of an object and then using new fields as keys for the HashTable (~ 20 min)
- I am stil confused and don't understand why do elves count already connected junction boxes (~ 40 min, had to look it up, otherwise it would be a lot more)
Time to solve Part 1: 1 hour 56 minutes
Time to solve Part 2: 4 minutes
Full solution at Codeberg: solution.nim