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.