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/

  • janAkali@lemmy.sdf.org
    link
    fedilink
    arrow-up
    2
    ·
    7 days 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