Skip Navigation

Posts
26
Comments
92
Joined
2 yr. ago

  • python-level intuitive-to-read language with static typing

    Agreed, this is exactly Nim

  • Yeah the descriptions contain a lot of story fluff, but also critical bits of information.

  • Nim

    Happy I decided to not actually expand anything. Manhattan distance and counting the number of empty rows and columns was plenty. Also made part 2 an added oneliner :) It's still pretty inefficient iterating over the grid multiple times to gather the galaxies and empty rows, runtime is about 17ms

    I could also extract and re-use my 2D Coord and Grid classes from day 10, and learned more about Nim in the process ^^

    Part 1 and 2 combined

  • Yepp, this one got me as well! I found the discrepancy when testing against the sample through, which showed the result for a factor 100 (which needed to be 99). Knowing the correct outcome made debugging a lot easier.

    I always make sure my solution passes all the samples before trying the full input.

  • Nim

    This was a great challenge, it was complex enough to get me to explore more of the Nim language, mainly (ref) types, iterators, operators, inlining.

    I first parse the input to Tiles stored in a grid. I use a 1D seq for fast tile access, in combination with a 2D Coord type. From the tile "shapes" I get the connection directions to other tiles based on the lookup table shapeConnections. The start tile's connections are resolved based on how the neighbouring tiles connect.

    Part 1 is solved by traversing the tiles branching out from the start tile in a sort of pathfinding-inspired way. Along the way I count the distance from start, a non-negative distance means the tile has already been traversed. The highest distance is tracked, once the open tiles run our this is the solution to part 1.

    Part 2 directly builds on the path found in Part 1. Since the path is a closed loop that doesn't self-intersect, I decided to use the raycast algorithm for finding if a point lies inside a polygon. For each tile in the grid that is not a path tile, I iterate towards the right side of the grid. If the number of times the "ray" crosses the path is odd, the point lies inside the path. Adding all these points up give the solution for Part 2.

    Initially it ran quite slow (~8s), but I improved it by caching the tile connections (instead of looking them up based on the symbol), and by ditching the "closed" tiles list I had before which kept track of all the path tiles, and switched to checking the tile distance instead. This and some other tweaks brought the execution speed down to ~7ms, which seems like a nice result :)

    Part 1 & 2 combined

  • I looked into the iterators and they are really handy, they remind me of C#'s Linq syntax.

  • Have you joined the community?

    I have now, thanks for the tip!

    And that's some very compact code! I've only just started with nim, so seeing more nim solutions is a great way to learn 😁

  • Thank you so much! I'll check out the index and discord/forums.

    So far I'm having a lot of fun with Nim, the syntax is clean and readable, but it's very flexible and capable :)

  • This is my solution in Nim:

     nim
        
    import strutils, strformat
    
    const digitStrings = ["one", "two", "three", "four", "five", "six", "seven", "eight", "nine"]
    
    ### Type definiton for a proc to extract a calibration function from a line
    type CalibrationExtracter = proc (line:string): int
    
    ## extract a calibration value by finding the first and last numerical digit, and concatenating them
    proc extractCalibration1(line:string): int =
      var first,last = -1
        
      for i, c in line:
        if c.isDigit:
          last = parseInt($c)
          if first == -1:
            first = last
            
      result = first * 10 + last
    
    ## extract a calibration value by finding the first and last numerical digit OR english lowercase word for a digit, and concatenating them
    proc extractCalibration2(line:string): int =
      var first,last = -1
      
      for i, c in line:
        if c.isDigit:
          last = parseInt($c)
          if first == -1:
            first = last
        else: #not a digit parse number words
          for dsi, ds in digitStrings:
            if i == line.find(ds, i):
              last = dsi+1
              if first == -1:
                first = last
              break #break out of digit strings
            
      result = first * 10 + last
    
    ### general purpose extraction proc, accepts an extraction function for specific line handling
    proc extract(fileName:string, extracter:CalibrationExtracter, verbose:bool): int =
      
      let lines = readFile(fileName).strip().splitLines();
      
      for lineIndex, line in lines:
        if line.len == 0:
          continue
        
        let value = extracter(line)
        result += value
        
        if verbose:
          echo &"Extracted {value} from line {lineIndex} {line}"
    
    ### public interface for puzzle part 1
    proc part1*(input:string, verbose:bool = false): int =
      result = input.extract(extractCalibration1, verbose);
    
    ### public interface for puzzle part 2
    proc part2*(input:string, verbose:bool = false): int =
      result = input.extract(extractCalibration2, verbose);
    
    
      
  • Awesome! I'm looking forward to trying it out 🙂

  • Nice! Have you used it before? I found it a long time ago, but never had a good opportunity to learn it.

  • This will be my first time participating, I'll be using Nim.

  • Looks more like a tortoise 🙃

  • The code already describes what it does, your comments should describe why it does that, so the purpose of the code.

  • The little void is Yami, and she is extremely smol 😻

  • Mochi and Yami

  • This is like Shakespeare for cats 😸

  • She actually makes chirping sounds 😻