;;;; AoC 2020 (defun read-1 (file) (with-open-file (stream file) (loop for line = (read-line stream nil) while line collect (parse-integer line)))) (defvar *input-1-0* nil) (setf *input-1-0* (read-1 "inputs/1-0")) (defvar *input-1-1* nil) (setf *input-1-1* (read-1 "inputs/1-1.txt")) (defun solve-1-1 (data target) (let ((deficits (map 'list (lambda (n) (- target n)) data))) (reduce #'* (intersection data deficits)))) (defun make-deficits (list difference) (map 'list (lambda (n) (- difference n)) list)) (defun solve-1-2 (data target) (let ((first-deficits (make-deficits data target))) (reduce #'* (remove-duplicates (mapcan (lambda (n) (intersection (make-deficits data n) data)) first-deficits))))) (defun solve-1 (data target) (time (progn (print (solve-1-1 data target)) (print (solve-1-2 data target))))) (defstruct password (pchar) (prange) (word)) (defun read-2 (file) (with-open-file (stream file) (loop for line = (read-line stream nil) while line collect (let* ((pwlist (split-sequence:split-sequence #\space line)) (range (multiple-value-bind (n index) (parse-integer (first pwlist) :junk-allowed t) (list n (parse-integer (first pwlist) :start (1+ index)))))) (make-password :pchar (char (second pwlist) 0) :prange range :word (third pwlist)))))) (defun %solve-2-1 (pw) (let ((n (count (password-pchar pw) (password-word pw)))) (and (not (> (first (password-prange pw)) n)) (not (< (second (password-prange pw)) n))))) (defun %solve-2-2 (pw) (let ((valid 0)) (loop for index in (password-prange pw) do (if (eq (password-pchar pw) (elt (password-word pw) (1- index))) (incf valid))) (= valid 1))) (defun %solve-2 (data test) (let ((pn 0)) (loop for p in data do (if (funcall test p) (incf pn))) pn)) (defun solve-2 (file) (let ((data (read-2 file))) (time (progn (print (%solve-2 data #'%solve-2-1)) (print (%solve-2 data #'%solve-2-2)))))) (defun read-3 (file) (with-open-file (stream file) (let ((temp-map (loop for line = (read-line stream nil) while line collect line))) (make-array (list (length temp-map) (length (first temp-map))) :initial-contents temp-map :element-type 'character)))) (defun step-slope (position direction map) (let* ((temp-position (map 'list #'+ direction position)) (overflow (map 'list #'> temp-position (array-dimensions map)))) (cond ((first overflow) :bottom) ((second overflow) (progn (decf (second temp-position) (second (array-dimensions map))) temp-position)) (t temp-position)))) (defun solve-3-1 (direction map) (let ((tree-count 0)) (labels ((rec (position) (let ((zero-pos (map 'list #'1- position)) (new-pos (step-slope position direction map))) (if (char= (aref map (first zero-pos) (second zero-pos)) #\#) (incf tree-count)) (unless (eq new-pos :bottom) (rec new-pos))))) (rec '(1 1)) tree-count))) ;; (height width) (defun solve-3-2 (slopes map) (reduce #'* (loop for slope in slopes collecting (solve-3-1 slope map)))) (defun solve-3 (map) (time (let ((data (read-3 map))) (print (solve-3-1 '(1 3) data)) (print (solve-3-2 '((1 1) (1 3) (1 5) (1 7) (2 1)) data))))) (defvar *passport-fields* (list "byr" "iyr" "eyr" "hgt" "hcl" "ecl" "pid" "cid")) (defvar *passport-rules-broken* (list nil nil nil nil nil nil nil (lambda (n) (declare (ignore n)) t))) (defvar *passport-rules* nil) (setf *passport-rules* (list (lambda (n) (and n (let ((nn (ignore-errors (parse-integer n)))) (and nn (>= nn 1920) (<= nn 2002))))) (lambda (n) (and n (let ((nn (ignore-errors (parse-integer n)))) (and nn (>= nn 2010) (<= nn 2020))))) (lambda (n) (and n (let ((nn (ignore-errors (parse-integer n)))) (and nn (>= nn 2020) (<= nn 2030))))) (lambda (h) (and h (multiple-value-bind (n offset) (parse-integer h :junk-allowed t) (let ((unit (subseq h offset))) (cond ((string= unit "cm") (and (>= n 150) (<= n 193))) ((string= unit "in") (and (>= n 59) (<= n 76)))))))) (lambda (c) (and c (= (length c) 7) (char= (elt c 0) #\#) (parse-integer (subseq c 1) :radix 16))) (lambda (c) (and c (member c '("amb" "blu" "brn" "gry" "grn" "hzl" "oth") :test #'equal))) (lambda (pid) (and pid (= 9 (length pid) (length (remove-if (lambda (n) (not (digit-char-p n))) pid))))) (lambda (cid) (declare (ignore cid)) t))) (defun read-passport (stream) (let ((passport-list (apply #'concatenate 'list (loop for line = (read-line stream nil) while (and line (not (string= line ""))) collect (split-sequence:split-sequence #\space line)))) (current-passport (make-hash-table :test 'equal))) (loop for key in passport-list do (setf (gethash (subseq key 0 3) current-passport) (subseq key 4))) current-passport)) (defun read-4 (file) (with-open-file (stream file) (loop while (peek-char nil stream nil) collect (read-passport stream)))) (defun %solve-4 (data tests) (let ((valid-count 0)) (loop for passport in data do (unless (member 'nil (map 'list (lambda (field test) (if test (funcall test (gethash field passport)) (gethash field passport))) *passport-fields* tests)) (incf valid-count))) valid-count)) (defun solve-4 (file) (let ((data (read-4 file))) (time (progn (print (%solve-4 data *passport-rules-broken*)) (print (%solve-4 data *passport-rules*))))))