part-02.fth 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. require string.fs
  2. : not 0= ;
  3. : even? dup 2 mod 0= ;
  4. : success -1 ;
  5. : failure 0 ;
  6. : input-filename s" input" ;
  7. : crlf-len 2 ;
  8. 256 Constant max-bytes-line
  9. Create line-buffer max-bytes-line crlf-len + allot
  10. input-filename r/o open-file throw Value puzzle-input-handle
  11. : upper-case? ( char -- flag )
  12. dup dup
  13. 65 >= swap 90 <= and ;
  14. : char-priority ( char -- score )
  15. upper-case? if
  16. 38 - \ upper-case letter shift to 27 - 52 is 38
  17. else
  18. 96 - \ lower-case letter shift to 1 - 26 is 96
  19. then ;
  20. \ tests
  21. char a char-priority 1 = 0= throw
  22. char b char-priority 2 = 0= throw
  23. char c char-priority 3 = 0= throw
  24. char d char-priority 4 = 0= throw
  25. char e char-priority 5 = 0= throw
  26. char f char-priority 6 = 0= throw
  27. char g char-priority 7 = 0= throw
  28. char h char-priority 8 = 0= throw
  29. char i char-priority 9 = 0= throw
  30. char j char-priority 10 = 0= throw
  31. char k char-priority 11 = 0= throw
  32. char l char-priority 12 = 0= throw
  33. char m char-priority 13 = 0= throw
  34. char n char-priority 14 = 0= throw
  35. char o char-priority 15 = 0= throw
  36. char p char-priority 16 = 0= throw
  37. char q char-priority 17 = 0= throw
  38. char r char-priority 18 = 0= throw
  39. char s char-priority 19 = 0= throw
  40. char t char-priority 20 = 0= throw
  41. char u char-priority 21 = 0= throw
  42. char v char-priority 22 = 0= throw
  43. char w char-priority 23 = 0= throw
  44. char x char-priority 24 = 0= throw
  45. char y char-priority 25 = 0= throw
  46. char z char-priority 26 = 0= throw
  47. char A char-priority 27 = 0= throw
  48. char Z char-priority 52 = 0= throw
  49. : char-in-string? ( c-addr len char -- c-addr len char flag )
  50. dup 2>r \ c-addr len char
  51. 2dup
  52. r>
  53. scan 0<>
  54. nip
  55. r> swap ;
  56. \ tests
  57. s" abc" char d char-in-string? throw drop drop drop
  58. s" abc" char b char-in-string? 0= throw drop drop drop
  59. : first-char ( c-addr len -- char )
  60. drop c@ ;
  61. s" abc" first-char char a = 0= throw
  62. s" rthsdasdfgfdfgabc" first-char char r = 0= throw
  63. : zero-string? ( c-addr len -- flag )
  64. 2dup 0= nip ;
  65. : non-empty-string? ( c-addr len -- flag )
  66. 2dup 0> nip ;
  67. : char->string ( c -- addr 1)
  68. here tuck c! 1 ;
  69. \ can only be created outside of definition???
  70. create empty-string 0 chars allot
  71. create result-string 128 chars allot
  72. : common-chars ( c-addr1 len1 c-addr2 len2 -- result-string )
  73. \ put empty string as neutral accumulation element
  74. s" " result-string place
  75. begin
  76. \ s" current result string:" type result-string count type cr
  77. non-empty-string? while
  78. \ c-addr1 len1 c-addr2 len2 | _
  79. 2dup 2>r
  80. \ c-addr1 len1 c-addr2 len2 | len2 c-addr2
  81. first-char
  82. \ c-addr1 len1 char | len2 c-addr2
  83. char-in-string?
  84. \ c-addr1 len1 char flag | len2 c-addr2
  85. if \ c-addr1 len1 char | len2 c-addr2
  86. char->string \ c-addr1 len1 char-as-string len | len2 c-addr2
  87. \ concat result string
  88. result-string +place \ c-addr1 len1 | len2 c-addr2
  89. \ cleanup return stack
  90. 2r> \ c-addr1 len1 c-addr2 len2 | _
  91. else
  92. \ drop the empty string char address
  93. drop \ c-addr1 len1 | len2 c-addr2
  94. 2r> \ c-addr1 len1 c-addr2 len2 | _
  95. then
  96. \ drop first character from string
  97. 1
  98. /string
  99. \ result-string len c-addr1 len1 c-addr2' len2' | _
  100. repeat
  101. 2drop 2drop
  102. result-string count ;
  103. \ tests
  104. create str1 256 chars allot
  105. create str2 256 chars allot
  106. s" aaaaaxbbby" str1 place
  107. s" xdddxeeye" str2 place
  108. str1 count str2 count
  109. common-chars s" xxy" compare throw
  110. s" gdfhzdujrz" str1 place
  111. s" aaaaaazuja" str2 place
  112. str1 count str2 count
  113. common-chars s" zuj" compare throw
  114. : read-ok? ( read-length eof-flag -- read-length flag )
  115. \ s" checking if read ok:" type .s cr
  116. swap dup 0 >
  117. rot
  118. and ;
  119. \ Read the strings of 3 lines from the input file and put
  120. \ them on the stack.
  121. : read-3-lines ( -- c-addr1 len1 c-addr2 len2 c-addr3 len3 )
  122. 3 0 ?DO
  123. \ read line from file
  124. \ clear line buffer
  125. line-buffer empty-buffer
  126. line-buffer max-bytes-line puzzle-input-handle read-line
  127. \ STACK: read-len eof-flag read-error-flag
  128. \ s" before checking if read ok:" type .s cr
  129. throw \ stack: acc length eof-flag
  130. \ check that everything was read OK from the line buffer
  131. read-ok?
  132. \ s" stack after read-ok?:" type .s cr
  133. if
  134. line-buffer swap \ acc c-addr length
  135. \ Check, that each line has an even number of characters.
  136. \ This is not strictly necessary, just trying out some
  137. \ validation and cleanup.
  138. even? if
  139. \ Remove trailing whitespace.
  140. -trailing
  141. else
  142. s" invalid input" type cr bye
  143. then
  144. then
  145. LOOP
  146. \ create success or failure flag
  147. dup 0<> ;
  148. : process-group ( c-addr1 len1 c-addr2 len2 c-addr3 len3 -- prio )
  149. .s cr
  150. 2dup 2>r type s" --" type 2dup 2>r type s" --" type 2dup 2>r type cr
  151. 2r> 2r> 2r>
  152. common-chars
  153. common-chars
  154. 2dup s" common chars of all 3 lines:" type type cr
  155. dup 0= if
  156. s" invalid input, no common character" type bye
  157. then
  158. \ common-chars len
  159. drop c@
  160. dup s" common char is:" type emit cr
  161. \ char
  162. char-priority ;
  163. \ tests
  164. Create a 256 allot s" aaabccc" a 256 insert a 7
  165. Create b 256 allot s" dddbeee" b 256 insert b 7
  166. Create c 256 allot s" fffbggg" c 256 insert c 7
  167. process-group char b char-priority = 0= throw
  168. \ this test somehow fails, wrong score?
  169. Create a 256 allot s" tdltdtmhlRNCBcwmHr" a 256 insert a 18
  170. Create b 256 allot s" WDzDPnvvGnsWLWpGJJHRzCCRZNBRrRwMNwHH" b 256 insert b 36
  171. Create c 256 allot s" DsDsQnJDnWsJnJvrQDPJddgShFQhjljqhggbdbbt" c 256 insert c 40
  172. process-group char r char-priority = 0= throw
  173. \ TODO: There is only 1 common char in the 2 halves of a
  174. \ string, but there may be multiple common chars within 2
  175. \ given lines! If one does not exist in all 3 lines, you
  176. \ need to try the next common char.
  177. : process ( c-addr length -- ??? )
  178. 0 \ accumulator value for score
  179. begin
  180. puzzle-input-handle file-eof? not
  181. while
  182. read-3-lines if
  183. process-group
  184. s" accumulating:" type .s cr
  185. +
  186. then
  187. repeat
  188. \ drop length of read characters from EOF read
  189. s" EOF reached:" type .s cr
  190. drop drop drop ;
  191. process . cr
  192. puzzle-input-handle close-file