From ec3b438f40170b63cf02ff46ad87936347027b78 Mon Sep 17 00:00:00 2001 From: Joseph Montanaro Date: Fri, 6 Dec 2024 20:39:16 -0500 Subject: [PATCH] 2024 day 3 part 2 --- 2024/03.fs | 82 +++++++++++++++++++++++++++++++++++------------------- 1 file changed, 54 insertions(+), 28 deletions(-) diff --git a/2024/03.fs b/2024/03.fs index 7a6ed62..26a57f2 100644 --- a/2024/03.fs +++ b/2024/03.fs @@ -1,16 +1,11 @@ -create data 20000 allot \ create a 20K buffer -variable fileid \ create a variable `fileid` -s" data/03.txt" r/o open-file \ open data file -drop \ drop the top value from the stack, it's just a status code and we aren't going to bother handling errors -fileid ! \ save the file id to the variable +: load-data ( addr1 u1 -- addr2 u2 ) + 20000 allocate drop \ allocate a 20k buffer, drop the status code + dup 2swap \ duplicate the buffer addr and stick both copies under the addr/length of filename + r/o open-file drop \ open file, drop the status code + 20000 swap \ stick the number of bytes to be read in between the buffer addr and file id + read-file drop \ read the file, drop the status code +; -variable data-len -data 20000 fileid @ read-file -drop -data-len ! - -: data-str ( -- addr u ) - data data-len @ ; : chop-prefix ( addr u u2 -- addr2 u2 ) \ chop the first `u2` bytes off the beginning of the string at `addr u` @@ -21,9 +16,11 @@ data-len ! swap \ put them back in the right order ; + require regexp.fs : mul-instr ( addr u -- flag ) + \ match a string of the form `mul(x,y)` where x and y are integers and capture those integers (( =" mul(" \( {++ \d ++} \) ` , \( {++ \d ++} \) ` ) )) ; @@ -38,24 +35,53 @@ require regexp.fs then ; -variable result + +variable result \ initialize `result` with 0 0 result ! -: sum-mul-instrs ( addr u -- u2 ) - begin \ start looping - s" mul(" search \ search for the string "mul(" - if \ if successful, top 2 values on stack will be start address of "mul(" and remainder of original string - 2dup \ duplicate address and remaining length of string - get-product \ pass those to get-product above - result @ + \ load `result` and add to product - result ! \ store this new value back in `result` - 4 chop-prefix \ bump the start of the string by 4 characters - else \ if not successful, we have finished scanning through the string - 2drop \ dump the string address and length - result @ exit \ put the result on top of the stack and return to caller - then - again +variable enabled +-1 enabled ! \ idiomatically -1 is "true" (really anything other than 0 is true) + +: handle-mul ( addr u -- ) + get-product \ pass those to get-product above + result @ + \ load `result` and add to product + result ! \ store this new value back in `result` ; -data-str sum-mul-instrs . +: sum-mul-instrs ( addr u -- u2 ) + \ we want to loop from addr to (addr + u - 8), because 8 is the min length of a valid mul(x,y) instruction + \ we also want to have addr + u on the top of the stack when we enter the loop, + \ so that we can use that to compute the remaining length of the string from our current address + + over + \ copy addr to top of stack and add to length + dup 8 - \ duplicate, then subtract 8 from the top value + rot \ move original addr to top of stack + ( stack at this point: [ addr + u, addr + u - 8, addr ] ) + ( i.e. [ end-of-string, loop-limit, loop-start ] ) + + do \ start looping + I 4 s" do()" str= \ compare the length-4 substring starting at I to the string "do()" + if \ if valid do() instruction, + -1 enabled ! \ set enabled=true + then + + I 7 s" don't()" str= \ compare length-7 substring to "don't()" + if \ if valid don't() instruction, + 0 enabled ! \ set enabled=false + then + + I 4 s" mul(" str= \ compare length-4 substring to "mul(" + enabled @ and \ combine with current value of `enabled` + if \ if a candidate for `mul(x,y)` instruction, and enabled=true, then + dup I - \ subtract current string pointer from end-of-string pointer to get length of remaining string + I swap handle-mul \ put current pointer onto stack again, swap so stack is ( addr len), and handle + then + loop + + drop \ get rid of end-of-string pointer + result @ \ return value of result +; + +s" data/03.txt" load-data +sum-mul-instrs . bye