submarine.lisp 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. (defparameter *diagnostics-input* "./input.txt")
  2. (defun read-diagnostics ()
  3. "Read input file, returning a list of its binary diagnostics."
  4. (let ((input (open *diagnostics-input* :if-does-not-exist nil))
  5. (input-diagnostics '()))
  6. (when input
  7. (loop for line = (read-line input nil)
  8. while line do
  9. (setq input-diagnostics (cons line input-diagnostics)))
  10. (close input))
  11. (reverse input-diagnostics)))
  12. (defun get-zero-one-frequencies (input)
  13. "Determine how many bits have a 1 at this input and how many have a 0."
  14. (defun all-bits-at-index (index all-readings)
  15. (map 'list (lambda (byte) (elt byte index)) all-readings))
  16. (loop for i upto (1- (length (car input)))
  17. collecting (count #\0 (all-bits-at-index i input))
  18. into zeros
  19. collecting (count #\1 (all-bits-at-index i input))
  20. into ones
  21. finally (return (list zeros ones))))
  22. (defun calculate-gamma (input)
  23. "Calculate the gamma rate."
  24. (let* ((frequencies (get-zero-one-frequencies input))
  25. (zeros (car frequencies))
  26. (ones (cadr frequencies)))
  27. (map 'list
  28. (lambda (zero one)
  29. (if (> zero one) "0" "1"))
  30. zeros
  31. ones)))
  32. (defun calculate-epsilon (input)
  33. "Calculate the epsilon rate."
  34. (defun invert (gamma)
  35. (loop for i in gamma
  36. if (string= i "0")
  37. collect "1"
  38. else collect "0"))
  39. (invert (calculate-gamma input)))
  40. (defun print-power-consumption-report (input)
  41. (let* ((gamma (calculate-gamma input))
  42. (epsilon (calculate-epsilon input))
  43. (gamma-string (format nil "~{~A~}" gamma))
  44. (epsilon-string (format nil "~{~A~}" epsilon))
  45. (gamma-decimal (parse-integer gamma-string :radix 2))
  46. (epsilon-decimal (parse-integer epsilon-string :radix 2)))
  47. (format t "gamma: ~{~a~}~%" gamma)
  48. (format t " ~a~%" gamma-decimal)
  49. (format t "epsilon: ~{~a~}~%" epsilon)
  50. (format t " ~a~%" epsilon-decimal)
  51. (format t "power consumption: ~a~%" (* epsilon-decimal gamma-decimal))))
  52. ;; gamma: 001110101111
  53. ;; 943
  54. ;; epsilon: 110001010000
  55. ;; 3152
  56. ;; power consumption: 2972336
  57. (defun oxygen-generator-rating (input)
  58. "Calculate the oxygen generator rating.
  59. Determined by having the most bits in the most-common positions."
  60. (in-majority-bit-criteria #'remove-if input))
  61. (defun co2-scrubber-rating (input)
  62. "Calculate the CO2 scrubber rating.
  63. Determined by having the fewest bits in the most-common positions."
  64. (in-majority-bit-criteria #'remove-if-not input))
  65. (defun in-majority-bit-criteria (filter input)
  66. "Reduce list to byte contaning the most filtered majority bit criteria."
  67. (defun iter-filter (measurements index)
  68. (if (= 1 (length measurements))
  69. (car measurements)
  70. (iter-filter
  71. (funcall
  72. filter
  73. (lambda (x) (in-the-bit-majority? x index measurements)) measurements)
  74. (1+ index))))
  75. (iter-filter input 0))
  76. (defun in-the-bit-majority? (byte bit-index all-bytes)
  77. "Is the bit at bit-index of byte in the more popular group of bits at this index in all-bytes?"
  78. (let* ((bit-frequencies (get-zero-one-frequencies all-bytes))
  79. (most-popular-bit
  80. (if (> (elt (car bit-frequencies) bit-index)
  81. (elt (cadr bit-frequencies) bit-index))
  82. #\0
  83. #\1))
  84. (current-bit (elt byte bit-index)))
  85. (char= current-bit most-popular-bit)))
  86. (defun print-life-support-report (input)
  87. (let* ((oxygen (oxygen-generator-rating input))
  88. (co2 (co2-scrubber-rating input))
  89. (oxy-decimal (parse-integer oxygen :radix 2))
  90. (co2-decimal (parse-integer co2 :radix 2)))
  91. (format t "oxygen: ~a~%" oxygen)
  92. (format t " ~a~%" oxy-decimal)
  93. (format t "co2: ~a~%" co2)
  94. (format t " ~a~%" co2-decimal)
  95. (format t "life support: ~a~%" (* oxy-decimal co2-decimal))))
  96. (print-power-consumption-report (read-diagnostics))
  97. ;; gamma: 001110101111
  98. ;; 943
  99. ;; epsilon: 110001010000
  100. ;; 3152
  101. ;; power consumption: 2972336
  102. (print-life-support-report (read-diagnostics))
  103. ;; oxygen: 111000100010
  104. ;; 3618
  105. ;; co2: 001110100011
  106. ;; 931
  107. ;; life support: 3368358