aboutsummaryrefslogtreecommitdiffstats
path: root/AoC2022/20/solver.lisp
blob: dc1f2c74fc6cc5779c41285443e2d3ad7813197c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
(ql:quickload '(fiveam uiop))

(defparameter *msg* #(1 2 -3 3 -2 0 4))

(defun directional-pointers (size)
  (let ((forward (make-array size))
        (reverse (make-array size)))
    (dotimes (i size)
      (setf (svref forward i) (mod (1+ i) size)
            (svref reverse i) (mod (1- i) size)))
    (values forward reverse)))

(defun follow-pointer (pointer index count)
  (if (zerop count)
      index
      (follow-pointer pointer (svref pointer index) (1- count))))

(defun move! (forward reverse element-idx shift)
  "FORWARD is the leading array, not necessarily forward movement"
  (let ((next-element (svref forward element-idx))
        (prev-element (svref reverse element-idx)))
    ;; remove element from sequence
    (setf (svref reverse next-element) prev-element)
    (setf (svref forward prev-element) next-element))
  (let* ((amount (1+ (mod (1- shift) (1- (length forward)))))
         (target-index (follow-pointer forward element-idx amount)))
    (psetf (svref reverse element-idx) target-index
           (svref reverse (svref forward target-index)) element-idx
           (svref forward element-idx) (svref forward target-index)
           (svref forward target-index) element-idx))
  (values forward reverse))

(defun shuffle! (forward reverse element-idx shift)
  (cond
    ((zerop shift))
    ((plusp shift)
     (move! forward reverse element-idx shift))
    ((move! reverse forward element-idx (abs shift))))
  (values forward reverse))

(defun shuffle-pointers (msg repeat)
  (multiple-value-bind (forward reverse) (directional-pointers (length msg))
    (dotimes (_ repeat)
      (dotimes (element-idx (length msg))
        ;; (format t "st: ~a f: ~a r: ~a~%" (ordered-series msg forward) forward reverse)
        (shuffle! forward reverse element-idx (svref msg element-idx))))
    (values forward reverse)))

(defun ordered-series (msg forward)
  (let* ((len (length msg))
         (series (make-array len)))
    (do ((i (position 0 msg) (svref forward i))
         (count 0 (1+ count)))
        ((<= len count) series)
      (setf (svref series count)
            (svref msg i)))))

(defun solver (repeat message)
  (let ((new-array
          (ordered-series message (shuffle-pointers message repeat))))
    (+
     (svref new-array (mod 1000 (length new-array)))
     (svref new-array (mod 2000 (length new-array)))
     (svref new-array (mod 3000 (length new-array))))))


(defun times-decrypt-key (msg)
  (map 'vector (lambda (x) (* 811589153 x)) msg))

(fiveam:test solutions
  (fiveam:is (= 3 (solver 1 *msg*)))
  (fiveam:is (= 1623178306 (solver 10 (times-decrypt-key *msg*))))
  (let ((input-msg (map 'vector #'parse-integer (uiop:read-file-lines "input"))))
    (fiveam:is (= 7225 (solver 1 input-msg)))
    (fiveam:is (= 548634267428 (solver 10 (times-decrypt-key input-msg))))))