ShareMyScreen/AdventOfCode/2022/01/CalorieCounting

From J Wiki
Jump to navigation Jump to search

The Problem >>

The input is going to come from the clipboard in character form and I need to convert it to integers and then group using the blank lines. In J, all items of an array must have the same shape. When, as here, the items have different shapes, we enclose each item in a box. A box has the shape of an atom and can have any noun value as contents, so it provides a way to get the effect of ragged arrays.

I start by cutting the input into lines and then executing each line, leaving the line's result in a box. I'll start on the example data, putting it onto the clipboard and pasting it into a J session:

   wd 'clippaste'
1000
2000
3000

4000

5000
6000

7000
8000
9000

10000

Now to separate the lines. I use Selfintervals-Cut, (x u;._2 y), to process the LF-terminated lines. It breaks the array into pieces where each piece ends just before an item that matches the last item of the overall array; then it applies u to each piece. As my u I use <@". which executes each line and then puts the result into a box. The execution will produce either a single number or an empty list.

   ] lines =. <@".;._2 wd 'clippaste'
|spelling error (invalid character in sentence, code unit 10)
|   
2
|   ^
|   ]lines=.    ".;._2 wd'clippaste'

How's that? Spelling error? That means an invalid character in the line. Code point 10 is a linefeed, but those should have been line separators. What's in that line, anyway?

   a. i. wd 'clippaste'
49 48 48 48 10 50 48 48 48 10 51 48 48 48 10 10 52 48 48 48 10 10 53 48 48 48 10 54 48 48 48 10 10 55 48 48 48 10 56 48 48 48 10 57 48 48 48 10 10 49 48 48 48 48

a. is all the ASCII characters, so a. i. is finding the ASCII code for each character on the clipboard. Look, the input ends with '0' (48) instead of LF (10). Yes, when I go back to the browser I see that the trailing LF was not picked up. Easy enough to put it on:

   ] lines =. <@".;._2 LF ,~ wd 'clippaste'
+----+----+----++----++----+----++----+----+----++-----+
|1000|2000|3000||4000||5000|6000||7000|8000|9000||10000|
+----+----+----++----++----+----++----+----+----++-----+

That's more like it. x , y joins two noun values together, and ~ means switch the arguments, so the code appended LF to the end of the clipboard. Then it chopped the resulting string into pieces that end with the last character (;._2) and executes each piece as a sentence (". y) and encloses the result of execution in a box (< y). The result is a list of boxes, one for each line.

I am going to have to read data twice for every problem (once for the example data and once for my puzzle input), so I define a template that I can use to do that.

onaoclines =: {{ u;._2 LF ,~ wd 'clippaste' }}  NB. Adverb: apply u to lines of clipboard

Now what am I to do with this data? Yes, I'm to add all the numbers that come between empty lines. I must group the lines between the empty lines. That's another job for u;._2, this time with a u that will sum the contents of the boxes. That verb will be (+/@;), in which ; y runs the numbers into a list, followed by +/ y to add them.

I also need an empty box (a:) at the end to terminate the last elf's data:

   ] elftotals =. +/@; ;._2 lines , a:
6000 4000 11000 24000 10000

If you have trouble following that, I'll separate the grouping and the summation by enclosing each group in a box.

NB. slow-motion replay
   <;._2 lines , a:
+----------------+------+-----------+----------------+-------+
|+----+----+----+|+----+|+----+----+|+----+----+----+|+-----+|
||1000|2000|3000|||4000|||5000|6000|||7000|8000|9000|||10000||
|+----+----+----+|+----+|+----+----+|+----+----+----+|+-----+|
+----------------+------+-----------+----------------+-------+
   ] 1000;2000;3000  NB. A list of boxes
+----+----+----+
|1000|2000|3000|
+----+----+----+
   ; 1000;2000;3000   NB. Contents run together
1000 2000 3000
   +/ ; 1000;2000;3000  NB. Contents totaled
6000

There are 5 groups, each a list of boxes.

What was I asked for? The largest number in the list?

   >./ elftotals
24000

I get my test input (which is missing the trailing LF, just like the example data), rerun the 3 lines, and submit my answer. It is correct, as expected, and I get puzzle part 2.

It is to get the total of the top 3 numbers in elftotals. That is, the sum of the first 3 numbers in elftotals after it has been sorted into descending order:

   +/ 3 {. \:~ elftotals
45000

Sort, take 3 biggest values, add 'em up. Step by step it looks like:

NB. slow-motion replay
   \:~ elftotals   NB. sort descending
24000 11000 10000 6000 4000
   3 {. \:~ elftotals  NB. take first 3 items of sorted list
24000 11000 10000
   +/ 3 {. \:~ elftotals  NB. add em up