So far the code for Day14 (no part is complete, that is simply for the input) is the following:
Code:
gvSmallLarge
"S" @S small, L large
gvMinX
500
gvMaxX
500
gvMaxY
500
gvMatrixState
""
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
1 lvAllSegmentsSize
FOR lvPos @not a DOSUB because debugging those is not easy if the operations aren't trivial
IF lvPos 100 MOD 0 ==
@ I want feedback on the large loop
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
@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
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
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
@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
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
END
"modifying matrix state, this should not happen" DOERR
END
2 STEP @ two elements every time
gvMatrixState
\>>
\>>
gvInputSmall
@ MPOS of , ; - ; 13 CHR (carriage return)
"498,4 -> 498,6 -> 496,6
503,4 -> 502,4 -> 502,9 -> 494,9
"
With the large input it says "out of memory" and this annoys me to no end. Not because the input is too large, or better it can be said so, but then there could be always another system with less memory, for example the casio 9860 GD has 61kb of memory if I am not wrong, in comparison the 50g has plenty.
The real reason is that the 50g has plenty of storage. First there is the ERAM that has those 128kb extra that cannot be really addressed. I know it is a limitation of the emulated OS, but still is super annoying, because the ram is there.
Second one could make a sort of "paging", for example making a list that contains part of the larger data structures (including overlapping and metadata) that get swapped in and out to ERAM or Flash storage ( unfortunately emu48 cannot simulate a SD card and thus it would be difficult to emulate paging there using SDfiler ). Anyway such swapping function would take quite a while as well and I instead would like to proceed with the problem.
In other words, would it be a system like the 48G Series, with a maximum of 128kb of ram, I would accept it without being annoyed, but with the 50g one could do more but the system makes it complicated.
Really a bummer. It could well be that there are approaches that are less memory intensive (my solutions are rarely optimal), yet I still think that the calculator could support even my solutions, had the ERAM be shared with the user. It is a pity because I really enjoyed trying to use functions that normally I barely used in the past, like manipulating strings, matrices and complex numbers. The matrix I am using to map the "state" of the system uses 102k of ram. If I would do only stackrobatics I think I could squeeze it in (otherwise it needs to be in memory AND reported on the stack). Only I don't enjoy stackrobatics.