(import (srfi :43)) ; returns a vector of 12 elements where each one counts the number ; of times the n-th bit was zero in the input vector (define (count-zeroes-for-each-bit numbers) (let [(zeroes (make-vector 12 0))] (vector-for-each (lambda (index number) (let iterate [(bit 0)] (when (< bit 12) (when (not (bitwise-bit-set? number bit)) (vector-set! zeroes bit (+ 1 (vector-ref zeroes bit)))) (iterate (+ 1 bit))))) numbers) zeroes)) (define (part-1 numbers) (let* [(zeroes (count-zeroes-for-each-bit numbers))] (let iter-loop [(i 0) (gamma 0)] (if (< i 12) ; We don't need to compute the number of ones ; as it is what's left when the zeroes are removed. ; So that's just the number of elements minus the number of zeroes. (if (> (vector-ref zeroes i) (/ (vector-length numbers) 2)) (iter-loop (+ i 1) (+ gamma (bitwise-arithmetic-shift-left 1 i))) (iter-loop (+ i 1) gamma)) (let [(epsilon (bitwise-xor gamma #b111111111111))] (printf "part 1: ~% gamma: ~a~% epsilon: ~a~% power consumption: ~a~%" gamma epsilon (* gamma epsilon))))))) ; recursively filters the numbers checking for the n-th bit with the comparator ; with <= as the comparator, it will check for bits that are set ; with the opposite > comparator, it will check for bits that are not (define (determine-rating numbers comparator) (let loop [(bit 11) (numbers (vector-map (lambda (index number) number) numbers))] (if (= 1 (vector-length numbers)) (vector-ref numbers 0) (let* [(zeroes (count-zeroes-for-each-bit numbers)) (mask (bitwise-arithmetic-shift-left 1 bit)) (target (if (apply comparator (list (vector-ref zeroes bit) (/ (vector-length numbers) 2))) 0 mask))] ;(printf "dataset: ~a~% zeroes: ~a~% bit: ~a~% mask: (#b~b)~%" numbers zeroes bit mask) (loop (- bit 1) (vector-fold (lambda (index result number) (if (= target (bitwise-and number mask)) (vector-append result (vector number)) result)) '#() numbers)))))) (define (part-2 numbers) (let [(oxygen-gen (determine-rating numbers <=)) (co2-scrub (determine-rating numbers >))] (printf "part 2:~% O2-gen rating: ~a~% CO2-scrub rating: ~a~% life support: ~a~%" oxygen-gen co2-scrub (* oxygen-gen co2-scrub)))) (call-with-input-file "input" (lambda (file) (let [(numbers '#())] (let read-loop () (let [(line (get-line file))] (when (not (eof-object? line)) (set! numbers (vector-append numbers (vector (string->number line 2)))) (read-loop)))) (part-1 numbers) (part-2 numbers))))