zogwarg

joined 2 years ago
[–] [email protected] 2 points 1 year ago (6 children)

Cleaned up version of code used to solve part 2 in jq.

Spoiler code section

#!/usr/bin/env jq -n -R -f

# Get LR instructions
( input / "" | map(if . == "L" then 0 else 1 end )) as $LR |
( $LR | length ) as $l |

# Make map {"AAA":["BBB","CCC"], ...}
(
  [
    inputs | select(.!= "") | [ scan("[A-Z]{3}") ] | {(.[0]): .[1:]}
  ] | add
) as $map |

# List primes for GCM test / factorization
[
  2, 3, 5, 7, 11, 13, 17, 19,
  23, 29, 31, 37, 41, 43, 47,
  53, 59, 61, 67, 71, 73, 79,
  83, 89, 97
] as $primes |

reduce (
  $map | keys[] | select(test("..A")) | { s: 0, i: 0, c: .} |

  # For each "..A" starting position
  # Produce visited [ "KEY", pos mod $l ], until loop is detected
  until (.i as $i | .[.c] // [] | contains([$i]);
    .s as $s | .i as $i | .c as $c        |
    $map[$c][$LR[$i]] as $next            | # Get next KEY
    .[$c] = (( .[$c] // [ $s ] ) + [$i] ) | # Append ( .s ≡ $l ) to array for KEY (first = .s non mod)
    .s = ( $s + 1 )  | .i = (.s % $l )    | # Update cursors, for next iteration
    .c = $next
  )
  | .[.c][0] as $start_loop_idx | (.s - $start_loop_idx) as $loop_size
  | [ to_entries[] | select(.key[-1:] == "Z") ]
  | if (
      length != 1                                           # Only one ..Z per loop
      or ( .[0].value[0] != $loop_size )                    # First ..Z idx = loop size
      or ( [ .[0].value[0] / $l ] | inside($primes) | not ) # loop_size = ( prime x $l )
      or ( .[0].value[0] / $l  > $l )                       # GCM(loop_sizes) = $l
    ) then "Input does not fit expected pattern" | halt_error else
      # Under these conditions, synched positions of ..Zs happen at:
      # LCM = Π(loop_size_i / GCM) * GCM

      # loop_size_i / GCM
      .[0].value[0] / $l
    end
) as $i (1; . * $i)

# Output LCM = first step where, all ghosts are on "..Z" nodes
| . * $l

[–] [email protected] 3 points 1 year ago* (last edited 1 year ago) (7 children)

Day 8: Haunted Wasteland

https://adventofcode.com/2023/day/8

Not so easy at least for part two.

spoilerDo you remember high school math, like lowest common multiple, part 2 electric boogaloo.

[–] [email protected] 3 points 1 year ago* (last edited 1 year ago) (1 children)

Day 6: Wait For It

https://adventofcode.com/2023/day/6

Alternate spoiler name - for part 2~~Do you remember highschool algebra?~~ Can you (or your compiler) remember highschool algebra fast enough to beat out a naïve implementation?

[–] [email protected] 3 points 1 year ago (1 children)

The main catch is it would often be faster to use a "real" programming langage ^^, both in writing the code, and in execution time for some loop heavy examples: equivalent code that completes say in 1 second in python, completing in 1 minute in jq. Also missing a way to call native libraries, to do stuff like say "md5" (relevant) in past years advents-of-code.

That being said i like the general "pipe", map-reduce feel of the language. Like bash one-liners It can make for very terse implementations. I like to add comments, and indentation to make it readable though.

[–] [email protected] 4 points 1 year ago* (last edited 1 year ago) (4 children)

I liked the slight trickiness of part 2, that the naive implementation would never complete in time.

As always doing a JQ implementation:

Part 1

#!/usr/bin/env jq -n -R -f

# Get seeds
input | [ match("\\d+"; "g").string | tonumber ] as $seeds |

# Collect maps
reduce inputs as $line ({};
  if $line == "" then
    .
  elif $line | test(":") then
    .k = ( $line / " " | .[0] )
  else
    .[.k] += [[ $line | match("\\d+"; "g").string | tonumber ]]
  end
)

# For each map, apply transformation to all seeds.
# seed -> ... -> location
| reduce ( to_entries[] | select(.key != "k") .value) as $map ({s:$seeds};
  .s[] |= (
    # Only attempt transform if element is in one of the ranges
    [ . as $e | $map[] | select(. as  [$d,$s,$l] | $e >= $s and $e < $s + $l) ] as $range |
    if ($range | length ) > 0 then
      $range[0] as [$d,$s] |
      . - $s + $d
    else
      .
    end
  )
)

# Get lowest location
| .s | min

Some comments:

  • A nice use of input first to get the seeds, then inputs to get remaining lines.

Part 2

#!/usr/bin/env jq -n -R -f

# Utility function
def group_of($n):
  ( length / $n ) as $l |
  . as $arr |
  range($l) | $arr[.*$n:.*$n+$n]
;

# Get all seed ranges
input | [ match("\\d+"; "g").string | tonumber ] | [group_of(2)] as $seeds |

# Collect maps
reduce inputs as $line ({};
  if $line == "" then
    .
  elif $line | test(":") then
    .k = ( $line / " " | .[0] )
  else
    .[.k] += [[ $line | match("\\d+"; "g").string | tonumber ]]
  end
)

# For each map, apply transformation to all seeds ranges.
# Producing new seed ranges if applicable
# seed -> ... -> location
| reduce (to_entries[] | select(.key != "k") .value) as $map ({s:$seeds};
  .s |= [
    # Only attempt transform if seed range and map range instersect
    .[] | [.[0], add, .[1] ] as [$ea, $eb, $el] | [
      $map[] | select(.[1:] | [.[0], add ] as [$sa,$sb] |
        ( $ea >= $sa and $ea < $sb ) or
        ( $eb >= $sa and $eb < $sb ) or
        ( $sa >= $ea and $sa < $eb )
      )
    ] as $range |
    if $range | length > 0 then
      $range[0] as [$d,$s,$l] |
      # ( only end ) inside map range
      if $ea < $s and $eb < $s + $l then
        [$ea, $s - $ea], [$d, $eb - $s ]
      # ( both start, end ) outside map range
      elif $ea < $s then
        [$ea, $s - $ea], [$d, $l], [ $s + $l, $eb ]
      # ( only start ) inside map range
      elif $eb > $s + $l then
        [$ea + $d - $s, $l - $ea + $s ], [$s + $l, $eb - $s - $l]
      # ( both start, end ) inside map range
      else
        [$ea + $d - $s , $el]
      end
    else
      .
    end
  ]
)

# Get lowest location
| [.s[][0]] | min

Some comments:

  • Since iterating across all seeds naively would take forever, iterating over seed ranges instead.
  • It's nice that JQ can neatly produce extra elements: [1,2,3] | [ .[] | if . == 2 then . * 10 + 1 , . * 10 + 2 else . end ] -> [1, 21, 22, 3]
  • There is probably a more compact way of expressing all the conditions and produced outputs.

Replaced less-than (and greater-than for symmetry) symbols with full-width version, since lemmy apparently doesn't handle them well within a code block: replacing less than with <

[–] [email protected] 4 points 1 year ago (2 children)

Back to a more straightfoward day, do they make them harder on the weekends?

Day 4 Scratchcards

Part 1

#!/usr/bin/env jq -n -R -f
[
  inputs
  # Split winning numbers | card
  | split(" | ")
  # Get numbers, remove game id
  | .[] |= [ match("\\d+"; "g").string | tonumber ] | .[0] |= .[1:]
  # Get score for each line
  | .[1] - (.[1] - .[0]) | length | select(. > 0) | pow(2; . - 1)
]

# Output total score sum
| add

Very suited to JQ, extra trick learned using: [ match("\\d+"; "g").string | tonumber ] as a parse all ints in line.

Part 2

#!/usr/bin/env jq -n -R -f
[
  inputs
  # Split winning numbers | card
  | split(" | ")
  # Get numbers, remove game id
  | .[] |= [ match("\\d+"; "g").string | tonumber ] | .[0] |= .[1:]
  # Set number of cards to 1, and further cards count
  | .[1] - (.[1] - .[0]) | [ 1, length ]
]

| { cards: ., i: 0, l: length } | until (.i == .l;
  # Get number for current card
  .cards[.i][0] as $num
  # Increase range of futher cards, by current number
  | .cards[.i + range(.cards[.i][1]) + 1 ][0] += $num
  | .i += 1
)

# Output total sum of cards
| [ .cards[][0] ] | add

Not too much of an edit compared to part one, being able to easily do operations on range of indices is convenient.

[–] [email protected] 4 points 1 year 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.

[–] [email protected] 12 points 1 year ago* (last edited 1 year ago) (2 children)

One (simpler) explanation is that proving an absence of something is almost impossible, and that attempting too hard would make them look a heck of a lot guilty.

There is a good reason why the burden of evidence is “innocent until proven guilty”, and yes this extends to the (in your eyes) untrustworthy.

Prove to me you never stole candy from a store as a child (or if you did, replace that accusation with any item of higher value until you hit something you did not steal)

[–] [email protected] 9 points 1 year ago* (last edited 1 year ago)

One of the more disturbing things that happened at work when using MS Word, was the automatic addition of alt-text images. I didn't ask for that, I didn't click any "Please send my images to the cloud, possibly leaking sensitve material, so inference can be run there, to add potentially unhelpful descriptions"

Is document editing really a task that benefits from AI?

An example of unhelpfulness:

I'm torn between at almost praising meek half-assed attempt at accessibility, and shrieking to the heavens about this unweclome shoe-horned addition.

[–] [email protected] 11 points 1 year ago

Either way it's a circus of incompetence.

[–] [email protected] 9 points 1 year ago

Something something Poe's law, something something. Honestly some of the shit i've read should have been satire, but noooooo.

[–] [email protected] 4 points 1 year ago* (last edited 1 year ago)

Absolutely this, shuf would easily come up in a normal google search (even in googles deteriorated relevancy).

For fun, "two" lines of bash + jq can easily achieve the result even without shuf (yes I know this is pointlessly stupid)

cat /usr/share/dict/words | jq -R > words.json
cat /dev/urandom | od -A n -D | jq -r -n '
  import "words" as $w;
  ($w | length) as $l |
  label $out | foreach ( inputs * $l / 4294967295 | floor ) as $r (
    {i:0,a:[]} ;
    .i = (if .a[$r] then .i  else .i + 1 end) | .a[$r] = true ;
    if .i > 100 then break $out else $w[$r] end
  )
'

Incidentally this is code that ChatGPT would be utterly incapable of producing, even as toy example but niche use of jq.

view more: ‹ prev next ›