diff options
Diffstat (limited to 'AoC2023/day18/solver.lisp')
-rw-r--r-- | AoC2023/day18/solver.lisp | 62 |
1 files changed, 62 insertions, 0 deletions
diff --git a/AoC2023/day18/solver.lisp b/AoC2023/day18/solver.lisp new file mode 100644 index 0000000..62adac2 --- /dev/null +++ b/AoC2023/day18/solver.lisp @@ -0,0 +1,62 @@ +;;8:16 +;;9:33 +;;10:45 +(ql:quickload '(fiveam arrows cl-ppcre)) + +(defun move (dir) + (ecase dir + ((R 0) (list 0 1)) + ((D 1) (list 1 0)) + ((L 2) (list 0 -1)) + ((U 3) (list -1 0)))) + +(defun parse (filename part) + (mapcar (lambda (line) + (destructuring-bind (dir len rest) + (cl-ppcre:split " " line) + (if (eq part 'first) + (list (intern dir) (parse-integer len)) + (list + (digit-char-p (aref rest 7)) + (parse-integer + (subseq rest 2 7) :radix 16))))) + (uiop:read-file-lines filename))) + +(defun polygon-area (points) + (destructuring-bind ((fx fy) (lx ly)) (cons (car points) (last points)) + (arrows:-> + (loop for ((x y) (nx ny)) on points by #'cdr + when nx + sum (- (* x ny) (* y nx))) + (+ (- (* lx fy) (* ly fx))) + (/ 2) + (abs)))) + +(fiveam:test partials + (fiveam:is (= 4.5 (polygon-area '((1 1) (3 2) (2 6)))))) + +(defun solver (filename part &aux (row 0) (col 0) (perimeter 0)) + (let ((points + (loop + for (dir len) in (parse filename part) + collect + (destructuring-bind (dr dc) (move dir) + (incf perimeter len) + (list + (incf row (* dr len)) + (incf col (* dc len))))))) + ;; poligon area is for no width boundary + ;; thus add half-perimeter. Think on a square + ;; top and left edges contain area, but right & bottom not + ;; thus add that part of perimeter as with. Then add 1 because + ;; the corner on bottom right + (+ + 1 + (/ perimeter 2) + (polygon-area points)))) + +(fiveam:test solutions + (fiveam:is (= 62 (solver "eg-in" 'first))) + (fiveam:is (= 76387 (solver "input" 'first))) + (fiveam:is (= 952408144115 (solver "eg-in" 'second))) + (fiveam:is (= 250022188522074 (solver "input" 'second)))) |