ShareMyScreen/AdventOfCode/2022/14/RegolithReservoir

From J Wiki
Jump to navigation Jump to search

The Problem << >>

This simulation seems more interesting than the others so far. I will have to follow the course of each unit of sand, but I don't have to follow each one from the source: I'll remember the path each unit took until it came to rest, and start the next unit in the last cell vacated by the previous unit.

First to read the input. I think I can do this by executing each line as a sentence after proper modification. I will replace

  • , with `, which on nouns is like , but is a conjunction so it executes before verbs
  • -> with dl (for Draw Line), which will mark the occupied cells

I don't know how big to make the playing area. Glancing at my input I don't see anything that won't fit in 400x600 so that's what I'll use. I will change the coordinate system from (x,y) to (y,x) to match normal J display.

Now to write the verb to fill in a line-segment. I'll need to generate indexes from the startpoint to the endpoint, depending on which coordinate is changing. Then I can use a 2-dimensional amend (x (<y-values;x-values)} board) to fill them in.

Wait a minute! If I am using a 2-D fill, I should view the region to fill as a 2-D area rather than a line. Either the width or the height must be 1, but I don't have to know which.

The way to generate the list of indexes going from start to end inclusive is ((+ i.@>:)/ -~/\ start,end). This does a running subtract to convert (start,end) to (start,end-start), and then adds 0 1...end-start to start. You have to add 1 to the length to make the interval inclusive. This works only when end>:start so I'll need to sort the intervals into ascending order.

I start with (x0,y0) and (x1,y1) and I want to turn them into

x0 x1
y0 y1

then

y0 y1
x0 x1

then sort the rows into

ymin ymax
xmin xmax

then

ymin ylen-1
xmin xlen-1

and from there to the boxed index lists. The code is shorter than the description. I make sure that dl returns x as its result so that lines can be chained together.

board =. 400 600 $ 0  NB. empty boolean board
dl =: {{  NB. x is (pt0x,pt0y), y is (pt1x,pt1y)  we mark board filled in the intervening places.  Result is x
board =: 1 (< <@(+   i.@>:)/"1 -~/\"1 /:~"1 |. x,.y)} board
x
}}
   ".;._2 (',';'`';'->';'dl') stringreplace LF ,~ wd'clippaste'
498 4
503 4
   (0 492,:10 14) [;.0 board
0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 1 0 0 0 1 1 0 0
0 0 0 0 0 0 1 0 0 0 1 0 0 0
0 0 0 0 1 1 1 0 0 0 1 0 0 0
0 0 0 0 0 0 0 0 0 0 1 0 0 0
0 0 0 0 0 0 0 0 0 0 1 0 0 0
0 0 1 1 1 1 1 1 1 1 1 0 0 0

The definition of dl is one of those J moments when you think, 'where did the program go'?

The simulation is simple. I loop processing sand units until one runs away to a y value greater than, say, 399.

addsand =: {{    NB. Nilad.  modify board.  result is number of units that stopped
path =. ,: 0 500   NB. starting path
ndrops =. 0  NB. number we have dropped that stopped
while. do.   NB. till there is a runaway
  candcells =. (< (1;0 _1 1) +&.> {:path) { board  NB. candidates to drop to, in priority order
  if. candcells -: 1 1 1 do.
    board =: 1 (<{:path)} board [ ndrops =. ndrops+1  NB. stop.  Increment stop count, fill cell in board, back up to before we moved here
    path =. }: path
  else.
    if. 398 <: (<_1 0) { path do. ndrops return. end.  NB. if the unit escaped, we're done
    path =. path , ({: path) + 1 , {. (-. candcells) # 0 _1 1  NB. Take the highest-priority move down
  end.
end.
}}

I'll try it.

   addsand''
24

In Part 2, there is a floor and the sand runs until the input is blocked. That's a very small change: I'll just change my termination condition to be when path is empty. I think I'll make the board bigger, and I'll add the floor in addsand

board =. 400 1000 $ 0  NB. empty boolean board
   ".;._2 (',';'`';'->';'dl') stringreplace LF ,~ wd'clippaste'
addsand =: {{    NB. Nilad.  modify board.  result is number of units that stopped
path =. ,: 0 500   NB. starting path
ndrops =. 0  NB. number we have dropped that stopped
board =: 1 (2 + 1 i:~ +./"1 board)} board  NB. fill in the floor, 2 below the last 1
while. #path do.  NB. till the starting point has been filled
  candcells =. (< (1;0 _1 1) +&.> {:path) { board  NB. candidates to drop to, in priority order
  if. candcells -: 1 1 1 do.
    board =: 1 (<{:path)} board [ ndrops =. ndrops+1  NB. stop.  Increment stop count, fill cell in board, back up to before we moved here
    path =. }: path
  else.
    path =. path , ({: path) + 1 , {. (-. candcells) # 0 _1 1  NB. Take the highest-priority move down
  end.
end.
ndrops
}}
   addsand''
93