Advent of Code’s day eleven puzzle asks us to compute a three hundred square grid of values and to find the three by three sub-grid that contains the highest sum of values. In my heart of hearts I knew that this would be a problem well suited to the J programming language.

I started by working on a verb to break a grid into a number of sub-grids of a given size. This reminded me quite a bit of Elixir’s `Enum.chunk_every/4` function, so I decided to name it accordingly:

``````    grid =. 5 5 \$ i. 25
grid
0  1  2  3  4
5  6  7  8  9
10 11 12 13 14
15 16 17 18 19
20 21 22 23 24
chunk_every =. [ <\"2 [: |:"2 [: > <\
3 chunk_every grid
┌────────┬────────┬────────┐
│0 5 10  │1 6 11  │2 7 12  │
│1 6 11  │2 7 12  │3 8 13  │
│2 7 12  │3 8 13  │4 9 14  │
├────────┼────────┼────────┤
│5 10 15 │6 11 16 │7 12 17 │
│6 11 16 │7 12 17 │8 13 18 │
│7 12 17 │8 13 18 │9 14 19 │
├────────┼────────┼────────┤
│10 15 20│11 16 21│12 17 22│
│11 16 21│12 17 22│13 18 23│
│12 17 22│13 18 23│14 19 24│
└────────┴────────┴────────┘
``````

To be totally transparent, I originally came up with this verb by tinkering in the REPL, and converted it into a tacit verb after the fact.

Now that we have `chunk_every`, we can define a few more needed values, like our initial grid, our grid size, and our grid serial number:

``````    size =. 300
grid =. (size,size) \$ i. size * size
grid_serial_number =. 9424
``````

The puzzle tells us how to convert our initial grid’s x/y coordinates into “fuel cell values”. Let’s write an `init` verb that takes our initial verb and calculates and populates those values:

``````    init =. 3 : 0
'cy cx' =. (0,size)#:y
rack_id =. cx + 10
power =. rack_id*cy
power =. power + grid_serial_number
power =. power * rack_id
power =. 10 | power <.@% 100
power =. power - 5
power
)
``````

Now we’re ready to start. We’ll begin by generating our grid of fuel cells:

``````    grid =. init"0 grid
``````

Next, we’ll break our grid into three by three chunks:

``````    chunks =. 3 chunk_by grid
``````

Once we have our sub-grids, we’ll calculate the sum of each and flatten that into a one dimensional array of sums:

``````    flat_chunks =. , +/"1 ,"2 > chunks
``````

And find the maximum sub-grid sum:

``````    max =. >./ flat_chunks
``````

And the corresponding index of that maximum sum:

``````    highest =. flat_chunks i. >./ flat_chunks
``````

Finally, we can turn that index into a pair of x/y coordinates:

``````    |. (0,(size-2))#:highest
``````

This is the answer to our puzzle. Victory!

Our fuel cells, visualized.

Just for fun, we can check out what our newly initialized fuel cell matrix looks like with the help of `viewmat`. We can see some cool Moiré patterns in the resulting visualization as a side effect of our calculations.

Part Two

Part two wants us to vary the size of our sub-grids, and find the sub-grid size, and x/y coordinate pair that has the most amount of available fuel, or the highest sum.

My first instinct was to run `chunk_by` multiple times against chunk sizes ranging from `1` to `300`:

``````    chunks =. (grid&(<@:chunk_by~))"0 (1 + i. size)
``````

I wrote a verb to `count` the amount of available fuel within each new set of sub-grids, and ran that against all of the sub-grid sets I was generating:

``````    count =. 3 : 0
chunks =. > y
chunk_size =. # 0 0 {:: chunks
flat_chunks =. , +/"1 ,"2 > chunks
max =. >./ flat_chunks
highest =. flat_chunks i. >./ flat_chunks
coord =. |. (0,(size-(chunk_size-1)))#:highest
max;coord,chunk_size
)

counts =. count"_1 chunks
``````

From there, I could grab the best score of all of the sub-grid sizes, find the max, and return a tuple of that winning sub-grid’s size, and its x/y coordinate:

``````    scores =. > 0 {"1 counts
idx =. scores i. >./ scores
1 {:: idx { counts
``````

Unfortunately, this turned out to be too slow of a solution.

Thankfully, there were some patterns to be found that let us speed things up considerably! If we `plot` our `counts` with a max grid size of `10`, `50`, and `100`, we can see that our score always peaks almost immediately. We don’t need to test larger sub-grid sizes because we know our answer won’t be there.

A plot of our sub-grid size vs our maximum fuel availability.

Let’s change our solution to only check sub-grid sizes from one to twenty:

``````    chunks =. (grid&(<@:chunk_by~))"0 (1 + i. size)
``````

And just like that, we get an answer almost immediately.

Thanks J!