Day 8: Playground

Megathread guidelines

  • Keep top level comments as only solutions, if you want to say something other than a solution put it in a new post. (replies to comments can be whatever)
  • You can send code in code blocks by using three backticks, the code, and then three backticks or use something such as https://topaz.github.io/paste/ if you prefer sending it through a URL

FAQ

you are viewing a single comment's thread
view the rest of the comments
[–] 6 points 9 months ago* (last edited 9 months ago) (1 child)

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

  • source
  • hideshow 1 child comment