(asdf:load-system :adventofcode2020) (in-package #:adventofcode2020) (named-readtables:in-readtable :adventofcode2020) (defun parse-action (str) (cl-ppcre:register-groups-bind ((λ(char _ 0) action) (#'parse-integer scalar)) ("([NSEWLRF])([0-9]+)" str) (list action scalar))) (defstruct ship (heading #\E) (ns-coord 0) (ew-coord 0) (waypoint-ns 1) (waypoint-ew 10)) (defun apply-turn-heading (heading degree) (let ((directions #(#\N #\E #\S #\W)) (heading-delta (/ degree 90))) (-<> (position heading directions) (+ heading-delta) (mod 4) (aref directions <>)))) (defun apply-turn-space (x y degree) (if (= degree 0) (list x y) (destructuring-bind (x y) (apply-turn-space x y (- degree (* (signum degree) 90))) (if (> degree 0) (list y (* -1 x)) (list (* -1 y) x))))) (defun apply-action-ship (ship act-pair) (destructuring-bind (action scalar) act-pair (let ((new-ship (copy-structure ship))) (case action (#\N (setf (ship-ns-coord new-ship) (+ (ship-ns-coord ship) scalar))) (#\S (setf (ship-ns-coord new-ship) (- (ship-ns-coord ship) scalar))) (#\E (setf (ship-ew-coord new-ship) (+ (ship-ew-coord ship) scalar))) (#\W (setf (ship-ew-coord new-ship) (- (ship-ew-coord ship) scalar))) (#\L (setf (ship-heading new-ship) (apply-turn-heading (ship-heading ship) (* -1 scalar)))) (#\R (setf (ship-heading new-ship) (apply-turn-heading (ship-heading ship) (* +1 scalar)))) (#\F (setf new-ship (apply-action-ship new-ship (list (ship-heading ship) scalar))))) new-ship))) (defun apply-action-waypoint (ship act-pair) (destructuring-bind (action scalar) act-pair (let ((new-ship (copy-structure ship))) (case action (#\N (setf (ship-waypoint-ns new-ship) (+ (ship-waypoint-ns ship) scalar))) (#\S (setf (ship-waypoint-ns new-ship) (- (ship-waypoint-ns ship) scalar))) (#\E (setf (ship-waypoint-ew new-ship) (+ (ship-waypoint-ew ship) scalar))) (#\W (setf (ship-waypoint-ew new-ship) (- (ship-waypoint-ew ship) scalar))) (#\L (destructuring-bind (x y) (apply-turn-space (ship-waypoint-ew ship) (ship-waypoint-ns ship) (* -1 scalar)) (setf (ship-waypoint-ew new-ship) x) (setf (ship-waypoint-ns new-ship) y))) (#\R (destructuring-bind (x y) (apply-turn-space (ship-waypoint-ew ship) (ship-waypoint-ns ship) (* +1 scalar)) (setf (ship-waypoint-ew new-ship) x) (setf (ship-waypoint-ns new-ship) y))) (#\F (setf (ship-ns-coord new-ship) (+ (ship-ns-coord ship) (* scalar (ship-waypoint-ns ship)))) (setf (ship-ew-coord new-ship) (+ (ship-ew-coord ship) (* scalar (ship-waypoint-ew ship)))))) new-ship))) (day 12 input (let ((actions (mapcar #'parse-action (list-from input)))) (part1 (let ((final-ship (reduce #'apply-action-ship actions :initial-value (make-ship)))) (manhattan-distance (list 0 0) (list (ship-ew-coord final-ship) (ship-ns-coord final-ship))))) (part2 (let ((final-ship (reduce #'apply-action-waypoint actions :initial-value (make-ship)))) (manhattan-distance (list 0 0) (list (ship-ew-coord final-ship) (ship-ns-coord final-ship))))))) (def-suite day12) (in-suite day12) (defvar *simple-actions* '("F10" "N3" "F7" "R90" "F11")) (test apply-turns-heading (is (equal #\S (apply-turn-heading #\E 90))) (is (equal #\W (apply-turn-heading #\E 180))) (is (equal #\N (apply-turn-heading #\E 270))) (is (equal #\N (apply-turn-heading #\E -90))) (is (equal #\W (apply-turn-heading #\E -180)))) (test apply-actions-ship (is (equalp (make-ship :heading #\S :ns-coord -8 :ew-coord 17) (reduce #'apply-action-ship (mapcar #'parse-action *simple-actions*) :initial-value (make-ship))))) (run! 'day12)