75 lines
2.6 KiB
Scheme
75 lines
2.6 KiB
Scheme
(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
|
|
"day-3.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))))
|