thomas_2023/day_4/part1.fs

163 lines
2.9 KiB
Forth

variable input-fd
: open-input r/o open-file throw input-fd ! ;
256 constant MAX_LINE
create line MAX_LINE allot
: fill-line line line MAX_LINE input-fd @ read-line throw ;
: start s" input.txt" open-input ;
: hint s" hint.txt" open-input ;
( c c-addr u -- c-addr' u' ) \ Search string for char `c`
: find-char
begin
\ Read character
over c@
\ Pick c from stack and compare
3 pick = if
\ Drop off c
rot drop
exit
then
\ Next character
swap 1+ swap 1-
again ;
( c-addr u -- c-addr' u' )
: skip-card-number
': rot rot find-char
\ Skip past ": "
swap 2 + swap 2 - ;
( c-addr u -- c-addr' u' )
: find-pipe
'| rot rot find-char
\ Skip past "| "
swap 2 + swap 2 - ;
2variable winning_nums
2variable my_nums
( c-addr u -- ) \ Splits input line and stores in winning_nums and my_nums
: split-line
\ Skip past card number
skip-card-number
\ Find the pipe
2dup find-pipe
\ This is the start of my_nums
2dup my_nums 2!
\ (win_addr win_len my_addr my_len)
\ Subtract lens then -3 to remove the " | "
swap drop - 3 -
winning_nums 2! ;
( c-addr u -- c-addr' u' ) \ Increment string until a non space is found
: skip-spaces
begin
dup
while
over
c@ bl <> if
exit
then
swap 1+ swap 1-
repeat ;
\ 11/10 pow()
: ** swap dup rot 1- 0 do over * loop swap drop ;
\ Fuck it, we copy paste now. I'm tired
2variable cur2
( n -- w ) \ w = 1 if win
: check-win
winning_nums 2@ cur2 2!
begin
cur2 2@
swap drop
while
\ Preserve `n` passed in
dup
0 0 cur2 2@ skip-spaces >number
\ Stack now has address of rest of string, skip past the spaces and save to cur
skip-spaces
cur2 2!
\ Drop upper part of dint from >number
drop
= if
." Win " .S . cr
true
exit
then
repeat
drop
false
;
2variable cur
variable wins
( -- w ) \ w = 1 if win
: check-mine
0 wins !
my_nums 2@ cur 2!
begin
cur 2@
swap drop
while
0 0 cur 2@ skip-spaces >number
\ Stack now has address of rest of string, skip past the spaces and save to cur
skip-spaces
cur 2!
\ Drop upper part of dint from >number
drop
." Passed to check-win" .S cr
check-win
if
wins @ 1+ wins !
then
repeat
;
: calc-points
wins @ 1 > if
2 wins @ **
2 /
exit
else
wins @ 0 = if
0 exit
then
then
1 ;
variable points
: do-all
begin
\ Read in a line
fill-line
while
split-line
winning_nums 2@ type cr
my_nums 2@ type cr
check-mine cr
." Wins " wins @ . cr
calc-points points @ + points !
repeat ;
start
do-all
cr ." Done ?!@# " points @ . cr
quit
( bye )