(ql:quickload '(fiveam arrows trivia str)) (defpackage #:day07 (:use #:cl) (:local-nicknames (#:f #:fiveam))) (in-package :day07) (defparameter eg-input "32T3K 765 T55J5 684 KK677 28 KTJJT 220 QQQJA 483") (defun occurences (str &optional joker) (let* ((bag (make-hash-table)) (jokers (loop for le across str do (incf (gethash le bag 0)) count (eq le #\J))) (result (sort (alexandria:hash-table-values bag) #'>))) (when joker (setf result (remove jokers result :count 1)) (if (= jokers 5) (setf result '(5)) (incf (car result) jokers))) result)) (defun hand-type (str &optional joker) (trivia:match (occurences str joker) ((list 5) 5) ((list 4 1) 4) ((list 3 2) 3) ((list 3 1 1) 2) ((list 2 2 1) 1) ((list 2 1 1 1) 0) ((list 1 1 1 1 1) -1))) (defun card-strength (card &optional joker) (position card (if joker "J23456789TQKA" "23456789TJQKA"))) (defun card-< (a b &optional joker) (< (card-strength a joker) (card-strength b joker))) (defun hand-< (a b &optional joker) (let ((a-t (hand-type a joker)) (b-t (hand-type b joker))) (cond ((< a-t b-t)) ((= a-t b-t) (loop for l across a for s across b unless (eq l s) return (card-< l s joker)))))) (f:test partial (f:is (equal '(3 1 1) (occurences "QJQAQ"))) (f:is (equal '(4 1) (occurences "QJQAQ" 'joker))) (f:is (equal '(5) (occurences "JJJJJ" 'joker))) (f:is (card-< #\2 #\J)) (f:is-false (card-< #\2 #\J 'joker)) (f:is (hand-< "2AAAA" "33332")) (f:is (hand-< "77788" "77888")) (f:is (hand-< "77788" "77778"))) (defun parse-input (str) (let ((data (arrows:->> (ppcre:split "\\s" str) (remove-if #'str:empty?)))) (loop for (hand bid) on data by #'cddr collect (cons hand (parse-integer bid))))) (defun total-win (sorted-hands) (loop for (hand . bid) in sorted-hands for c from 1 sum (* c bid))) (defun solver (lines &optional joker) (arrows:-> (parse-input lines) (sort (lambda (a b) (hand-< a b joker)) :key #'car) (total-win))) (f:test solutions (f:is (= 6440 (solver eg-input))) (f:is (= 5905 (solver eg-input 'joker))) (f:is (= 253205868 (solver (uiop:read-file-string "input")))) (f:is (= 253907829 (solver (uiop:read-file-string "input") 'joker)))) ;; part2