;; https://adventofcode.com/2022/day/20 (defpackage :day-20 (:use :cl)) (in-package :day-20) (ql:quickload :array-operations) (ql:quickload "fiveam") (ql:quickload 'alexandria) (5am:def-suite day20-tests) ;; and shift some slice 1 to right (defun move-item-to-left (array moved-index move-size) (declare (optimize (debug 3))) (let* ((move-size (mod move-size (1- (length array)))) (moved-value (aref array moved-index)) (move-by (- (mod move-size (length array)))) (moving-slice-size move-size) (to-be-moved (make-array moving-slice-size :displaced-to array :displaced-index-offset (+ moved-index move-by))) (into-these-move (make-array moving-slice-size :displaced-to array :displaced-index-offset (+ moved-index move-by 1)))) (loop for i from (1- move-size) downto 0 do (setf (aref into-these-move i) (aref to-be-moved i))) (setf (aref array (+ moved-index move-by)) moved-value) array)) (5am:def-test move-left-inside-of-array (:suite day20-tests) (5am:is (equalp (make-array 10 :initial-contents '(0 1 2 6 3 4 5 7 8 9)) (move-item-to-left (aops:linspace 0 9 10) 6 3)))) (5am:def-test move-left-to-edge (:suite day20-tests) (5am:is (equalp (make-array 10 :initial-contents '(6 0 1 2 3 4 5 7 8 9)) (move-item-to-left (aops:linspace 0 9 10) 6 6)))) (5am:def-test move-by-arr-size-leaves-intact (:suite day20-tests) (5am:is (equalp (make-array 10 :initial-contents '(0 1 2 3 4 5 6 7 8 9)) (move-item-to-left (aops:linspace 0 9 10) 6 9)))) (5am:def-test move-by-more-than-arr-size (:suite day20-tests) (5am:is (equalp (make-array 10 :initial-contents '(0 1 2 6 3 4 5 7 8 9)) (move-item-to-left (aops:linspace 0 9 10) 6 12)))) (defun move-item-to-right (array moved-index move-by) (declare (optimize (debug 3))) (let* ((move-by (mod move-by (1- (length array)))) (moved-value (aref array moved-index)) (moving-slice-size move-by) (to-be-moved (make-array moving-slice-size :displaced-to array :displaced-index-offset (+ moved-index 1))) (into-these-move (make-array moving-slice-size :displaced-to array :displaced-index-offset moved-index))) (loop for i from 0 below move-by do (setf (aref into-these-move i) (aref to-be-moved i))) (setf (aref array (+ moved-index move-by)) moved-value) array)) (5am:def-test move-right-inside-of-array (:suite day20-tests) (5am:is (equalp (make-array 10 :initial-contents '(0 1 2 3 4 5 7 6 8 9)) (move-item-to-right (aops:linspace 0 9 10) 6 1)))) (5am:def-test move-right-to-edge (:suite day20-tests) (5am:is (equalp (make-array 10 :initial-contents '(0 1 2 3 4 5 7 8 9 6)) (move-item-to-right (aops:linspace 0 9 10) 6 3)))) (5am:def-test move-right-by-arr-size-leaves-intact (:suite day20-tests) (5am:is (equalp (make-array 10 :initial-contents '(0 1 2 3 4 5 6 7 8 9)) (move-item-to-right (aops:linspace 0 9 10) 6 9)))) (5am:def-test move-right-by-more-than-arr-size (:suite day20-tests) (5am:is (equalp (make-array 10 :initial-contents '(0 1 2 3 4 5 7 8 9 6)) (move-item-to-right (aops:linspace 0 9 10) 6 12)))) (defun move-item (array move-index move-by) (let* ((raw-target-index (if (>= move-by 0) (+ move-index move-by) (+ move-index move-by))) (in-array-target-index (mod raw-target-index (1- (length array)))) (in-array-target-index (if (= 0 in-array-target-index) (1- (length array)) in-array-target-index ; a hack )) (safe-move-by (- in-array-target-index move-index))) ;; (list move-index move-by ;; 'raw-target raw-target-index ;; 'in-array-target in-array-target-index ;; 'safe-move-by safe-move-by) (if (> safe-move-by 0) (move-item-to-right array move-index safe-move-by) (move-item-to-left array move-index (- safe-move-by))) )) ;; we know the element value, but not it's place (defun move-elem-by-itself (array element) (declare (optimize (debug 3))) (let ((i (position element array))) (move-item array i element))) (defun mixing-array (arr) (let ((to-be-modified (alexandria:copy-array arr))) (loop for elem across arr do (progn (move-elem-by-itself to-be-modified elem) (format t "after moving ~a, arr: ~a~%" elem to-be-modified) )) to-be-modified)) (5am:run! 'day20-tests)