;;; https://gitlab.com/Syndamia/senzill (require :senzill) (use-package :senzill.math) (use-package :senzill.collections) (use-package :senzill.pair) (use-package :senzill.io) (defparameter +rope-length+ 10) (ask-for-stream (prog-input) (let ((rope '()) (visited '((0 . 0)))) (flet ((norm>sqrt2p (p) ; If c's eucledian length is less than sqrt(2). In other words, if c is outside the 3x3 square. "Optimized version of (> (norm p) (sqrt 2))" (or (> (abs (car p)) 1) (> (abs (cdr p)) 1))) (dir-to-pair (direction) (cond ((char= direction #\R) '( 1 . 0)) ((char= direction #\L) '(-1 . 0)) ((char= direction #\U) '( 0 . 1)) ((char= direction #\D) '( 0 . -1))))) (dotimes (i +rope-length+) (push '(0 . 0) rope)) (doread-lines (inpt :read-line-options (prog-input NIL)) (loop for i from 1 to (parse-integer inpt :start 2) for dirvec = (dir-to-pair (char inpt 0)) do (pair+= (first rope) dirvec) ; First knot is the head ;;; We update the knot positions from left to right (from head to tail) ;;; Since each knot depends on the previous, we iterate from head to tail-1 ;;; but always update "the second element" (from head+1 to tail) (loop for knot on rope while (cdr knot) for movec = (pair- (first knot) (second knot)) ; head - tail if (norm>sqrt2p movec) do ;; dist-resize so we don't put the knot on top of the other, but behind it (pair+= (second knot) (pair-round (dist-resize-by movec -1))) finally (if (not (member-if (lambda (x) (pair= x (car knot))) visited)) (push (car knot) visited))))) (print (length visited)))))