Rules: no spoilers.

The other rules are made up as we go along.

Share code by link to a forge, home page, pastebin (Eric Wastl has one here) or code section in a comment.

  • zogwarg@awful.systems
    link
    fedilink
    English
    arrow-up
    4
    ·
    11 months ago

    Have been mostly using jq for fun.

    Day 1

    Part 1
    #!/usr/bin/env jq -n -R -f
    
    # Get and reduce every "pretty" line
    reduce inputs as $line (
      0;
      # Add extracted number
      . + ( $line / "" | [ .[] | tonumber? ] | [first * 10 , last] | add )
    )
    

    First part was easy, and very suited to jq

    Part 2
    #!/usr/bin/env jq -n -R -f
    
    # Define string to num value map
    {
      "one":   1,  "1": 1,
      "two":   2,  "2": 2,
      "three": 3,  "3": 3,
      "four":  4,  "4": 4,
      "five":  5,  "5": 5,
      "six":   6,  "6": 6,
      "seven": 7,  "7": 7,
      "eight": 8,  "8": 8,
      "nine":  9,  "9": 9
    } as $to_num |
    
    # Get and reduce every "pretty" line
    reduce inputs as $line (
      0;
      . + (
        $line |
        # Try two capture two numbers
        capture("(^.*?(?(one|two|three|four|five|six|seven|eight|nine|[1-9])).*(?(one|two|three|four|five|six|seven|eight|nine|[1-9])).*?$)?") |
        # If no capture, get one number twice
        if .f == "" then $line | capture("^.*?(?(one|two|three|four|five|six|seven|eight|nine|[1-9]))") | .l = .f else . end |
        # Add extracted number
        $to_num[.f] * 10 + $to_num[.l]
      )
    )
    

    Second part was harder than expected, i had to resort to regex.

    Day 2

    Part 1
    #!/usr/bin/env jq -n -R -f
    
    # For each game: Is 12 red cubes, 13 green cubes, and 14 blue cubes possible ?
    # Line Format =
    # Game 1: 3 blue, 4 red; 1 red, 2 green, 6 blue; 2 green
    [
      # Splitting input game id and content
      inputs / ": " |
      # Saving id
      (.[0] / " " | .[1] | tonumber ) as $id |
      # Parsing game
      .[1] / "; " | [
        .[] / ", " | [ .[] / " " | {(.[1]): .[0] | tonumber} ] | add |
        # Is given sample possible ?
        .red <= 12 and .green <= 13 and .blue <= 14
      ] |
      # If all samples possible, return id, else 0
      if all then $id else 0 end
    ] |
    
    # Return sum of all possible game ids
    add
    

    Not too much trickery in this example.

    Part 2
    #!/usr/bin/env jq -n -R -f
    
    # Line Format =
    # Game 1: 3 blue, 4 red; 1 red, 2 green, 6 blue; 2 green
    [
      # Splitting input game id and content
      inputs / ": " |
      # Parsing game
      .[1] / "; " |
        [ .[] / ", " | [ .[] / " " | {(.[1]): .[0] | tonumber} ] | add ] |
        # Getting minimum required mumber for each color,
        # and computing the power
        {
          r: ([.[].red]   | max),
          g: ([.[].green] | max),
          b: ([.[].blue]  | max)
        } | .r * .g * .b
    ] |
    
    # Return sum of all powers
    add
    

    Satisifyingly straightfoward edit form part one.

    Day 3

    Part 1
    #!/usr/bin/env jq -n -R -f
    
    # Getting input with padding, and padded width
    [ "." + inputs + "." ] as $inputs | ( $inputs[0] | length ) as $w |
    
    # Working with flattened string, convert all symbols to '#'
    [
      ([range($w) | "."]|join("")), # Padding
      $inputs[],
      ([range($w) | "."]|join(""))  # Padding
    ] | join("") | gsub("[^0-9.]";"#") as $inputs |
    
    reduce (
      # Get all indices for symbols, in box pattern around symbols
      $inputs | indices("#")[] |
      . - $w -1  , . - $w , . - $w + 1 ,
      . - 1      , empty  , . + 1      ,
      . + $w - 1 , . + $w , . + $w + 1
    ) as $i (
      # Numbers containes bounding indices,
      # of numbers bordering symbols
      {numbers: []};
    
      # Test if current index isn't included in any found number
      def new_number($i): [ .numbers[] | .[0] <= $i and $i <= .[1] ] | any | not ;
      # Make "number" as bounding indices, by extending left and right
      def make_number($i):
        {a: $i, b: ($i+1 )}
          | until( $inputs[.a:.b] | test("^[^0-9]"); .a -= 1 )
          | until( $inputs[.a:.b] | test("[^0-9]$"); .b += 1 )
          | [ .a +1 , .b -1 ]
      ;
    
      # Add numbers if bordering symbol and new
      if ($inputs[$i:$i+1] | test("[0-9]")) and new_number($i) then .numbers += [ make_number($i) ] else . end
    ) |
    
    # Output sum of all found numbers
    [ .numbers[] | $inputs[.[0]:.[1]] | tonumber ] | add
    

    Took More time than i expected, glad i had the idea early to search by the indices of the symbols and not the digits. Not super well suited to jq, unless I’m missing a better solution.

    Part 2
    #!/usr/bin/env jq -n -R -f
    
    # Getting input with padding, and padded width
    [ "." + inputs + "." ] as $inputs | ( $inputs[0] | length ) as $w |
    
    # Working with flattened string, only keep gear '*' symbols
    [
      ([range($w) | "."]|join("")), # Padding
      $inputs[],
      ([range($w) | "."]|join(""))  # Padding
    ] | join("") | gsub("[^0-9*]";".") as $inputs |
    
    # Iterate over index positions of all gears
    reduce ($inputs | indices("*")[]) as $i (
      0;
      # Re-use part-1 functions
      def new_number($i):
        [ .numbers[] | .[0] <= $i and $i <= .[1] ] | any | not
      ;
      def make_number($i):
        {a: $i, b: ($i+1 )}
          | until( $inputs[.a:.b] | test("^[^0-9]"); .a -= 1 )
          | until( $inputs[.a:.b] | test("[^0-9]$"); .b += 1 )
          | [ .a +1 , .b -1 ]
      ;
      # Reset and add numbers for each "box" ids
      def add_numbers($box_idx):
        reduce $box_idx[] as $i ({numbers:[]};
          if ($inputs[$i:$i+1] | test("[0-9]")) and new_number($i) then
            .numbers += [ make_number($i) ]
          else
            .
          end
        )
      ;
      add_numbers([
        $i - $w -1 , $i - $w , $i -$w + 1 ,
        $i - 1     , empty   , $i + 1     ,
        $i + $w - 1, $i + $w , $i + $w + 1
      ]).numbers as $numbers |
    
      if $numbers | length == 2 then
        # Add product if exactly two bordering numbers
        . += ( $numbers | map($inputs[.[0]:.[1]]|tonumber) | .[0] * .[1] )
      else
        .
      end
    )
    

    Not too far of an edit from part one.