Update: Tried benchmarking an older version of advent of code script, which 
parses the input in one go, then loops through the parsed sequences once for 
the first solution, then again for the second solution
    
    
    import strutils,std/strformat,tables
    
    type ball = tuple[number: int, color: string]
    type set = seq[ball]
    type game = seq[set]
    var allgames = newSeq[game]()
    
    proc processInputs(inputLines: seq[string]) =
      var gameId,ballnum: int
      var sets,balls,thisball: seq[string]
      var games,ballcolor: string
      for lineI,lineV in inputLines:
        # echo inputLines
        gameId = lineI + 1
        games = lineV.split(": ")[1]
        sets = games.split("; ")
        var thisgame = newSeq[set]()
        for setI,setV in sets.pairs:
          # echo "set " & setI.string
          var thisset = newSeq[ball]()
          balls = setV.split(", ")
          for ball in balls:
            thisball = ball.split(" ")
            ballnum = parseInt(thisball[0])
            ballcolor = thisball[1]
            thisset.add((ballnum,ballcolor))
          thisgame.add(thisset)
        allgames.add(thisgame)
      # echo allgames
    
    
    proc Level1(): int=
      var sum,gameId: int
      const colorLimits = {"red":12,"green":13,"blue":14}.toTable
      for gameI,gameV in allgames.pairs:
        # echo inputLines
        var impossible = false
        gameId = gameI + 1
        for set in gameV:
          for ball in set:
            if ball.number > colorLimits[ball.color]:
              impossible = true
        if impossible == false:
          sum += gameId
      return sum
    
    proc Level2(): int=
      var gameId,sum: int
      for gameI,gameV in allgames.pairs:
        var minBalls = {"red":0,"green":0,"blue":0}.toTable
        gameId = gameI + 1
        for set in gameV:
          # echo "set " & setI.string
          for ball in set:
            if ball.number > minBalls[ball.color]:
              minBalls[ball.color] = ball.number
        var product = 1
        for color,value in minBalls:
          product *= value
        # echo product
        sum += product
      return sum
    
    
    proc main() =
      let input = readFile("input.txt")
      let inputLines = input.splitLines
      processInputs(inputLines)
      echo fmt"Level1: {Level1()}"
      echo fmt"Level2: {Level2()}"
    
    main()
    
    
    Run

orc is now faster
    
    
    nim\aoc23\day02> hyperfine day2orc.exe day2markandsweep.exe --warmup 10
    Benchmark 1: day2orc.exe
      Time (mean ± σ):     245.4 ms ±   3.7 ms    [User: 233.1 ms, System: 17.0 
ms]
      Range (min … max):   240.8 ms … 254.9 ms    11 runs
    
    Benchmark 2: day2markandsweep.exe
      Time (mean ± σ):     354.9 ms ±   6.6 ms    [User: 333.1 ms, System: 22.3 
ms]
      Range (min … max):   348.3 ms … 365.5 ms    10 runs
    
    Summary
      'day2orc.exe' ran
        1.45 ± 0.03 times faster than 'day2markandsweep.exe'
    
    
    Run

My understanding is that the older version has more unnecessary loops and 
unnecessary sequences, so it is the less efficient script. Is the garbage 
collection working more now, and therefore orc is better? Is markandsweep 
better if less garbage collection is needed?

Reply via email to