(import (srfi :43)) ; vector extensions (define (>> x n) (bitwise-arithmetic-shift-right x n)) (define (<< x n) (bitwise-arithmetic-shift-left x n)) (define (& x n) (bitwise-and x n)) ; str is a string of hexadecimal numbers ; bit-reader returns a closure that iterators over the bits ; defined by the hex numbers over the requested amount. ; if 'position is sent to closure instead of a number, ; the current bit position in the stream is returned. (define (bit-reader str) (let [(index -1) (len (string-length str)) (available 0) (nibble #f)] (lambda (want) (case want ['position (+ (* index 4) (- 4 available))] [else (let reader [(want want)] (when (= available 0) (set! index (+ index 1)) (set! nibble (if (< index len) (string->number (substring str index (+ index 1)) 16) #f)) (set! available 4)) (if nibble (let* [(consume (min want available)) (offset (- 4 consume)) (mask (- (<< 1 consume) 1)) (result (>> (& nibble (<< mask offset)) offset))] (set! nibble (<< nibble consume)) (set! available (- available consume)) (if (< consume want) (let [(left (- want consume))] (+ (<< result left) (reader left))) result)) #f))])))) ; given a bit-reader, this decodes a variable width integer ; where each packet is 5 bits and a leading bit of 1 tells ; there is one more packet to read (define (decode-integer br) (let loop [(value 0)] (let* [(more? (= (br 1) 1)) (bits (br 4)) (value (+ (* value 16) bits))] (if more? (loop value) value)))) ; this decodes each packet in the given hex string ; calling visitor for each with the version type and value of each packet ; for a packet of type 4, value is the literal value of the packet ; for other packets, value is the number of arguments to the opcode. (define (decode str visitor) (let [(br (bit-reader str))] (let loop () (let* [(version (br 3)) (type (br 3))] (if (= type 4) (visitor version type (decode-integer br)) (let [(length-type (br 1))] (if (= length-type 0) (let* [(to-decode (br 15)) (start (br 'position))] (let sub [(count 1)] (loop) (if (< (- (br 'position) start) to-decode) (sub (+ count 1)) (visitor version type count)))) (let [(count (br 11))] (let sub [(n count)] (loop) (if (> n 1) (sub (- n 1)) (visitor version type count))))))))))) ; returns the sum of all version numbers of all the packets in the given encoded BITS stream (define (sum-versions str) (let [(sum-version 0)] (decode str (lambda (version type value) (set! sum-version (+ version sum-version)))) sum-version)) ; given a stack, pops "value" as many elements ; and returns a stack with a new head with ; op concatenated with the popped values. ; the rest of the original stack follows (define (do-op op stack value) (let rec [(stack stack) (got 0) (output '())] (if (= got value) (cons (cons op output) stack) (let [(v (car stack))] (rec (cdr stack) (+ got 1) (cons v output)))))) ; we can't use regular scheme operators for the evaluation of the BITS stream ; because they return #t/#f instead of 1 0 ; so these 3 are helpers to solve the situation (define (greater-than a b) (if (> a b) 1 0)) (define (less-than a b) (if (< a b) 1 0)) (define (equal-to a b) (if (= a b) 1 0)) ; decodes the operation given by the BITS encoded stream and evaluates it (define (evaluate str) (let [(stack '())] (decode str (lambda (version type value) (set! stack (case type [0 (do-op '+ stack value)] [1 (do-op '* stack value)] [2 (do-op 'min stack value)] [3 (do-op 'max stack value)] [4 (cons value stack)] [5 (do-op 'greater-than stack value)] [6 (do-op 'less-than stack value)] [7 (do-op 'equal-to stack value)])))) (eval (car stack)))) (call-with-input-file "input" (lambda (file) (let [(data (get-line file))] (printf "part 1:~% Sum of version numbers ~a~%" (sum-versions data)) (printf "part 2:~% Transmission value: ~a~%" (evaluate data)))))