ShareMyScreen/AdventOfCode/2022/14/RegolithReservoir
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