123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129 |
- (defparameter *diagnostics-input* "./input.txt")
- (defun read-diagnostics ()
- "Read input file, returning a list of its binary diagnostics."
- (let ((input (open *diagnostics-input* :if-does-not-exist nil))
- (input-diagnostics '()))
- (when input
- (loop for line = (read-line input nil)
- while line do
- (setq input-diagnostics (cons line input-diagnostics)))
- (close input))
- (reverse input-diagnostics)))
- (defun get-zero-one-frequencies (input)
- "Determine how many bits have a 1 at this input and how many have a 0."
- (defun all-bits-at-index (index all-readings)
- (map 'list (lambda (byte) (elt byte index)) all-readings))
- (loop for i upto (1- (length (car input)))
- collecting (count #\0 (all-bits-at-index i input))
- into zeros
- collecting (count #\1 (all-bits-at-index i input))
- into ones
- finally (return (list zeros ones))))
- (defun calculate-gamma (input)
- "Calculate the gamma rate."
- (let* ((frequencies (get-zero-one-frequencies input))
- (zeros (car frequencies))
- (ones (cadr frequencies)))
- (map 'list
- (lambda (zero one)
- (if (> zero one) "0" "1"))
- zeros
- ones)))
- (defun calculate-epsilon (input)
- "Calculate the epsilon rate."
- (defun invert (gamma)
- (loop for i in gamma
- if (string= i "0")
- collect "1"
- else collect "0"))
- (invert (calculate-gamma input)))
- (defun print-power-consumption-report (input)
- (let* ((gamma (calculate-gamma input))
- (epsilon (calculate-epsilon input))
- (gamma-string (format nil "~{~A~}" gamma))
- (epsilon-string (format nil "~{~A~}" epsilon))
- (gamma-decimal (parse-integer gamma-string :radix 2))
- (epsilon-decimal (parse-integer epsilon-string :radix 2)))
- (format t "gamma: ~{~a~}~%" gamma)
- (format t " ~a~%" gamma-decimal)
- (format t "epsilon: ~{~a~}~%" epsilon)
- (format t " ~a~%" epsilon-decimal)
- (format t "power consumption: ~a~%" (* epsilon-decimal gamma-decimal))))
- ;; gamma: 001110101111
- ;; 943
- ;; epsilon: 110001010000
- ;; 3152
- ;; power consumption: 2972336
- (defun oxygen-generator-rating (input)
- "Calculate the oxygen generator rating.
- Determined by having the most bits in the most-common positions."
- (in-majority-bit-criteria #'remove-if input))
- (defun co2-scrubber-rating (input)
- "Calculate the CO2 scrubber rating.
- Determined by having the fewest bits in the most-common positions."
- (in-majority-bit-criteria #'remove-if-not input))
- (defun in-majority-bit-criteria (filter input)
- "Reduce list to byte contaning the most filtered majority bit criteria."
- (defun iter-filter (measurements index)
- (if (= 1 (length measurements))
- (car measurements)
- (iter-filter
- (funcall
- filter
- (lambda (x) (in-the-bit-majority? x index measurements)) measurements)
- (1+ index))))
- (iter-filter input 0))
- (defun in-the-bit-majority? (byte bit-index all-bytes)
- "Is the bit at bit-index of byte in the more popular group of bits at this index in all-bytes?"
- (let* ((bit-frequencies (get-zero-one-frequencies all-bytes))
- (most-popular-bit
- (if (> (elt (car bit-frequencies) bit-index)
- (elt (cadr bit-frequencies) bit-index))
- #\0
- #\1))
- (current-bit (elt byte bit-index)))
- (char= current-bit most-popular-bit)))
- (defun print-life-support-report (input)
- (let* ((oxygen (oxygen-generator-rating input))
- (co2 (co2-scrubber-rating input))
- (oxy-decimal (parse-integer oxygen :radix 2))
- (co2-decimal (parse-integer co2 :radix 2)))
- (format t "oxygen: ~a~%" oxygen)
- (format t " ~a~%" oxy-decimal)
- (format t "co2: ~a~%" co2)
- (format t " ~a~%" co2-decimal)
- (format t "life support: ~a~%" (* oxy-decimal co2-decimal))))
- (print-power-consumption-report (read-diagnostics))
- ;; gamma: 001110101111
- ;; 943
- ;; epsilon: 110001010000
- ;; 3152
- ;; power consumption: 2972336
- (print-life-support-report (read-diagnostics))
- ;; oxygen: 111000100010
- ;; 3618
- ;; co2: 001110100011
- ;; 931
- ;; life support: 3368358
|