diff options
Diffstat (limited to '09/lib.scm')
-rw-r--r-- | 09/lib.scm | 70 |
1 files changed, 70 insertions, 0 deletions
diff --git a/09/lib.scm b/09/lib.scm new file mode 100644 index 0000000..5eac027 --- /dev/null +++ b/09/lib.scm @@ -0,0 +1,70 @@ +(library (lib) + (export solve-part1 solve-part2) + (import (chezscheme)) + + ; Global state... a sin, but very convenient in this case! + (define chars '()) ; Characters still to be parsed + (define part1-total 0) ; Total score of groups in input + (define part2-total 0) ; Total non-escaped garbage chars + + ; Is the next character in the stream equal to `c'? + (define (peek? c) + (char=? c (car chars))) + + ; Blindly accept character and pop it. We do all detection + ; via `peek?', so we don't care what gets discarded here. + (define (next) + (set! chars (cdr chars))) + + ; Parse a "group". We can assume all input is well-formed, + ; which really helps keep this code as simple as possible. + (define (parse-group depth) + (next) ; Accept initial #\{ + (let loop () + ; Expect start of "group" or "garbage" + (cond + ((peek? #\{) + (parse-group (+ depth 1))) + ((peek? #\<) + (parse-garbage))) + ; Expect comma or end of current "group" + (cond + ((peek? #\,) + (next) ; Accept #\, + (loop)) ; Parse next "group"/"garbage" + ((peek? #\}) + ; Add current group's nesting depth to total score + (set! part1-total (+ part1-total depth)) + (next))))) ; Accept #\} and return + + ; Parse "garbage": everything until next non-escaped #\>. + (define (parse-garbage) + (let loop () + (next) ; Accept char (#\< at first) + (cond + ((peek? #\>) + (next)) ; Accept #\> and return + ((peek? #\!) + (next) ; Accept #\! + (loop)) ; Continue to escaped char + (else + ; Add this character to the total count + (set! part2-total (+ part2-total 1)) + (loop))))) + + ; Reset global parser state and parse the input string + (define (solve-puzzle str) + (set! chars (string->list str)) + (set! part1-total 0) + (set! part2-total 0) + (parse-group 1)) + + (define (solve-part1 str) + (solve-puzzle str) + part1-total) + + (define (solve-part2 str) + (solve-puzzle str) + part2-total) + +) |