123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221 |
- require string.fs
- : not 0= ;
- : even? dup 2 mod 0= ;
- : success -1 ;
- : failure 0 ;
- : input-filename s" input" ;
- : crlf-len 2 ;
- 256 Constant max-bytes-line
- Create line-buffer max-bytes-line crlf-len + allot
- input-filename r/o open-file throw Value puzzle-input-handle
- : upper-case? ( char -- flag )
- dup dup
- 65 >= swap 90 <= and ;
- : char-priority ( char -- score )
- upper-case? if
- 38 - \ upper-case letter shift to 27 - 52 is 38
- else
- 96 - \ lower-case letter shift to 1 - 26 is 96
- then ;
- \ tests
- char a char-priority 1 = 0= throw
- char b char-priority 2 = 0= throw
- char c char-priority 3 = 0= throw
- char d char-priority 4 = 0= throw
- char e char-priority 5 = 0= throw
- char f char-priority 6 = 0= throw
- char g char-priority 7 = 0= throw
- char h char-priority 8 = 0= throw
- char i char-priority 9 = 0= throw
- char j char-priority 10 = 0= throw
- char k char-priority 11 = 0= throw
- char l char-priority 12 = 0= throw
- char m char-priority 13 = 0= throw
- char n char-priority 14 = 0= throw
- char o char-priority 15 = 0= throw
- char p char-priority 16 = 0= throw
- char q char-priority 17 = 0= throw
- char r char-priority 18 = 0= throw
- char s char-priority 19 = 0= throw
- char t char-priority 20 = 0= throw
- char u char-priority 21 = 0= throw
- char v char-priority 22 = 0= throw
- char w char-priority 23 = 0= throw
- char x char-priority 24 = 0= throw
- char y char-priority 25 = 0= throw
- char z char-priority 26 = 0= throw
- char A char-priority 27 = 0= throw
- char Z char-priority 52 = 0= throw
- : char-in-string? ( c-addr len char -- c-addr len char flag )
- dup 2>r \ c-addr len char
- 2dup
- r>
- scan 0<>
- nip
- r> swap ;
- \ tests
- s" abc" char d char-in-string? throw drop drop drop
- s" abc" char b char-in-string? 0= throw drop drop drop
- : first-char ( c-addr len -- char )
- drop c@ ;
- s" abc" first-char char a = 0= throw
- s" rthsdasdfgfdfgabc" first-char char r = 0= throw
- : zero-string? ( c-addr len -- flag )
- 2dup 0= nip ;
- : non-empty-string? ( c-addr len -- flag )
- 2dup 0> nip ;
- : char->string ( c -- addr 1)
- here tuck c! 1 ;
- \ can only be created outside of definition???
- create empty-string 0 chars allot
- create result-string 128 chars allot
- : common-chars ( c-addr1 len1 c-addr2 len2 -- result-string )
- \ put empty string as neutral accumulation element
- s" " result-string place
- begin
- \ s" current result string:" type result-string count type cr
- non-empty-string? while
- \ c-addr1 len1 c-addr2 len2 | _
- 2dup 2>r
- \ c-addr1 len1 c-addr2 len2 | len2 c-addr2
- first-char
- \ c-addr1 len1 char | len2 c-addr2
- char-in-string?
- \ c-addr1 len1 char flag | len2 c-addr2
- if \ c-addr1 len1 char | len2 c-addr2
- char->string \ c-addr1 len1 char-as-string len | len2 c-addr2
- \ concat result string
- result-string +place \ c-addr1 len1 | len2 c-addr2
- \ cleanup return stack
- 2r> \ c-addr1 len1 c-addr2 len2 | _
- else
- \ drop the empty string char address
- drop \ c-addr1 len1 | len2 c-addr2
- 2r> \ c-addr1 len1 c-addr2 len2 | _
- then
- \ drop first character from string
- 1
- /string
- \ result-string len c-addr1 len1 c-addr2' len2' | _
- repeat
- 2drop 2drop
- result-string count ;
- \ tests
- create str1 256 chars allot
- create str2 256 chars allot
- s" aaaaaxbbby" str1 place
- s" xdddxeeye" str2 place
- str1 count str2 count
- common-chars s" xxy" compare throw
- s" gdfhzdujrz" str1 place
- s" aaaaaazuja" str2 place
- str1 count str2 count
- common-chars s" zuj" compare throw
- : read-ok? ( read-length eof-flag -- read-length flag )
- \ s" checking if read ok:" type .s cr
- swap dup 0 >
- rot
- and ;
- \ Read the strings of 3 lines from the input file and put
- \ them on the stack.
- : read-3-lines ( -- c-addr1 len1 c-addr2 len2 c-addr3 len3 )
- 3 0 ?DO
- \ read line from file
- \ clear line buffer
- line-buffer empty-buffer
- line-buffer max-bytes-line puzzle-input-handle read-line
- \ STACK: read-len eof-flag read-error-flag
- \ s" before checking if read ok:" type .s cr
- throw \ stack: acc length eof-flag
- \ check that everything was read OK from the line buffer
- read-ok?
- \ s" stack after read-ok?:" type .s cr
- if
- line-buffer swap \ acc c-addr length
- \ Check, that each line has an even number of characters.
- \ This is not strictly necessary, just trying out some
- \ validation and cleanup.
- even? if
- \ Remove trailing whitespace.
- -trailing
- else
- s" invalid input" type cr bye
- then
- then
- LOOP
- \ create success or failure flag
- dup 0<> ;
- : process-group ( c-addr1 len1 c-addr2 len2 c-addr3 len3 -- prio )
- .s cr
- 2dup 2>r type s" --" type 2dup 2>r type s" --" type 2dup 2>r type cr
- 2r> 2r> 2r>
- common-chars
- common-chars
- 2dup s" common chars of all 3 lines:" type type cr
- dup 0= if
- s" invalid input, no common character" type bye
- then
- \ common-chars len
- drop c@
- dup s" common char is:" type emit cr
- \ char
- char-priority ;
- \ tests
- Create a 256 allot s" aaabccc" a 256 insert a 7
- Create b 256 allot s" dddbeee" b 256 insert b 7
- Create c 256 allot s" fffbggg" c 256 insert c 7
- process-group char b char-priority = 0= throw
- \ this test somehow fails, wrong score?
- Create a 256 allot s" tdltdtmhlRNCBcwmHr" a 256 insert a 18
- Create b 256 allot s" WDzDPnvvGnsWLWpGJJHRzCCRZNBRrRwMNwHH" b 256 insert b 36
- Create c 256 allot s" DsDsQnJDnWsJnJvrQDPJddgShFQhjljqhggbdbbt" c 256 insert c 40
- process-group char r char-priority = 0= throw
- \ TODO: There is only 1 common char in the 2 halves of a
- \ string, but there may be multiple common chars within 2
- \ given lines! If one does not exist in all 3 lines, you
- \ need to try the next common char.
- : process ( c-addr length -- ??? )
- 0 \ accumulator value for score
- begin
- puzzle-input-handle file-eof? not
- while
- read-3-lines if
- process-group
- s" accumulating:" type .s cr
- +
- then
- repeat
- \ drop length of read characters from EOF read
- s" EOF reached:" type .s cr
- drop drop drop ;
- process . cr
- puzzle-input-handle close-file
|