Quest 5: Fishbone Order

  • 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

Link to participate: https://everybody.codes/

you are viewing a single comment's thread
view the rest of the comments
[โ€“] 3 points 1 year ago*

Nim

Nothing fancy. Simple iterative tree construction and sort, using the std/algorithm and a custom < operator on types.

type
  LeafNode = ref object
    value: int
  Node = ref object
    value: int
    left, right: LeafNode
    center: Node
  Sword = object
    id, quality: int
    levels: seq[int]
    fishbone: Node

proc add(node: var Node, val: int) =
  var curNode = node
  while not curNode.isNil:
    if val < curNode.value and curNode.left.isNil:
      curNode.left = LeafNode(value: val)
      return
    elif val > curNode.value and curNode.right.isNil:
      curNode.right = LeafNode(value: val)
      return
    elif curNode.center.isNil:
      curNode.center = Node(value: val)
      return
    else: curNode = curNode.center
  node = Node(value: val)

proc calcQuality(sword: Sword): int =
  var res = ""
  var curNode = sword.fishbone
  while not curNode.isNil:
    res &= $curNode.value
    curNode = curNode.center
  return parseInt(res)

proc getLevels(s: Sword): seq[int] =
  var curNode = s.fishbone
  while not curNode.isNil:
    var strVal = ""
    strVal &= (if curNode.left.isNil:  "" else: $curNode.left.value)
    strVal &= $curNode.value
    strVal &= (if curNode.right.isNil: "" else: $curNode.right.value)
    result.add parseInt(strVal)
    curNode = curNode.center

proc `<`(s1, s2: seq[int]): bool =
  for i in 0..min(s1.high, s2.high):
    if s1[i] != s2[i]: return s1[i] < s2[i]
  s1.len < s2.len

proc `<`(s1, s2: Sword): bool =
  if s1.quality != s2.quality: s1.quality < s2.quality
  elif s1.levels != s2.levels: s1.levels < s2.levels
  else: s1.id < s2.id

proc parseSwords(input: string): seq[Sword] =
  for line in input.splitLines:
    let numbers = line.split({':',','}).mapIt(parseInt(it))
    var node= Node(value: numbers[1])
    for num in numbers.toOpenArray(2, numbers.high):
      node.add num
    result &= Sword(id: numbers[0], fishbone: node)

proc solve_part1*(input: string): Solution =
  let swords = parseSwords(input)
  result := swords[0].calcQuality()

proc solve_part2*(input: string): Solution =
  let qualities = parseSwords(input).mapIt(it.calcQuality())
  result := qualities.max - qualities.min

proc solve_part3*(input: string): Solution =
  var swords = parseSwords(input)
  for i in 0..swords.high:
    swords[i].levels = swords[i].getLevels()
    swords[i].quality = swords[i].calcQuality()
  swords.sort(Descending)
  for pos, id in swords.mapit(it.id):
    result.intVal += (pos+1) * id

Full solution at Codeberg: solution.nim

  • source