https://adventofcode.com/2021/day/18

For day 18, the puzzle was about "snailfish sums".

sample=:{{)n
[1,2]
[[1,2],3]
[9,[8,7]]
[[1,9],[8,5]]
[[[[1,2],[3,4]],[[5,6],[7,8]]],9]
[[[9,[3,8]],[[0,9],6]],[[[3,7],[4,9]],3]]
[[[[1,3],[5,3]],[[1,3],[8,7]]],[[[4,9],[6,9]],[[8,2],[7,3]]]]
}}

Each line here was a "snailfish number".

A snailfish number consists of pairs of regular numbers and/or pairs.

And, each snailfish number has five operations defined on it: reduce,
explode, split, addition and magnitude:

reduce is a stepwise operation. A reduce step means that the leftmost
regular number which is greater than 9 explodes, and the leftmost
element of a pair which has been nested inside four other pairs
explodes. reduce itself is reducestep^:_ and is a required operation
on all snailfish numbers.

explode is a single step operation on a pair of regular numbers which
turns it into a single 0 in its containing pair.. If there's regular
numbers to the left of the pair, the left value from the exploding
pair is added to the rightmost of those regular numbers. If there's
regular numbers to the right of the pair, the rightmost value from the
exploding pair is added to the leftmost of those regular numbers.

split is a single step operation on a single regular number, which
turns it into a pair: (<.,>.)@-:

addition combines two snailfish numbers into a pair (which is then reduced).

The magnitude of a regular number is that regular number. The
magnitude of an x,y pair is (3*magnitude x)+2*magnitude y

------------------------------------------

At first, it might seem that putting pairs in boxes is the right
approach here. However, that makes the "explode" operation extremely
complicated.  So, instead, I used a two row array, where the first row
was nesting depth and the second row was regular numbers.

To convert the textual representation of snailfish numbers into this
form, I used:

use=: {{
   depth=. +/\-/'[]'=/y
   sel=. _1|.0 1 E.mask=.-.y e. '[,]'
   vals=.".mask #inv mask#y   assert. (+/sel)=#vals
   (sel#depth),:vals
}}

Next, I implemented an explode which repeated until no depths were
greater than 4 and a split which continued until no regular numbers
were greater than 9 (exploding each step of the way when depth gets
deep enough).

NB. the leftmost deepest pair is always the first pair at that depth
explode=: {{
  'depth vals'=. y
  while. 4 < d=.>./depth do.
    'j k'=.0 1+depth i.d
    vec=. 0 0
    loc=. j,k
    mask=. k~:i.#vals
    depth=. mask#(d-1) loc} depth
    if. 0~:j do.
      vec=. (+/vals{~j-1 0),vec
      loc=. (j-1),loc
    end.
    if. k<(#vals)-1 do.
      vec=. vec,+/vals{~k+0 1
      loc=. loc,k+1
    end.
    vals=. mask#vec loc}vals
    assert. depth -:&# vals
  end.
  depth,:vals
}}

NB. split always creates a pair one deeper than the number it replaces.
split=: {{
  'depth vals'=. y
  lim=. (#vals)-1
  while. lim>: j=. vals i.&1@:> 9 do.
    pair=. (<.,>.)-:j{vals
    depth=.(d=.1+j{depth) (j+0 1)} depth#~rep=.1+j=i.#depth
    vals=. pair (j+0 1)}vals#~rep
    if. 4<d do.
      'depth vals'=. explode depth,:vals
    end.
    lim=.(#vals)-1
  end.
  depth,:vals
}}

These routines are a bit verbose, but the problem specification
requires information be lost in a specific sequence, and I could not
think of how to parallelize that, nor could I figure out how to
further encode these operations numerically. (I did start to wish that
the jqt text editor would give me quick shortcuts to indent/outdent
blocks of code.)

Anyways, with these routines, reduce looks like this:

reduce=: {{
   split explode y
}}

I do not need to use an expression of the form reduce^:_ because split
(and explode) already implement their own ^:_ mechanisms.

And, add looks like this:

add=: {{
  reduce 1 0+x,.y
}}

And, magnitude looked like this:

magnitude=: {{
  'depth vals'=. y
  for_d. 1+i.->./{.y do.
    sel=. d=depth
    sums=. _2 +/\ (sel#vals) * f=.(+/sel)$3 2
    selb=. sel#inv b=.2|f
    mask=. (d>depth)+.selb
    depth=. (d-1)<.mask#depth
    vals=. mask #sums (I.selb)} vals
  end.
}}

And, the part A implementation was:

a18=: {{
  magnitude ;add~each/|.<@use;._2 y
}}

I used |. because the puzzle specified that addition proceeds from
left to right, and this kind of addition is not associative. It's also
not commutative, so I also had to use add~ instead of simply add, to
retain the original pair order here.

For part B, the problem was to find the largest magnitude from adding
two of the given sailfish numbers. So that was basically max reduce of
an outer produce

b18=: {{
  fish=: <@use;._2 y
  >./,magnitude@add every/~ fish
}}

FYI,

-- 
Raul
----------------------------------------------------------------------
For information about J forums see http://www.jsoftware.com/forums.htm

Reply via email to