janAkali

joined 2 years ago
[–] janAkali@lemmy.sdf.org 3 points 7 months ago (2 children)

No? Most of his stuff are terrible movies.

But, I am watching them for fucking around with cool ideas and crazy visual scenes. Couldn't care less about plot, characters, sometimes logic, etc.

[–] janAkali@lemmy.sdf.org 3 points 7 months ago

This is just another layer. Order in 8/2(2+2) is still not clear if you understand the division symbol correctly.

https://en.wikipedia.org/wiki/Order_of_operations#Mixed_division_and_multiplication

[–] janAkali@lemmy.sdf.org 2 points 7 months ago* (last edited 7 months ago) (3 children)

Both are right, depending on who you ask:

most people see:

8 / 2 * (2+2) = 16

math people see "juxtaposition" instead of multiplication, it has precedence over multiplication and division:

5 / 2a = 5 / (2 * a)

Math notation just sucks and is not standard in general, everyone just tries to avoid ambiguity like in this equation.

 
[–] janAkali@lemmy.sdf.org 2 points 8 months ago (1 children)

> zweihander

[–] janAkali@lemmy.sdf.org 0 points 8 months ago* (last edited 8 months ago)

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 calculate distances between each possible pair of boxes and sort them.
I have a hashtable that holds each curcuit (length >= 2), each curcuit is a hashet of Nodes and each Node has the cuircuit ID that it is belonging to (initialised to -1).
Then I iterate over distances and check if I can add to or merge curcuits.
Result is calculated at 1000th connection, doesn't matter if it's redunant or not.

Part 2:
I Iterate over all distance to the end and calculate a.x * b.x each time we create "not redundant" connection. Result is the last product we calculated.

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

[–] janAkali@lemmy.sdf.org 0 points 8 months ago* (last edited 8 months ago) (1 children)

Nim

Another simple one.

Part 1: count each time a beam crosses a splitter.
Part 2: keep count of how many particles are in each column in all universes
(e.g. with a simple 1d array), then sum.

Runtime: 116 μs

type
  AOCSolution[T,U] = tuple[part1: T, part2: U]

proc solve(input: string): AOCSolution[int, int] =
  var beams = newSeq[int](input.find '\n')
  beams[input.find 'S'] = 1

  for line in input.splitLines():
    var newBeams = newSeq[int](beams.len)
    for pos, cnt in beams:
      if cnt == 0: continue
      if line[pos] == '^':
        newBeams[pos-1] += cnt
        newBeams[pos+1] += cnt
        inc result.part1
      else:
        newbeams[pos] += cnt
    beams = newBeams
  result.part2 = beams.sum()

Full solution at Codeberg: solution.nim

[–] janAkali@lemmy.sdf.org 0 points 8 months ago* (last edited 8 months ago)

Nim

The hardest part was reading the part 2 description. I literally looked at it for minutes trying to understand where the problem numbers come from and how they're related to the example input. But then it clicked.

The next roadblock was that my template was stripping whitespace at the end of the last line, making parsing a lot harder. I've replaced strip() with strip(chars={'\n'}) to keep the trailing space intact.

Runtime: ~~1.4 ms~~ 618 μs

view code

type
  AOCSolution[T,U] = tuple[part1: T, part2: U]

proc solve(input: string): AOCSolution[int, int] =
  let lines = input.splitLines()
  let numbers = lines[0..^2]
  let ops = lines[^1]

  block p1:
    let numbers = numbers.mapIt(it.splitWhiteSpace().mapIt(parseInt it))
    let ops = ops.splitWhitespace()
    for x in 0 .. numbers[0].high:
      var res = numbers[0][x]
      for y in 1 .. numbers.high:
        case ops[x]
        of "*": res *= numbers[y][x]
        of "+": res += numbers[y][x]
      result.part1 += res

  block p2:
    var problems: seq[(char, Slice[int])]
    var ind = 0
    while ind < ops.len:
      let len = ops.skipWhile({' '}, ind+1)
      problems.add (ops[ind], ind .. ind + len - (if ind+len < ops.high: 1 else: 0))
      ind += len + 1

    for (op, cols) in problems:
      var res = 0
      for x in cols:
        var num = ""
        for y in 0 .. numbers.high:
          num &= numbers[y][x]

        if res == 0:
          res = parseInt num.strip
        else:
          case op
          of '*': res *= parseInt num.strip
          of '+': res += parseInt num.strip
          else: discard

      result.part2 += res

Full solution at Codeberg: solution.nim

[–] janAkali@lemmy.sdf.org 44 points 8 months ago* (last edited 8 months ago) (2 children)

+1 shitty superpower ideas
I should really start writing them down at this point.

[–] janAkali@lemmy.sdf.org 0 points 8 months ago* (last edited 8 months ago)

Nim

Huh, I didn't expect two easy days in a row.
Part 1 is a range check. Part 2 is a range merge.

Runtime: ~720 µs

type
  AOCSolution[T,U] = tuple[part1: T, part2: U]

proc merge[T](ranges: var seq[Slice[T]]) =
  ranges.sort(cmp = proc(r1, r2: Slice[T]): int = cmp(r1.a, r2.a))
  var merged = @[ranges[0]]
  for range in ranges.toOpenArray(1, ranges.high):
    if range.a <= merged[^1].b:
      if range.b > merged[^1].b:
        merged[^1].b = range.b
    else:
      merged.add range
  ranges = merged

proc solve(input: string): AOCSolution[int, int] =
  let chunks = input.split("\n\n")
  var freshRanges = chunks[0].splitLines().mapIt:
    let t = it.split('-'); t[0].parseInt .. t[1].parseInt

  freshRanges.merge()

  block p1:
    let availableFood = chunks[1].splitLines().mapIt(parseInt it)
    for food in availableFood:
      for range in freshRanges:
        if food in range:
          inc result.part1
          break

  block p2:
    for range in freshRanges:
      result.part2 += range.b-range.a+1

Full solution at Codeberg: solution.nim

[–] janAkali@lemmy.sdf.org 0 points 8 months ago

Nim

type
  AOCSolution[T,U] = tuple[part1: T, part2: U]
  Vec2 = tuple[x,y: int]

proc removePaper(rolls: var seq[string]): int =
  var toRemove: seq[Vec2]
  for y, line in rolls:
    for x, c in line:
      if c != '@': continue
      var adjacent = 0
      for (dx, dy) in [(-1,-1),(0,-1),(1,-1),
                       (-1, 0),       (1, 0),
                       (-1, 1),(0, 1),(1, 1)]:
        let pos: Vec2 = (x+dx, y+dy)
        if pos.x < 0 or pos.x >= rolls[0].len or
           pos.y < 0 or pos.y >= rolls.len: continue
        if rolls[pos.y][pos.x] == '@': inc adjacent

      if adjacent < 4:
        inc result
        toRemove.add (x, y)

  for (x, y) in toRemove: rolls[y][x] = '.'

proc solve(input: string): AOCSolution[int, int] =
  var rolls = input.splitLines()
  result.part1 = rolls.removePaper()
  result.part2 = result.part1
  while (let cnt = rolls.removePaper(); result.part2 += cnt; cnt) > 0:
    discard

Today was so easy, that I decided to solve it twice, just for fun. First is a 2D traversal (see above). And then I did a node graph solution in a few minutes (in repo below). Both run in ~27 ms.

It's a bit concerning, because a simple puzzle can only mean that tomorrow will be a nightmare. Good Luck everyone, we will need it.

Full solution is at Codeberg: solution.nim

1
Advent of Nim 2025 (forum.nim-lang.org)
submitted 9 months ago* (last edited 9 months ago) by janAkali@lemmy.sdf.org to c/nim@programming.dev
 

Advent of Code 2025 is almost here!

Starting December 1st, 12 days of programming-related puzzles - mark your calendars.

We've set up a new Nim leaderboard for active participants.
Join by using the code 5173823-4add4eb1 on the private leaderboard page

Read the full announcement on Nim forum: Advent of Nim 2025

Happy coding!

view more: next ›