137 lines
5.9 KiB
Common Lisp
137 lines
5.9 KiB
Common Lisp
;; 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 initial-index)
|
|
(declare (optimize (debug 3)))
|
|
(let ((i (position initial-index array :test (lambda (searched-index zipped)
|
|
(= searched-index (car zipped))))))
|
|
(move-item array i (second (aref array i)))))
|
|
|
|
(defun mixing-array (arr)
|
|
(let ((to-be-modified (alexandria:copy-array arr)))
|
|
(loop
|
|
for initial-index from 0 below (length arr)
|
|
;; for elem across arr
|
|
do (progn (move-elem-by-itself to-be-modified initial-index)
|
|
;; (format t "after moving ~a, arr: ~a~%" elem to-be-modified)
|
|
))
|
|
to-be-modified))
|
|
|
|
(defun zip-with-index (ls)
|
|
(loop for v in ls
|
|
for i from 0
|
|
collect (list i v)))
|
|
|
|
(defun input-arr (filename)
|
|
(let ((nums (mapcar #'parse-integer (uiop:read-file-lines filename))))
|
|
(make-array (length nums) :initial-contents (zip-with-index nums))))
|
|
|
|
(defun get-ugh-nth (arr n)
|
|
;; need to find 0 by value in the (index, value) array
|
|
(let* ((zero-ind (position 0 arr :test (lambda (searched-value zipped)
|
|
(= searched-value (second zipped)))))
|
|
(unsafe-index (+ zero-ind n))
|
|
(safe-n (mod unsafe-index (length arr))))
|
|
(second (aref arr safe-n))))
|
|
|
|
(defun part-1-ans (filename)
|
|
(let* ((input-arr (input-arr filename))
|
|
(mixed (mixing-array input-arr)))
|
|
(format t "getting part 1, mixed array: ~a~%" mixed)
|
|
(+ (get-ugh-nth mixed 1000)
|
|
(get-ugh-nth mixed 2000)
|
|
(get-ugh-nth mixed 3000))))
|
|
|
|
(5am:run! 'day20-tests)
|