bingo.lisp 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. (defparameter *bingo-input* "./input.txt")
  2. (ql:quickload :cl-strings)
  3. (use-package :cl-strings)
  4. (defun read-bingo ()
  5. "Read input file, returning a list of its binary diagnostics."
  6. (let ((input (open *bingo-input* :if-does-not-exist nil))
  7. (bingo-boards-raw '())
  8. (bingo-draws '()))
  9. (when input
  10. (setq bingo-draws (cl-strings:split
  11. (read-line input nil) ","))
  12. (loop for line = (read-line input nil)
  13. while line do
  14. (setq bingo-boards-raw (cons line bingo-boards-raw)))
  15. (close input))
  16. (cons (map 'list (lambda (draw) (parse-integer draw)) bingo-draws)
  17. (reverse bingo-boards-raw))))
  18. (defun process-raw-bingo-boards (input)
  19. (defun iter-boards (current-board boards rows-to-process)
  20. (if (eq 'nil rows-to-process)
  21. (cons (reverse current-board) boards)
  22. (let ((next-row (car rows-to-process)))
  23. (if (string= "" next-row)
  24. (iter-boards '() (cons (reverse current-board) boards)
  25. (cdr rows-to-process))
  26. (iter-boards (cons
  27. (loop for x in
  28. (remove-if (lambda (x) (string= x ""))
  29. (cl-strings:split next-row))
  30. collecting (cons 'nil (parse-integer x)))
  31. current-board)
  32. boards
  33. (cdr rows-to-process))))
  34. ))
  35. (reverse (remove-if (lambda (x) (eq x 'nil)) (iter-boards '() '() input))))
  36. (defun mark-board (board square)
  37. (defun mark-row (row sq)
  38. (defun row-iter (row called-square marked-row)
  39. (if (eq 'nil row)
  40. (reverse marked-row)
  41. (let* ((current-square (car row))
  42. (already-marked (car current-square))
  43. (value (cdr current-square))
  44. (marked-square (cons (or (= value called-square) already-marked) value)))
  45. (row-iter (cdr row) called-square (cons marked-square marked-row)))))
  46. (row-iter row sq '()))
  47. (loop for row in board collect (mark-row row square)))
  48. (defun get-cols (board)
  49. (defun get-col (board)
  50. (defun col-iter (board reduced-board col)
  51. (if (eq 'nil board)
  52. (cons (reverse col) (reverse reduced-board))
  53. (col-iter (cdr board)
  54. (cons (cdr (car board)) reduced-board)
  55. (cons (car (car board)) col))))
  56. (col-iter board '() '()))
  57. (defun board-iter (board cols)
  58. (if (every (lambda (x) (not x)) board)
  59. cols
  60. (let* ((results (get-col board))
  61. (column (car results))
  62. (reduced-board (cdr results)))
  63. (board-iter
  64. reduced-board
  65. (cons column cols)))))
  66. (reverse (board-iter board '())))
  67. (defun winning-board (board)
  68. (defun winning-row (board)
  69. (some (lambda (row)
  70. (every (lambda (square) (car square)) row))
  71. board))
  72. (defun winning-col (board)
  73. (winning-row (get-cols board)))
  74. (or (winning-row board)
  75. (winning-col board)))
  76. (defun get-moves-and-boards ()
  77. (let ((data (read-bingo)))
  78. (cons
  79. (car data)
  80. (process-raw-bingo-boards (cdr data)))))
  81. (defun find-winning-board ()
  82. (defun move-iter (moves boards)
  83. (let* ((boards-with-move-applied
  84. (map 'list (lambda (board) (mark-board board (car moves)))
  85. boards))
  86. (winning-boards
  87. (remove-if-not
  88. (lambda (board) (winning-board board))
  89. boards-with-move-applied)))
  90. (if (not (eq 'nil winning-boards))
  91. (progn (format t "~A~%~A~%" winning-boards (car moves))
  92. winning-boards)
  93. (move-iter (cdr moves) boards-with-move-applied))))
  94. (let* ((moves-and-boards (get-moves-and-boards))
  95. (moves (car moves-and-boards))
  96. (boards (cdr moves-and-boards)))
  97. (move-iter moves boards)))
  98. (defun find-last-winning-board ()
  99. (defun move-iter (moves boards)
  100. (let* ((boards-with-move-applied
  101. (map 'list (lambda (board) (mark-board board (car moves)))
  102. boards))
  103. (losing-boards
  104. (remove-if
  105. (lambda (board) (winning-board board))
  106. boards-with-move-applied)))
  107. (if (= 1 (length losing-boards))
  108. (progn (format t "~A~%~A~%" losing-boards (car moves))
  109. losing-boards)
  110. (move-iter (cdr moves) losing-boards))))
  111. (let* ((moves-and-boards (get-moves-and-boards))
  112. (moves (car moves-and-boards))
  113. (boards (cdr moves-and-boards)))
  114. (move-iter moves boards)))
  115. ;; hacked together the final solution in a ... less than elegant manner.
  116. ;; the actual processing code is good, the final glue to get the answer...
  117. ;; couldn't be bothered to 'engineer' it lol
  118. (* 73 (reduce '+ (map 'list 'cdr (remove-if (lambda (s) (car s)) '((NIL . 86) (T . 80) (NIL . 77) (T . 18) (NIL . 87)
  119. (NIL . 79) (T . 93) (NIL . 52) (NIL . 17) (NIL . 20)
  120. (NIL . 30) (T . 68) (NIL . 48) (T . 12) (T . 91)
  121. (NIL . 25) (T . 98) (NIL . 13) (NIL . 9) (NIL . 47)
  122. (NIL . 45) (T . 73) (NIL . 97) (NIL . 15) (NIL . 59))))))
  123. ;; -> 58838
  124. ;; same story for finding the cute "last winner"
  125. (* 46 (+ 17 76 29 1 13))
  126. ;; -> 6256