Quest 9: Encoded in the Scales

  • 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
[โ€“] 2 points 11 months ago*

Nim

Very messy bruteforce.

I've had some problems with parsing in part 2 - I didn't account for double digit numbers before dna sequences and that caused my code to work on example, but silently fail only on the real input. I've figured it out after ~30 minutes with some external help.

Part 3 runs in 700ms - not great, but not too bad either.

proc similarity(a, b: string): int =
  for i, c in a:
    if c == b[i]: inc result

proc solve_part1*(input: string): Solution =
  var sim: seq[int]

  var dnaList: seq[string]
  for line in input.splitLines():
    dnaList.add line[2..^1]

  for i in 0 .. dnaList.high:
    for j in i+1 .. dnaList.high:
      let s = similarity(dnaList[i], dnaList[j])
      sim.add s

  sim.sort()
  result := sim[^2] * sim[^1]

proc parentTest(ch, p1, p2: string): bool =
  for i, c in ch:
    if (c != p1[i]) and (c != p2[i]): return false
  true

proc simTable(dnaList: seq[string]): seq[seq[int]] =
  result = newSeqWith(dnaList.len, newseq[int](dnaList.len))
  for i in 0 .. dnaList.high:
    for j in i+1 .. dnaList.high:
      let s = similarity(dnaList[i], dnaList[j])
      result[i][j] = s
      result[j][i] = s

proc solve_part2*(input: string): Solution =
  var dnaList: seq[string]
  for line in input.splitLines():
    dnaList.add line.split(':')[1]

  let sim = simTable(dnaList)
  var indices = toseq(0..dnaList.high)
  for i, childDna in dnaList:
    var indices = indices
    indices.del i

    block doTest:
      for k in 0 .. indices.high:
        for j in k+1 .. indices.high:
          let p1 = indices[k]
          let p2 = indices[j]
          if parentTest(childDna, dnaList[p1], dnaList[p2]):
            result.intVal += sim[i][p1] * sim[i][p2]
            break doTest

proc solve_part3*(input: string): Solution =
  var dnaList: seq[string]
  for line in input.splitLines():
    dnaList.add line.split(':')[1]

  var families: seq[set[int16]]
  var indices = toseq(0..dnaList.high)
  for ch, childDna in dnaList:
    var indices = indices
    indices.del ch

    block doTest:
      for k in 0 .. indices.high:
        for j in k+1 .. indices.high:
          let p1 = indices[k]
          let p2 = indices[j]
          if parentTest(childDna, dnaList[p1], dnaList[p2]):
            families.add {ch.int16, p1.int16, p2.int16}
            break doTest

  var combined: seq[set[int16]]
  while families.len > 0:
    combined.add families.pop()
    var i = 0
    while i <= families.high:
      if (combined[^1] * families[i]).len > 0:
        combined[^1] = combined[^1] + families[i]
        families.del i
        i = 0
      else: inc i

  let maxInd = combined.mapIt(it.len).maxIndex
  result := combined[maxInd].toseq.mapIt(it.int+1).sum()

Full solution at Codeberg: solution.nim

  • source