aoc-all

My solutions to all Advent of Code
git clone https://git.instinctive.eu/aoc-all.git
Log | Files | Refs | README | LICENSE

day05.ps (8874B)


      1 %!PS
      2 %
      3 % Copyright (c) 2022, Natacha Porté
      4 %
      5 % Permission to use, copy, modify, and distribute this software for any
      6 % purpose with or without fee is hereby granted, provided that the above
      7 % copyright notice and this permission notice appear in all copies.
      8 %
      9 % THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
     10 % WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     11 % MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
     12 % ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     13 % WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
     14 % ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
     15 % OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     16 %
     17 % Usage:
     18 % gs -q- -sDEVICE=png16m -o- day05.ps <day05.txt | display
     19 
     20 /str_to_int {
     21   0 exch { exch 10 mul add 48 sub } forall
     22 } bind def
     23 
     24 /int_to_str {
     25   % number
     26   1 10
     27   { % number length upper-bound
     28     2 index 1 index lt { exit } if
     29     exch 1 add exch 10 mul } loop
     30   pop dup string exch 1 sub
     31   { % number string index
     32     2 copy 1 sub 5 1 roll exch
     33     % next_index number string string index
     34     3 index 10 mod 48 add
     35     % next_index number string string index digit
     36     put
     37     % next_index number next_string
     38     3 1 roll 10 idiv
     39     % next_string next_index next_number
     40     dup 0 eq { pop pop exit } if
     41     % next_string next_index next_number
     42     3 1 roll
     43     % next_nubmer next_string next_index
     44   } loop
     45 } bind def
     46 
     47 /datafile (%stdin) (r) file def
     48 /stderr (%stderr) (w) file def
     49 
     50 % line-array line -> updated-line-array
     51 /parse-init {
     52   1 4 2 index length 1 sub {
     53     % line-array line char-index
     54     2 copy get
     55     % line-array line char-index cur-char
     56     exch 4 idiv
     57     % line-array line cur-char col-index
     58     exch 3 index 3 1 roll put
     59     % updated-line-array line
     60   } for
     61   % updated-line-array line
     62   pop
     63   % updated-line-array
     64 } bind def
     65 
     66 % array-of-arrays line-index col-index -> array-of-arrays selected-char
     67 /get-cell {
     68   3 copy pop get
     69   % array-of-arrays line-index col-index selected-line
     70   exch get
     71   % array-of-arrays line-index selected-char
     72   exch pop
     73   % array-of-arrays selected-char
     74 } bind def
     75 
     76 % array-of-arrays line-index col-index selected-char -> updated-array-of-arrays
     77 /put-cell {
     78   % array-of-arrays line-index col-index selected-char
     79   3 index 3 index get
     80   % array-of-arrays line-index col-index selected-char prev-line
     81   dup 4 2 roll put
     82   % array-of-arrays line-index updated-line
     83   2 index 4 1 roll put
     84   % updated-array-of-arrays
     85 } bind def
     86 
     87 % array-of-arrays col-index -> array-of-arrays line-count
     88 /stack-height {
     89   0 1 3 index length 1 sub {
     90     % array-of-arrays col-index line-index
     91     3 copy exch get-cell exch pop
     92     % array-of-arrays col-index line-index selected-char
     93     32 eq { exit } if
     94     % array-of-arrays col-index line-index
     95     pop
     96   } for
     97   % array-of-arrays col-index line-count
     98   exch pop
     99   % array-of-arrays line-count
    100 } bind def
    101 
    102 % (move X from Y to Z) -> X Y Z
    103 /parse-move {
    104   % (move X from Y to Z)
    105   (move ) anchorsearch
    106   not { quit } if pop
    107   % (X from Y to Z)
    108   ( from ) search
    109   not { quit } if
    110   % (Y to Z) ( from ) (X)
    111   str_to_int exch pop exch
    112   % X (Y to Z)
    113   ( to ) search
    114   not { quit } if
    115   str_to_int exch pop exch
    116   % X Y (Z)
    117   str_to_int
    118   % X Y Z
    119 } bind def
    120 
    121 % array-of-arrays X Y Z -> updated-array-of-arrays
    122 /run-move-1 {
    123   1 sub exch 1 sub exch
    124   % array-of-array count col-source col-dest
    125   3 2 roll {
    126     % array-of-array col-source col-dest
    127     3 2 roll
    128     % col-source col-dest array-of-array
    129     2 index stack-height 1 sub
    130     % col-source col-dest array-of-array line-source
    131     dup 3 1 roll
    132     % col-source col-dest line-source array-of-array line-source
    133     4 index get-cell
    134     % col-source col-dest line-source array-of-array moved-char
    135     3 1 roll exch 4 index
    136     % col-source col-dest moved-char array-of-array line-source col-source
    137     32 put-cell
    138     % col-source col-dest moved-char array-of-array
    139     2 index stack-height
    140     % col-source col-dest moved-char array-of-array line-dest
    141     3 index 3 index put-cell
    142     % col-source col-dest moved-char updated-array-of-array
    143     4 1 roll pop
    144     % updated-array-of-array col-source col-dest
    145   } repeat
    146   % updated-array-of-array col-source col-dest
    147   pop pop
    148   % updated-array-of-array
    149 } bind def
    150 
    151 % array-of-arrays X Y Z -> updated-array-of-arrays
    152 /run-move-2 {
    153   1 sub exch 1 sub exch
    154   % array-of-array count col-source col-dest
    155   3 index 2 index stack-height exch pop
    156   % array-of-array count col-source col-dest source-height
    157   3 index sub
    158   % array-of-array count col-source col-dest first-source-line
    159   4 index 2 index stack-height exch pop
    160   % array-of-array count col-source col-dest first-source-line dest-height
    161   5 4 roll {
    162     % array-of-array col-source col-dest line-source line-dest
    163     5 4 roll
    164     % col-source col-dest line-source line-dest array-of-array
    165     2 index 5 index get-cell exch
    166     % col-source col-dest line-source line-dest moved-char array-of-array
    167     3 index 6 index 32 put-cell
    168     % col-source col-dest line-source line-dest moved-char updtd-array-of-array
    169     2 index 5 index 4 3 roll put-cell
    170     % col-source col-dest line-source line-dest updtd-array-of-array
    171     5 1 roll
    172     % updated-array-of-array col-source col-dest line-source line-dest
    173     exch 1 add exch 1 add
    174     % updtd-array-of-array col-source col-dest updtd-line-source updtd-line-dest
    175   } repeat
    176   pop pop pop pop
    177   % updated-array-of-array
    178 } bind def
    179 
    180 /data-width 12 def
    181 /data-height 50 def
    182 
    183 [ data-height { [ data-width { 32 } repeat ] } repeat ]
    184   {
    185     datafile 100 string readline
    186     not {pop exit} if
    187     % array-of-arrays line
    188     dup 1 get 49 eq { pop exit } if
    189     % array-of-arrays stack-line
    190     [ data-width { 32 } repeat ] exch parse-init
    191     % array-of-arrays line-array
    192     exch aload
    193     % new-line-array line-array-0 line-array-1 … line-array-n-1 array-of-arrays
    194     exch pop
    195     % new-line-array line-array-0 line-array-1 … line-array-n-2 array-of-arrays
    196     astore
    197     % updated-array-of-arrays
    198   } loop
    199 % init-array-of-arrays
    200   dup {
    201     {
    202       stderr exch write
    203     } forall
    204     stderr 10 write
    205   } forall
    206 % init-array-of-arrays
    207   datafile 100 string readline
    208   pop pop
    209 % init-array-of-arrays
    210 [
    211   {
    212     datafile 100 string readline
    213     not {pop exit} if
    214     % line
    215     parse-move
    216     % X Y Z
    217     3 array astore
    218     % move
    219   } loop
    220 ]
    221 % init-array-of-arrays move-list
    222 
    223 /rebuild {
    224   [ 1 index { } forall ]
    225   exch pop
    226 } bind def
    227 
    228 /deep-rebuild {
    229   [ 1 index { rebuild } forall ]
    230   exch pop
    231 } bind def
    232 
    233 2 copy rebuild exch deep-rebuild exch
    234 % init-array-of-arrays move-list copy-of-array-of-arrays move-list-copy
    235 
    236 {
    237   aload pop
    238   run-move-1
    239 } forall
    240 
    241 % init-array-of-arrays move-list final-array-of-arrays
    242 
    243 /Helvetica 20 selectfont
    244 
    245 (First Puzzle: )
    246 72 700 moveto show
    247 % array-of-arrays
    248 data-width string
    249 0 1 data-width 1 sub {
    250   % array-of-arrays top-line cur-col
    251   2 index 1 index stack-height
    252   % array-of-arrays top-line cur-col array-of-arrays line-count
    253   dup 0 eq { pop data-height } if
    254   1 sub
    255   % array-of-arrays top-line cur-col array-of-arrays cur-line
    256   2 index get-cell
    257   % array-of-arrays top-line cur-col array-of-arrays cur-char
    258   exch pop
    259   % array-of-arrays top-line cur-col cur-char
    260   2 index 4 1 roll put
    261   % array-of-arrays updated-top-line
    262 } for
    263 show
    264 
    265 % reset
    266 pop
    267 2 copy rebuild exch deep-rebuild exch
    268 % init-array-of-arrays move-list copy-of-array-of-arrays move-list-copy
    269 
    270 {
    271   aload pop
    272   run-move-2
    273 } forall
    274 
    275 % init-array-of-arrays move-list final-array-of-arrays
    276 
    277 (Second Puzzle: )
    278 72 664 moveto show
    279 % array-of-arrays
    280 data-width string
    281 0 1 data-width 1 sub {
    282   % array-of-arrays top-line cur-col
    283   2 index 1 index stack-height
    284   % array-of-arrays top-line cur-col array-of-arrays line-count
    285   dup 0 eq { pop data-height } if
    286   1 sub
    287   % array-of-arrays top-line cur-col array-of-arrays cur-line
    288   2 index get-cell
    289   % array-of-arrays top-line cur-col array-of-arrays cur-char
    290   exch pop
    291   % array-of-arrays top-line cur-col cur-char
    292   2 index 4 1 roll put
    293   % array-of-arrays updated-top-line
    294 } for
    295 show
    296 
    297 showpage
    298 quit
    299 
    300 % Thinking back about these solutions, I realize I went through them with
    301 % a kind of "functional" mindset, with immutable objects and functions
    302 % returns a new object built from the old one, while PostScript primitives
    303 % have more of a "referential" paradigm, e.g. "put" functions pop the
    304 % composite from the stack and modify it in place, leaving it to be accessed
    305 % from another reference. There are several places where fighting the
    306 % PostScript doesn't go well, e.g. with the rebuild and deep-rebuild.
    307 %
    308 % I should also probably have used a linear array for storage, the lack of
    309 % clarity of copies vs references was compounded by the use of an array of
    310 % arrays, instead of using a linear array and modular arithmetic to map
    311 % 2D coordinates into a linear index.