ShareMyScreen/AdventOfCode/2022/02/RockPaperScissors
The first question is, How to think of the input? Is it one row per episode of rock/paper/scissors, or is it two lists giving the moves of each player? The way to decide is to consider what I will be doing with the information. Here, I am adding scores from each match, and I note that one component of the score is which choice I made: that doesn't depend on what the opponent did. That decides me to keep the information in two lists: one of the opponent's moves and one of mine.
As before, I will convert the input to numbers. Here there is a natural numbering system, since the scoring goes 'X'=1, 'Y'=2, 'Z'=3.
That tells me enough to read in the data. The steps are
- use onaoclines as before to operate on each line
- I will just pass each line through so that I have an nx3 array
- transpose the array (using |: y) and select the first and last lines (using x { y) to give 2 lists, one for each player
- convert those values to numbers - by arithmetic on their ASCII values
I put the example data on the clipboard and run
'them me' =. 1 + 'AX' -~&(a.&i.) 0 _1 { |: ] onaoclines them 1 2 3 me 2 1 3
Step by step:
NB. slow-motion replay ] onaoclines NB. read the data A Y B X C Z |: ] onaoclines NB. transpose ABC YXZ 0 _1 { |: ] onaoclines NB. select first and last line ABC YXZ a. i. 0 _1 { |: ] onaoclines NB. (a. i. y) gives the ASCII value of y 65 66 67 89 88 90 a. i. 'AX' 65 88 'AX' -~&(a.&i.) 0 _1 { |: ] onaoclines NB. subtract 'A' from first line, 'X' from last 0 1 2 1 0 2 1 + 'AX' -~&(a.&i.) 0 _1 { |: ] onaoclines NB. add 1 so rock=1 etc. 1 2 3 2 1 3
(x u&v y) applies v to x and y separately before executing u between the results of v. Here v is (a.&i.) which converts an ASCII character to its code number, and u is -~ which subtracts left from right.
Now simulate the scoring. There has to be a good way to do this. The scoring is loss=0, tie=3, win=6. I can subtract our picks and get 3 possible results, which seems hopeful. Suppose I subtract their pick from mine, and say I pick paper. Paper is 2. Their choices are rock/paper/scissors (1/2/3). The differences for those cases are 1/0/-1 which must correspond to the results win/tie/loss. That's the right order. I just need to add 1 to the difference to get 2/1/0. To handle all the possible values I need to take the remainder (mod 3) of the difference.
This analysis says that the component of the score coming from win/loss/tie should be 3 * 3 | 1+me-them. I'd better check that on all the possible input values:
{{ 3 * 3 | 1+x-y}}"0/~ 1 2 3 3 0 6 6 3 0 0 6 3
The verb takes my choice as x, their choice as y. I want to apply this verb to atoms (with "0) and I want to try it on all possible inputs, so I make a table (/) where both x and y take on the values 1 2 3 (both, because the ~ repeats the argument for both x and y). In the result, each row has the results of one of my choices: the second row says that if I pick paper, my score is 6/3/0 according to whether they pick rock/paper/scissors. Yes, that looks right.
With that out of the way, the scoring is easy. The component depending on my choices is simply the sum of my choices, and the component depending on the result is from the calculation I just worked out. Write it then:
+/ me , 3 * 3 | 1+me-them 15
With the correct result on the example input, I run my 2 sentences on my puzzle input:
'them me' =. 1 + 'AX' -~&(a.&i.) 0 _1 { |: ];._2 LF ,~ wd 'clippaste' +/ me , 3 * 3 | 1+me-them xxxx
In Part 2, I learn that I need to reinterpret my instructions as specifying the result rather than my selection. Without looking too deeply, I think I will just replace me with a value that gives the desired result.
If they play rock (1), to lose I would play scissors (3, i. e. 1+2), to tie I would play rock (1, i. e. 1+0), and to win I would play paper (2, i. e. 1+1). Should I just translate 1 2 3 to 2 0 1? That's ugly.
I'm regretting that I numbered the selections 123 rather than 012. I was distracted by the fact that the scoring was 123. The problem naturally uses modular arithmetic. I'm going to convert to 012 representation.
That clears my head. If they play rock (0), to lose I add _1 (mod 3), to tie I add 0, to win I add 1. I will convert me and them to 0-origin, calculate them+me-1, and then convert back to 1-origin so I can use the old program for scoring. (<: y) subtracts 1. Trying it on the example data:
me2 =. >: 3 | (<: them) + <: (<: me) +/ me2 , 3 * 3 | 1+me2-them 12
That's right.
Revision
I would normally write me2 as
me2 =. them (3 | (+ <:))&.<: me
but I didn't want to have to explain all the features involved in that.