Advent of Code 2024
Table of Contents
1. Day 12
(ql:quickload :uiop) (ql:quickload :alexandria) (defun yield-grid (input-file) (let* ((lines (uiop:read-file-lines input-file)) (arr (make-array (list (length lines) (length (car lines))) :initial-element nil))) (loop for i from 0 below (array-dimension arr 0) for line in lines do (loop for j from 0 below (array-dimension arr 1) do (setf (aref arr i j) (char line j)))) arr)) (defparameter *grid* (yield-grid "input.txt")) (defparameter *cluster-grid* (make-array (array-dimensions *grid*) :initial-element -1)) (defun scaffold-cluster (init-id chr) (let ((charac chr) (id init-id) (indices (make-hash-table :test 'equal)) (area 0) (perim 0) (vertex 0)) (labels ((get-id () id) (get-chr () charac) (insert-pos (i j) (setf (gethash (list i j) indices) t)) (indices () (alexandria:hash-table-keys indices)) (indexp (pos) (gethash pos indices)) (g-area () area) (inc-area () (incf area)) (g-perim () perim) (inc-perim () (incf perim)) (g-vertex () vertex) (inc-vertex () (incf vertex)) (orchestrate (msg) (case msg (:id #'get-id) (:chr #'get-chr) (:insert #'insert-pos) (:indices #'indices) (:idxp #'indexp) (:g-area #'g-area) (:g-perim #'g-perim) (:g-vertex #'g-vertex) (:inc-area #'inc-area) (:inc-perim #'inc-perim) (:inc-vertex #'inc-vertex) (otherwise (error 'invalid-msg msg))))) #'orchestrate))) (defmacro cf (cluster msg &rest args) `(funcall (funcall ,cluster ,msg) ,@args)) (defparameter *clusters* (make-hash-table)) (defmacro cidf (id msg &rest args) `(cf ,(gethash id *clusters*) ,msg ,@args)) (defun unmarked (i j) (when (array-in-bounds-p *cluster-grid* i j) (= (aref *cluster-grid* i j) -1))) (defun find-cluster (test-fn) (loop for i from 0 below (array-dimension *cluster-grid* 0) do (loop for j from 0 below (array-dimension *cluster-grid* 1) do (when (funcall test-fn i j) (return-from find-cluster (list i j)))))) (defun find-unmarked () (find-cluster #'unmarked)) (defun surroundings (i j) (list (list i (1- j)) (list (1- i) j) (list (1+ i) j) (list i (1+ j)))) (defparameter *corners* (list (list 1 1) (list -1 -1) (list 1 -1) (list -1 1))) (defun explore-root (id i j) (let* ((c-char (aref *grid* i j)) (c (scaffold-cluster id c-char))) (setf (gethash id *clusters*) c) (labels ((same? (ic jc) (when (array-in-bounds-p *grid* ic jc) (eq (aref *grid* ic jc) c-char))) (explore-dir-vertex (ic jc istep jstep) (when (array-in-bounds-p *grid* ic jc) (let ((istpd (same? (+ ic istep) jc)) (jstpd (same? ic (+ jc jstep))) (ijstpd (same? (+ ic istep) (+ jc jstep)))) (when (or (and (not istpd) (not jstpd)) (and (not ijstpd) istpd jstpd)) (cf c :inc-vertex))))) (explore-iter (ic jc) (if (array-in-bounds-p *grid* ic jc) (cond ((same? ic jc) (when (unmarked ic jc) (progn (cf c :inc-area) (setf (aref *cluster-grid* ic jc) id) (cf c :insert ic jc) (mapcar #'(lambda (pos) (apply #'explore-iter pos)) (surroundings ic jc))))) (t (cf c :inc-perim))) (cf c :inc-perim)))) (explore-iter i j) (dolist (cpos (cf c :indices)) (dolist (corner *corners*) (explore-dir-vertex (car cpos) (cadr cpos) (car corner) (cadr corner)))) (values (cf c :g-area) (cf c :g-perim) (cf c :g-vertex))))) (defun build-cluster-grid () (let ((acc-area-perim 0) (acc-area-sides 0)) (do ((next-unmarked (list 0 0) (find-unmarked)) (id 0 (1+ id))) ((not next-unmarked) (list acc-area-perim acc-area-sides)) (multiple-value-bind (area perim sides) (apply #'explore-root (cons id next-unmarked)) (incf acc-area-perim (* area perim)) (incf acc-area-sides (* area sides))))))
2. Day 11
(ql:quickload :uiop) (defparameter *stones* (uiop:split-string (uiop:read-file-line "input.txt"))) (defun even-str-p (string) (evenp (length string))) (defun strip-string (stone) (write-to-string (parse-integer stone))) (defun x2024 (stone) (write-to-string (* (parse-integer stone) 2024))) (defun halves (string) (let ((split (/ (length string) 2))) (mapcar #'strip-string (list (subseq string 0 split) (subseq string split))))) (defparameter *mem* (make-hash-table :test 'equal)) (defmacro ghsh (stone steps) `(gethash (list ,stone ,steps) *mem*)) (defun nstep (stone steps) (if (ghsh stone steps) (ghsh stone steps) (setf (ghsh stone steps) (cond ((= steps 0) 1) ((equal stone "0") (nstep "1" (1- steps))) ((even-str-p stone) (apply #'+ (mapcar #'(lambda (stone) (nstep stone (1- steps))) (halves stone)))) (t (nstep (x2024 stone) (1- steps))))))) (defun solve (i) (apply #'+ (mapcar #'(lambda (stone) (nstep stone i)) *stones*)))
3. Day 10
(ql:quickload :uiop) (ql:quickload :alexandria) ;; dynamic prog ;; at an n (store current position if peak) ;; merge positions of all surrounding (n+1s) ;; at a base (collate results of the base+1) (defparameter *base* 0) (defparameter *peak* 9) (defun char->int (char) (- (char-int char) (char-int #\0))) (defun parse-topography (input-file) (let* ((lines (uiop:read-file-lines input-file)) (arr (make-array (list (length lines) (length (car lines))) :element-type 'integer))) (loop for row from 0 below (array-dimension arr 0) do (loop for col from 0 below (array-dimension arr 1) do (setf (aref arr row col) (char->int (aref (nth row lines) col) ) ))) arr)) (defparameter *topography* (parse-topography "input.txt")) (defparameter *collates* (make-array (array-dimensions *topography*) :initial-element nil :element-type 'list)) (defun prot-get (arr i j) (when (array-in-bounds-p arr i j) (aref arr i j))) (defun prot-set (arr i j val) (when (array-in-bounds-p arr i j) (setf (aref arr i j) val))) (defun tget (i j) (prot-get *topography* i j)) (defun tset (i j val) (prot-set *topography* i j val)) (defun cget (i j) (prot-get *collates* i j)) (defun cset (i j val) (prot-set *collates* i j val)) (defun cpush (i j vals) (let ((init-vals (cget i j))) (setf (aref *collates* i j) (append vals init-vals)))) ;; start from peak ;; iterate until base (defparameter rows (array-dimension *topography* 0)) (defparameter cols (array-dimension *topography* 1)) (defun surroundings (i j) (list (list (1+ i) j) (list i (1+ j)) (list (1- i) j) (list i (1- j)))) (defun mark-surrounding-inits (i j n) (loop for pos in (surroundings i j) do (if (eq (tget (car pos) (cadr pos)) (1- n)) (cpush (car pos) (cadr pos) (cget i j))))) (defun populate-collation () (loop for curr from *peak* above *base* do (loop for i from 0 below rows do (loop for j from 0 below cols do (when (= (tget i j) curr) (when (= curr *peak*) (cpush i j (list (list i j)))) (mark-surrounding-inits i j curr)))))) (defun deduplicate () (loop for i from 0 below rows do (loop for j from 0 below cols do (cset i j (remove-duplicates (cget i j) :test #'equal))))) (defun report-base-scores () (let ((acc 0)) (loop for i from 0 below rows do (loop for j from 0 below cols do (when (= (tget i j) *base*) (incf acc (length (cget i j)))))) acc)) (defun solve-p1 () (populate-collation) (deduplicate) (report-base-scores)) (defun solve-p2 () (populate-collation) ;; (deduplicate) (report-base-scores))
4. Day 9
(ql:quickload :uiop) (ql:quickload :alexandria) (defun swap (arr i1 i2) (let ((temp (aref arr i1))) (setf (aref arr i1) (aref arr i2)) (setf (aref arr i2) temp))) (defun swap-lr (arr ll lr rl rr) (dotimes (i (1+ (- lr ll)) ) (swap arr (+ ll i) (+ rl i)))) (defun len (r) (- (cadr r) (car r) -1)) (defun process-init-checksum (input) (let* ((checksum (mapcar #'(lambda (char) (- (char-int char) (char-int #\0))) (coerce (car (uiop:read-file-lines input)) 'list))) (total-blocks (apply #'+ checksum)) (disk (make-array (list total-blocks) :initial-element -1)) (flrs nil) (eyrs nil)) (let ((i 0) (id 0) (empty nil)) (dolist (j checksum) (if (not empty) (progn (push (list i (+ j i -1)) flrs) (dotimes (b j) (setf (aref disk i) id) (incf i)) (incf id) (setf empty t)) (progn (when (>= (+ j i -1) i) (push (list i (+ j i -1)) eyrs)) (dotimes (b j) (setf (aref disk i) -1) (incf i)) (setf empty nil))))) (setf eyrs (nreverse eyrs)) (labels ((check-swap () (let* ((eyr (car eyrs)) (flr (find-if #'(lambda (flr) (<= (len flr) (len eyr))) flrs))) (if flr (let* ((ll (car eyr)) (lr (+ ll (len flr) -1)) (rl (car flr)) (rr (cadr flr))) (if (= (len flr) (len eyr)) (pop eyrs) (let ((neweyr (list (1+ lr) (cadr eyr)))) (pop eyrs) (push neweyr eyrs))) (setf flrs (remove-if #'(lambda (an-flr) (equal an-flr flr)) flrs)) (swap-lr disk ll lr rl rr)) (pop eyrs))))) (do () ((null eyrs) nil) (check-swap))) (do ((i 0 (+ 1 i)) (acc 0 acc)) ((eq i (length disk)) acc) (when (not (eq (aref disk i) -1)) (incf acc (* (aref disk i) i)))))) (process-init-checksum "input.txt")
5. Day 8
(ql:quickload :uiop) (ql:quickload :alexandria) (defun build-arr (input-file) (let* ((lines (uiop:read-file-lines input-file)) (arr (make-array (list (length lines) (length (car lines))) :element-type 'character))) (loop for row from 0 below (array-dimension arr 0) for line in lines do (loop for col from 0 below (array-dimension arr 1) do (setf (aref arr row col) (aref line col)))) arr)) (defparameter arr (build-arr "input.txt")) (defun fetch (i j) (when (array-in-bounds-p arr i j) (aref arr i j))) (defun setarr (i j val) (when (array-in-bounds-p arr i j) (setf (aref arr i j) val))) (defparameter hash (make-hash-table)) (defun inshash (key val) (if (gethash key hash) (setf (gethash key hash) (cons val (gethash key hash))) (setf (gethash key hash) (list val)))) (defun build-hash-from-arr () (loop for i from 0 below (array-dimension arr 0) do (loop for j from 0 below (array-dimension arr 1) do (let ((chr (fetch i j))) (when (not (eq chr #\.)) (inshash chr (list i j))))))) (build-hash-from-arr) (defun build-pairs (items) (remove-duplicates (remove-if #'(lambda (coords) (or (equal (car coords) (cadr coords)))) (alexandria:map-product #'list items items)) :test #'(lambda (a b) (equal a (reverse b))))) (defun vec-add (p1 p2) (mapcar #'+ p1 p2)) (defun vec-mul (p factor) (mapcar #'(lambda (ele) (* ele factor)) p)) (defun extrapolate (va vb) (let ((dir (vec-add vb (vec-mul va -1))) (antis '())) (do ((anti (vec-add va dir) (vec-add anti dir))) ((not (array-in-bounds-p arr (car anti) (cadr anti))) antis) (push anti antis)))) (defun calc-antinodes (va vb) (append (extrapolate va vb) (extrapolate vb va))) (defun report-all-antinodes () (remove-if-not #'(lambda (coord) (apply #'array-in-bounds-p arr coord)) (remove-duplicates (reduce #'append (mapcar #'(lambda (coord) (apply #'calc-antinodes coord)) (reduce #'append (mapcar #'build-pairs (alexandria:hash-table-values hash))))) :test 'equal))) (defun solve () (length (report-all-antinodes)))
6. Day 7
(ql:quickload :uiop) (ql:quickload :cl-ppcre) (defun parse-line (line) (let ((parsed (cl-ppcre:split ": " line))) (list (parse-integer (car parsed)) (mapcar #'parse-integer (uiop:split-string (cadr parsed)))))) (defun || (int1 int2) (parse-integer (format nil "~S~S" int1 int2))) (defun dfs (target path) (labels ((dfs-iter (left acc) (macrolet ((fork (op) `(dfs-iter (cdr left) (,op acc (car left))))) (cond ((null left) (= acc target)) (t (or (fork *) (fork +) (fork ||))))))) (dfs-iter (cdr path) (car path)))) (defun solve (input-file) (apply #'+ (remove-if #'null (mapcar #'(lambda (line) (let ((parsed (parse-line line))) (when (dfs (car parsed) (cadr parsed)) (car parsed)))) (uiop:read-file-lines input-file)))))
7. Day 6
(ql:quickload :uiop) (ql:quickload :alexandria) (defvar input (uiop:read-file-lines "test.txt")) (defun gen-util-funcs (arr) (macrolet ((in? (i low high) `(and (< ,i ,high) (>= ,i ,low)))) (let ((rows (length arr)) (cols (length (car arr))) (utils (make-hash-table))) (setf (gethash :idx utils ) (lambda (i j) ;; indexer (aref (nth i arr) j))) (setf (gethash :set utils) (lambda (i j char) (setf (aref (nth i arr) j) char))) (setf (gethash :chk utils) (lambda (i j) ;; validity checker (and (in? i 0 rows) (in? j 0 cols)))) utils))) (defvar utils (gen-util-funcs input)) (defun fetch (i j) (when (funcall (gethash :chk utils) i j) (funcall (gethash :idx utils) i j))) (defun setgr (i j char) (when (funcall (gethash :chk utils) i j) (funcall (gethash :set utils) i j char))) (defun setgrl (l char) (setgr (car l) (cadr l) char)) (defun fetchl (l) (fetch (car l) (cadr l))) ;; orientation can be decided by current stepper func ;; storing such that when you cycling through them is turning right (defvar dirs (list #'(lambda (i j) (list (1- i) j)) #'(lambda (i j) (list i (1+ j))) #'(lambda (i j) (list (1+ i) j)) #'(lambda (i j) (list i (1- j))))) (defvar dir-hash (make-hash-table)) (setf (gethash #\^ dir-hash) 0) (setf (gethash #\> dir-hash) 1) (setf (gethash #\v dir-hash) 2) (setf (gethash #\< dir-hash) 3) (defun yield-dir (dx) (nth dx dirs)) (defun turn-right (dx) (mod (1+ dx) 4)) (defun turn-left (dx) (mod (1- dx) 4)) (defun turn-around (dx) (mod (+ 2 dx) 4)) ;; moving around ;; given initial directions ;; dowhile with a counter map and incf for new place ;; continue until fetch is nil ;; when fetch is obstacle, turn right ;; when fetch is ., step ;; recurse (defun detect-initial-pos-dir () (dotimes (i (length input)) (dotimes (j (length (car input))) (let ((curr (fetch i j))) (when (not (find curr (list #\. #\#))) (setgr i j #\X) (return-from detect-initial-pos-dir (list i j (gethash curr dir-hash)))))))) ;; store dirs walked at an x ;; when x and dir sync, stop step (defun walkeds (input) (loop repeat (length input) collect (loop repeat (length (car input)) collect '()))) (defvar walkeds (walkeds input)) (defmacro fwalkeds (i j) `(nth ,j (nth ,i walkeds))) (defun inswalkeds (i j char) (setf (fwalkeds i j) (cons char (fwalkeds i j)))) (defun coincides? (i j dir) (find dir (fwalkeds i j))) (defvar found-obs '()) (defun already-placed? (i j) (find -1 (fwalkeds i j))) (defun potential-obs-ahead? (i j dir) (cond ((not (fetch i j)) nil) ((coincides? i j dir) t) (t (let ((next (funcall (yield-dir dir) i j))) (if (eq (fetchl next) #\#) (apply #'potential-obs-ahead? (append next (list (turn-right dir)))) (potential-obs-ahead? (car next) (cadr next) dir)))))) (defun walk () (let ((marked 1) (potential-obs 0) (obses '()) (pos-dir (detect-initial-pos-dir))) (labels ((stp (dx i j) (let* ((next (funcall (yield-dir dx) i j)) (fnext (fetchl next))) (inswalkeds i j dx) (cond ((eq fnext #\.) (progn (when (potential-obs-ahead? i j (turn-right dx)) (when (apply #'already-placed? next) (decf potential-obs)) (setf obses (cons (list (list 'in-from i j) `('obs-on ,@next) dx (turn-right dx)) obses)) (incf potential-obs)) (setgrl next #\X) (incf marked) (stp dx (car next) (cadr next)))) ((eq fnext #\#) (stp (turn-right dx) i j)) ((eq fnext #\X) (progn (when (potential-obs-ahead? i j (turn-right dx)) (when (apply #'already-placed? next) (decf potential-obs)) (setf obses (cons (list (list 'in-from i j) `('obs-on ,@next) dx (turn-right dx)) obses)) (incf potential-obs)) (stp dx (car next) (cadr next)))) (t (list obses marked potential-obs)))))) (inswalkeds (car pos-dir) (cadr pos-dir) (caddr pos-dir)) (stp (caddr pos-dir) (car pos-dir) (cadr pos-dir)))))
8. Day 5
(ql:quickload :uiop) (ql:quickload :alexandria) (ql:quickload :cl-ppcre) (defun parse-input (input-file) (let* ((parsed (cl-ppcre:split "\\n\\n" (uiop:read-file-string input-file))) (edges (cl-ppcre:split "\\n" (car parsed))) (updates (cl-ppcre:split "\\n" (cadr parsed)))) (list edges updates))) (defun gen-hash-manager () (let ((hsh (make-hash-table))) #'(lambda (message) (cond ((eq message 'reset) #'(lambda () (clrhash hsh))) ((eq message 'table) #'(lambda () hsh)) ((eq message 'insert) #'(lambda (key val) (let ((existing (gethash key hsh))) (if existing (setf (gethash key hsh) (cons val existing)) (setf (gethash key hsh) (list val)))))) ((eq message 'fetch) #'(lambda (key) (gethash key hsh))) (t (error message "invalid message received")))))) (defvar hasher (gen-hash-manager)) (defun insert (key val) (funcall (funcall hasher 'insert) key val)) (defun fetch (key) (funcall (funcall hasher 'fetch) key)) (defun build-hash (edges) (dolist (edge edges) (let ((split (cl-ppcre:split #\| edge))) (insert (parse-integer (cadr split)) (parse-integer (car split)))))) (defvar input (parse-input "input.txt")) (build-hash (car input)) (defun check-update (update) (let ((update (mapcar #'parse-integer update)) (mid (ceiling (/ (length update) 2))) (middle nil)) (do ((curr (car update) (car tail)) (tail (cdr update) (cdr tail)) (i 1 (+ i 1))) ((not tail) middle) (when (= i mid) (setf middle curr)) (when (intersection tail (fetch curr)) (return nil))))) (defun solve-p1 () (reduce #'(lambda (acc curr) (+ acc (if curr curr 0))) (mapcar #'check-update (mapcar (alexandria:curry #'cl-ppcre:split #\,) (cadr input))) :initial-value 0)) ;; part 2 (defun insert-at-index (list element index) (if (zerop index) (cons element list) (let ((head (subseq list 0 index)) (tail (nthcdr index list))) (append head (list element) tail)))) (defun curtail (curr tail intsction) (let ((fixes (insert-at-index tail curr (1+ (apply #'max (mapcar #'(lambda (ele) (position ele tail)) intsction)))))) (values (car fixes) (cdr fixes)))) (defun check-fixed-update (update) (let ((update (mapcar #'parse-integer update)) (mid (ceiling (/ (length update) 2))) (fix-flag nil) (middle nil)) (do ((curr (car update) (car tail)) (tail (cdr update) (cdr tail)) (i 1 (+ i 1))) ((not tail) (when fix-flag middle)) (tagbody start (let ((intsction (intersection tail (fetch curr)))) (when intsction (setf fix-flag t) (multiple-value-bind (cr tl) (curtail curr tail intsction) (setf curr cr tail tl)) (go start))) (when (= i mid) (setf middle curr)))))) (defun solve-p2 () (reduce #'(lambda (acc curr) (print curr) (+ acc (if curr curr 0))) (mapcar #'check-fixed-update (mapcar (alexandria:curry #'cl-ppcre:split #\,) (cadr input))) :initial-value 0))
9. Day 4
;; for each cell, check 8 directions ;; checking in a direction can be generically identified as an accumulated past state and the stepper function ;; the stepper functions will then be 8 of them ranging cartesian product of +1,-1,0 for x,y except 0,0 (9-1) ;; can build steppers dynamically with macros ;; the checker actually uses a stepper func, has the current state and has the knowledge of the state machine baked in (ql:quickload :uiop) (ql:quickload :alexandria) (defvar input (uiop:read-file-lines "input.txt")) (defun gen-util-funcs (arr) (macrolet ((in? (i low high) `(and (< ,i ,high) (>= ,i ,low)))) (let ((rows (length arr)) (cols (length (car arr))) (utils (make-hash-table))) (setf (gethash :idx utils ) (lambda (i j) ;; indexer (aref (nth i arr) j))) (setf (gethash :chk utils) (lambda (i j) ;; validity checker (and (in? i 0 rows) (in? j 0 cols)))) utils))) (defvar utils (gen-util-funcs input)) (defun fetch (i j) (when (funcall (gethash :chk utils) i j) (funcall (gethash :idx utils) i j))) (defun build-stepper (steps) #'(lambda (x y) (list (+ x (car steps)) (+ y (cadr steps))))) (defvar steppers (cdr (mapcar #'build-stepper (loop for x in (list 0 1 -1) nconc (loop for y in (list 0 1 -1) collect (list x y)))) )) (defun checker (i j stepper req) (labels ((iter-check (x y req-i) (let ((fetched (fetch x y)) (lreq (length req))) (cond ((= req-i lreq) t) ((not fetched) nil) ((equal fetched (aref req req-i)) (apply #'iter-check (append (funcall stepper x y) (list (+ 1 req-i))))))))) (iter-check i j 0))) (defun collate-checks (i j req) (count 't (mapcar #'(lambda (stepper) (checker i j stepper req)) steppers))) (defun solve-p1 (req) (let ((acc 0)) (dolist (i (alexandria:iota (length input))) (dolist (j (alexandria:iota (length (car input)))) (incf acc (collate-checks i j req)))) acc)) ;; part 2 ;; approach still the same via specific steppers, just validator can be monolithic (defun check-X-MAS (i j) (when (equal (fetch i j) #\A) (and (eval `(or ,@(mapcar (alexandria:curry #'checker (1- i) (1- j) (build-stepper (list 1 1))) (list "MAS" "SAM")))) (eval `(or ,@(mapcar (alexandria:curry #'checker (1+ i) (1- j) (build-stepper (list -1 1))) (list "MAS" "SAM"))))))) (defun solve-p2 () (let ((acc 0)) (dolist (i (alexandria:iota (1- (length input)) :start 1)) (dolist (j (alexandria:iota (1- (length (car input))) :start 1)) (when (check-x-mas i j) (incf acc 1)))) acc))
10. Day 3
(ql:quickload :uiop) (ql:quickload :cl-ppcre) (defvar input (read-file-to-string "input")) ;; part 1 (defun extract-mul-parameters (input-string) (multiple-value-bind (matched-p matches) (cl-ppcre:scan-to-strings "mul\\((\\d+),(\\d+)\\)" input-string) (when matched-p matches))) (defun parse-mul (match) (let* ((parse-vec (extract-mul-parameters match)) (n1 (parse-integer (svref parse-vec 0))) (n2 (parse-integer (svref parse-vec 1)))) (* n1 n2))) (defun solve-p1 (input) (apply #'+ (mapcar #'parse-mul (cl-ppcre:all-matches-as-strings "mul\\((\\d+),(\\d+)\\)" input)))) ;; part 2 (defun solve-p2 (input) (let ((do? t) (acc 0)) (dolist (state (cl-ppcre:all-matches-as-strings "mul\\((\\d+),(\\d+)\\)|do\\(\\)|don't\\(\\)" input) acc) (cond ((equal state "do()") (setf do? t)) ((equal state "don't()") (setf do? nil)) (t (when do? (incf acc (parse-mul state))))))))
11. Day 2
(defvar test-input '((7 6 4 2 1) (1 2 7 8 9) (9 7 6 2 1) (1 3 2 4 5) (8 6 4 4 1) (1 3 6 7 9))) (defun transit-diff-set (report) (let ((len (length report))) (remove-duplicates (mapcar #'(lambda (n-1 n) (- n n-1)) (subseq report 0 (- len 1)) (subseq report 1 len)) ))) (defun dampened-val-report (report) (if (val-report report) 1 (do ((i 0 (+ 1 i))) ((= i (length report)) 0) (let ((candidate (append (subseq report 0 i) (subseq report (+ i 1) (length report))))) (when (val-report candidate) (return 1)))))) (defun val-report (report) (let* ((diffs (transit-diff-set report)) (abs-diffs (remove-duplicates (mapcar #'abs diffs)))) (cond ((find 0 abs-diffs ) nil) ((> (apply #'max abs-diffs) 3) nil) ((= (length (remove-duplicates (mapcar #'signum diffs))) 2) nil) (t 1)))) (defun safe-reports (input) (apply #'+ (mapcar #'dampened-val-report input)))
12. Day 1
(ql:quickload :alexandria) (defvar test-input '((3 4) (4 3) (2 5) (1 3) (3 9) (3 3))) ;; ;; Part 1 (defmacro parse-sort (selector input) (let ((ele (gensym))) `(sort (mapcar #'(lambda (,ele) (coerce (,selector ,ele) 'integer)) ,input) #'>))) (defun add-abs-diff-solver (input) (apply #'+ (mapcar (lambda (x y) (abs (- x y) )) (parse-sort car input) (parse-sort cadr input)))) ;; Part 2 ;; (defun build-hash (lis table) (labels ((increment-hash (ele) (if (gethash ele table) (incf (gethash ele table) 1) (setf (gethash ele table) 1)))) (mapcar #'increment-hash lis))) (defun built-hash (lis) (let ((hash (make-hash-table))) (build-hash lis hash) hash)) (defun freq-mul-add-solver (input) (let ((h-a (built-hash (parse-sort car input))) (h-b (built-hash (parse-sort cadr input))) (acc 0)) (dolist (ka (alexandria:hash-table-keys h-a) acc) (incf acc (if (gethash ka h-b) (* (gethash ka h-a) (gethash ka h-b) ka) 0)))))