I was able to proceed further. I simply tried to save on port 1 (that is still ram) the largest variables I could identify.
I am unsure whether it really helped, as I think the variable is still pushed to the stack if needed, but maybe having the values on the stack and in a variable (local or global) is too much. I thought that the same value would be referenced instead of being there twice, but actually it seems there twice or something similar, as otherwise the port0 free space would have been enough.
Thus I can get the map state in a large matrix (102k), now I need to actually solve part1 and 2 (of Day 14).
Code:
gvSmallLarge
"S" @S small, L large
gvMinX
500
gvMaxX
500
gvMaxY
500
gvMatrixState
""
gpSTOMatrixState
@ because memory is limited, trying to use other memory for large variables
@ update: doing this somehow helped. Normally I would run out of memory (out of 215k in port0)
@ I am not totally sure whether having the same object in multiple locations, say
@ stack and global variables, means saving it only once and then having many references
@ or saving it multiple times. If it is the latter, then yes having a stack copy and
@ a global var in another port (port1 or 2 or 3) would help indeed. If it is the former,
@ then I don't see how it helps as the (larger) value is there really only once.
@ Anyway it seems that it helps a bit to put away large var, so I'll try to do it
@ more often when possible.
@ Better would be really paging, so having parts of the large variable in memory,
@ work on them and then move those away. But that is a lot of work.
\<<
@LVL1 matrix state
:1:gvMatrixState @it seems I cannot simply overwrite an object in a port if it is referenced.
@thus I deactivated the "last arguments" (flag -55)
DUP PURGE @nonetheless I need first to explicity purge the element saved, then can I store it.
STO
\>>
gpRCLMatrixState
\<<
:1:gvMatrixState
RCL
\>>
gpPickInput
\<<
IF gvSmallLarge "S" ==
THEN
gvInputSmall
ELSE
gvInput
END
\>>
gpProcessInput
@it goes through the input and extracts the pairs x,y
@to identify the lines to draw and also how large the system will be
@notice that the system will be determined, from the bottom (starting y is 0),
@from the source of the problem, left, right and top. Those borders will be
@touched by impassable lines.
\<<
@input
@localVar
"" "lvChar" DROP
10 CHR "lvLFChar" DROP
0 "lvInputSize" DROP
@0 "lvReadXYPair" DROP
0 "lvReadX" DROP @one can see X as columns and Y as rows
0 "lvReadY" DROP
"" "lvReadValue" DROP
500 "lvMinX" DROP @the smallest value of X that we find
500 "lvMaxX" DROP @ the biggest value of X
0 "lvMaxY" DROP @ the biggest value of Y
@{} "lvXYPair" DROP
{} "lvSegmentList" DROP
{} "lvAllSegments" DROP
1 "lvAllSegmentsPos" DROP
\->
@input
@localVar
lvChar
lvLFChar
lvInputSize
@lvReadXYPair
lvReadX
lvReadY
lvReadValue
lvMinX
lvMaxX
lvMaxY
@lvXYPair
lvSegmentList
lvAllSegments @ a list of (x,y) pairs, where two consecutive pairs define a segment.
@ nope a list grows or is edited too slowly in userRPL. let's try with an array.
lvAllSegmentsPos
\<<
@now I wanted to extract x and y in a "quick" way, using the position
@of commas, dashes and carriage returns but I see it too long to debug;
@and thus long dev time. Therefore I make it a bit dumber but quicker in dev time.
@ Also I may extract the xy in lists or complex numbers (at the end is an ad hoc parser
@ that can make use of what we have)
@we populate the array that will contain the result at first with dummy values
@ (0,-1) complex numbers. This because then the saving operations will be quicker.
@ The estimate is: 1 entry every 4 chars in the input, thus:
0 -1 R\->C gpPickInput SIZE 4 / IP NDUPN \->ARRY 'lvAllSegments' STO @I could have used CON
@reset the global values
500 'gvMinX' STO
500 'gvMaxX' STO
0 'gvMaxY' STO
gpPickInput SIZE 'lvInputSize' STO
1 lvInputSize
FOR lvPos
IF lvAllSegmentsPos 100 MOD 0 ==
@ I want feedback on the large loop
THEN
CLLCD lvAllSegmentsPos 1 DISP 2 WAIT
END
gpPickInput lvPos lvPos SUB 'lvChar' STO
CASE
"0" lvChar \<=
lvChar "9" \<=
AND
THEN
'lvReadValue' lvChar STO+
END
"," lvChar ==
THEN
@ we read X
lvReadValue OBJ\-> 'lvReadX' STO
@reset vars
"" 'lvReadValue' STO
END
" " lvChar ==
lvLFChar lvChar ==
OR
THEN
IF lvReadValue SIZE 0 >
THEN
@ we read Y
lvReadValue OBJ\-> 'lvReadY' STO
@ we save XY as complex number (alternative: list)
@'lvSegmentList' ( lvReadX , lvReadY ) STO+ @@this somehow doesn't work
@'lvSegmentList' lvReadX lvReadY R\->C STO+
lvAllSegments
lvAllSegmentsPos
lvReadX lvReadY R\->C
PUTI
'lvAllSegmentsPos' STO
'lvAllSegments' STO
@ we also update the min/max values (thus we cannot yet work on our "map")
IF lvReadX gvMinX < THEN lvReadX 'gvMinX' STO END
IF lvReadX gvMaxX > THEN lvReadX 'gvMaxX' STO END
IF lvReadY gvMaxY > THEN lvReadY 'gvMaxY' STO END
@reset other vars
"" 'lvReadValue' STO
IF
lvLFChar lvChar ==
THEN
@ new line and we restart everything
0 'lvReadX' STO
0 'lvReadY' STO
END
END
END
"-" lvChar ==
THEN
@ we are going to another XY pair
@ we, can, though, start a new segment if needed
IF lvAllSegmentsPos 2 MOD 1 == @then we collected enough entries to start a new segment
@note that the position points to the next index to save
@thus only when we have a odd number we can say (in conjution with having read a "-")
@that we are going to a next segment.
THEN
@ the entries saved already defines a segment
@ start a new one, using the current entry
lvAllSegments @where to store
lvAllSegmentsPos @the position
lvAllSegments lvAllSegmentsPos 1 - GET @the entry to duplicate
PUTI
'lvAllSegmentsPos' STO
'lvAllSegments' STO
END
@ we can speed up things moving the position cursor since the input format is known.
'lvPos' 2 STO+ @then there is the NEXT operation that increments to add a +1
END
@lvLFChar lvChar ==
@THEN
@ @@ new line and we restart everything after saving
@ IF lvSegmentList SIZE 2 ==
@ THEN
@ @@ the segment list already defines a segment
@ 'lvAllSegments' lvSegmentList STO+
@ END
@ "" 'lvReadValue' STO
@ {} 'lvSegmentList' STO
@ 0 'lvReadX' STO
@ 0 'lvReadY' STO
@END
END @case on the char
NEXT @for all chars
@ trim the vector containing the entries, removing summy values and saving memory.
lvAllSegments 1 lvAllSegmentsPos 1 - SUB
\>>
\>>
gpAdjSegmentValues
@ the input has values that are big on purpose, like the starting point
@ having an x of 500. Due to memory limits we are going to limit this and build a matrix
@ hopefully it will work.
@ One alternative could be a graphic object.
\<<
{} "lvAllSegments" DROP
\->
@input
@localVar
lvAllSegments
\<<
gpProcessInput 'lvAllSegments' STO
@we cannot really fix the Y value (the rows), but we can fix the X value (the columns)
@remembering that the indexes start from 1.
@ this is actually good for list processing. Or not even list processing, array works too at times.
@we create an array of entries that have to be subtracted from the read input.
lvAllSegments @to subtract from
gvMinX 1 - @x, remember we need to keep the index starting from 1
0 @y
R\->C @(x,y)
lvAllSegments SIZE 1 GET @because the size of an array is a list
NDUPN \->ARRY @array created . I could have used CON
- @reduce the x values
\>>
\>>
gpBuildMatrix
@ from the segments we build the matrix that represent the state
\<<
{} "lvAllSegments" DROP
0 "lvAllSegmentsSize" DROP
1 "lvEmptyValue" DROP
6 "lvRockValue" DROP @visibility
0 "lvSandValue" DROP @visibility
@1111111111
@1116111111
@1116111111
@1116111111
@6666111111
0 "lvSegmentStart" DROP @
0 "lvSegmentEnd" DROP @
0 "lvSegmentDiff" DROP @
0 "lvSegmentX" DROP @
0 "lvSegmentY" DROP @
0 "lvTempArr" DROP @
\->
@input
@localVar
lvAllSegments
lvAllSegmentsSize
lvEmptyValue
lvRockValue
lvSandValue
lvSegmentStart
lvSegmentEnd
lvSegmentDiff
lvSegmentX
lvSegmentY
lvTempArr
\<<
gpAdjSegmentValues DUP 'lvAllSegments' STO
SIZE 1 GET 'lvAllSegmentsSize' STO
@we cannot really fix the Y value (the rows), but we can fix the X value (the columns)
@remembering that the indexes start from 1.
@ this is actually good for list processing. Or not even list processing, array works too at times.
gvMaxY @The initial row in the problem is the row 0 that is producing the sand
@thus we likely do not need to account for the initial row as in RPL indexes start from 1
gvMaxX gvMinX - 1 + @column size, including an extreme
2 \->LIST
lvEmptyValue CON
@'gvMatrixState' STO
gpSTOMatrixState
1 lvAllSegmentsSize
FOR lvPos @not a DOSUB because debugging those is not easy if the operations aren't trivial
IF lvPos 100 MOD 1 ==
@ I want feedback on the large loop
@ mod 1 because we start from pos 1 and we jump every time some steps.
THEN
CLLCD lvPos 1 DISP 2 WAIT
END
lvAllSegments
lvPos lvPos 1 +
SUB @trying to avoid recalling large vars multiple times where I am able to do it.
OBJ\-> DROP @leaves two complex numbers on the stack.
@START
@END
'lvSegmentEnd' STO
'lvSegmentStart' STO
@check which dimension is the same
CASE
lvSegmentStart RE lvSegmentEnd RE == @the x is the same
THEN
@ then is the y that changes.
lvSegmentStart RE 'lvSegmentX' STO
lvSegmentStart IM lvSegmentEnd IM 2 \->LIST SORT 'lvSegmentDiff' STO @we need the elements from small to big.
@ now we get the column that is represended by x
@gvMatrixState lvSegmentX COL- 'lvTempArr' STO 'gvMatrixState' STO
gpRCLMatrixState lvSegmentX COL- 'lvTempArr' STO gpSTOMatrixState
@modify the COL (that is an array) so that it contains rock value in the right points
@create the substituting values via an array that will replace parts
@gvMatrixState @@the matrix to rebuild
gpRCLMatrixState @the matrix to rebuild
lvTempArr @the source to modify
lvSegmentDiff 1 GET @from where to start to replace
lvSegmentDiff \GDLIST { 1 } ADD @the diff between rows, +1 including one extreme.
@Example: if we want the rows 2 3 4, the diff is 4-2 +1
lvRockValue
CON @creates the array that goes replacing the Col
REPL @modifies the tempArr
lvSegmentX COL+ @readds the col
@'gvMatrixState' STO @@stores the state
gpSTOMatrixState
END
lvSegmentStart IM lvSegmentEnd IM == @the y is the same
THEN
@ then is the x that changes.
lvSegmentStart IM 'lvSegmentY' STO
lvSegmentStart RE lvSegmentEnd RE 2 \->LIST SORT 'lvSegmentDiff' STO @we need the elements from small to big.
@ now we get the row that is represended by y
@gvMatrixState lvSegmentY ROW- 'lvTempArr' STO 'gvMatrixState' STO
gpRCLMatrixState lvSegmentX ROW- 'lvTempArr' STO gpSTOMatrixState
@modify the ROW (that is an array) so that it contains rock value in the right points
@create the substituting values via an array that will replace parts
@gvMatrixState @@the matrix to rebuild
gpRCLMatrixState @the matrix to rebuild
lvTempArr @the source to modify
lvSegmentDiff 1 GET @from where to start to replace
lvSegmentDiff \GDLIST { 1 } ADD @the diff between colums, +1 including one extreme.
lvRockValue
CON @creates the array that goes replacing the row
REPL @modifies the tempArr
lvSegmentY ROW+ @readds the row
@'gvMatrixState' STO @@stores the state
gpSTOMatrixState
END
"modifying matrix state, this should not happen" DOERR
END
2 STEP @ two elements every time
@gvMatrixState
gpRCLMatrixState
\>>
\>>
gvInputSmall
@ MPOS of , ; - ; 13 CHR (carriage return)
"498,4 -> 498,6 -> 496,6
503,4 -> 502,4 -> 502,9 -> 494,9
"