Post Reply 
Advents of Code (programming challenges)
12-24-2022, 07:14 PM (This post was last modified: 12-24-2022 07:24 PM by pier4r.)
Post: #24
RE: Advents of Code (programming challenges)
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.

Wikis are great, Contribute :)
Find all posts by this user
Quote this message in a reply
Post Reply 


Messages In This Thread
RE: Advents of Code (programming challenges) - pier4r - 12-24-2022 07:14 PM



User(s) browsing this thread: 1 Guest(s)