54 lines
1.7 KiB
Common Lisp
54 lines
1.7 KiB
Common Lisp
(load (merge-pathnames "../common.lisp" *load-truename*))
|
|
|
|
(defconstant test-data
|
|
'("1-3 a: abcde"
|
|
"1-3 b: cdefg"
|
|
"2-9 c: ccccccccc"))
|
|
|
|
(defconstant expected-result 2)
|
|
(defconstant expected-result-part2 1)
|
|
|
|
(defstruct password lower upper char pass)
|
|
|
|
(defun parse-password (line)
|
|
(let* ((lower-end (position #\- line))
|
|
(upper-end (position #\Space line :start (1+ lower-end))))
|
|
(make-password :lower (parse-integer (subseq line 0 lower-end))
|
|
:upper (parse-integer (subseq line (1+ lower-end) upper-end))
|
|
:char (char line (1+ upper-end))
|
|
:pass (subseq line (+ upper-end 4) nil))))
|
|
|
|
(defun valid-password-part1 (password)
|
|
(let ((count (loop for x across (password-pass password)
|
|
counting (char= x (password-char password)))))
|
|
(and (<= (password-lower password) count)
|
|
(<= count (password-upper password)))))
|
|
|
|
(defun valid-password-part2 (password)
|
|
(let* ((pass (password-pass password))
|
|
(c (password-char password))
|
|
(lower-c (char pass (1- (password-lower password))))
|
|
(upper-c (char pass (1- (password-upper password)))))
|
|
(not (eq (char= c lower-c)
|
|
(char= c upper-c)))))
|
|
|
|
(defun day (lines p)
|
|
(loop for line in lines
|
|
counting (funcall p (parse-password line))))
|
|
|
|
(defun part1 (lines)
|
|
(day lines #'valid-password-part1))
|
|
|
|
(defun part2 (lines)
|
|
(day lines #'valid-password-part2))
|
|
|
|
(assert (= expected-result
|
|
(part1 test-data)))
|
|
|
|
(assert (= expected-result-part2
|
|
(part2 test-data)))
|
|
|
|
(defconstant input (read-data))
|
|
(format t "Part 1: ~D~%" (part1 input))
|
|
(format t "Part 2: ~D~%" (part2 input))
|