(ql:quickload '(fiveam str arrows transducers)) (defpackage #:day04 (:use #:cl #:fiveam) (:local-nicknames (#:t #:transducers))) (in-package #:day04) (defparameter eg-input "Card 1: 41 48 83 86 17 | 83 86 6 31 17 9 48 53 Card 2: 13 32 20 16 61 | 61 30 68 82 17 32 24 19 Card 3: 1 21 53 59 44 | 69 82 63 72 16 21 14 1 Card 4: 41 92 73 84 69 | 59 84 76 51 58 5 54 83 Card 5: 87 83 26 28 32 | 88 30 70 12 93 22 82 36 Card 6: 31 18 13 56 72 | 74 77 10 23 35 67 36 11") (defun matching-numbers (line) (destructuring-bind (_card winners haves) (uiop:split-string line :separator '(#\: #\|)) (declare (ignorable _card)) (intersection (mapcar #'parse-integer (str:split " " winners :omit-nulls t)) (mapcar #'parse-integer (str:split " " haves :omit-nulls t))))) (defun solver1 (lines) (t:transduce (t:comp (t:filter-map #'matching-numbers) (t:map #'length) (t:map #'1-) (t:map (lambda (n) (expt 2 n)))) #'+ lines)) (defun solver1c (lines) (arrows:->> (mapcar #'matching-numbers lines) (remove-if #'null) (mapcar #'length) (mapcar #'1-) (mapcar (lambda (n) (expt 2 n))) (apply #'+))) (defun solver2 (lines) (let* ((line-count (length lines)) (stash (make-hash-table :size line-count))) (loop for line in lines for i from 0 for matches = (length (matching-numbers line)) do (incf (gethash i stash 0)) (dotimes (j matches) (when (< (+ i j 1) line-count) (incf (gethash (+ i j 1) stash 0) (gethash i stash)))) sum (gethash i stash 0)))) (test solutions (is (= 13 (solver1 (uiop:split-string eg-input :separator '(#\Newline))))) (is (= 13 (solver1c (uiop:split-string eg-input :separator '(#\Newline))))) (is (= 18619 (solver1 #p"input"))) (is (= 18619 (solver1c (uiop:read-file-lines "input")))) (is (= 30 (solver2 (uiop:split-string eg-input :separator '(#\Newline))))) (is (= 8063216 (solver2 (uiop:read-file-lines "input")))))