blob: 4cb0a9ec153562b8d729dad7490145e83cdc4cf5 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
|
(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
|