diff --git a/src/22.rkt b/src/22.rkt index cb0b868..ff4e739 100644 --- a/src/22.rkt +++ b/src/22.rkt @@ -9,18 +9,27 @@ ;; A shuffle operation (technique) is ;; an affine transformation on a card's index. -;; Applying the transformation (m, o) to i yields (m*i + o). -;; We can compose transformations and only keep track -;; of the multiple and offset factors (modulo some len). ;; The identity transformation is I = (1, 0). +;; Applying the transformation (m, o) to i yields (m*i + o). (struct affine (multiple offset) #:transparent) +(define I (affine 1 0)) + (define (apply-affine len mo i) (match-let ([(affine m o) mo]) (% (+ (* m i) o) len))) -(define I (affine 1 0)) +;; We can compose transformations and only keep track +;; of the multiple and offset factors (modulo some len); +;; <> composes two transformations as if the second were +;; applied first and the first applied last, so +;; (m1 , o1) <> (m2, o2) = (m1 * m2, m1 * o2 + o1). +(define (<> len a1 a2) + (match-let ([(affine m1 o1) a1] + [(affine m2 o2) a2]) + (affine (% (* m1 m2) len) + (% (+ (* m1 o2) o1) len)))) ;; Applying the transformation (m, o) n times is the same as ;; applying the transformation (m^n + o*(m^n - 1)/(m - 1)), @@ -31,6 +40,13 @@ [o* (% (* o (sub1 m^n) (modular-inverse (sub1 m) len)) len)]) (affine m^n o*))) +;; Inverting the transformation (m, o) is the same as +;; the transformation (m^-1, -o*m^-1) +(define (affine-invert mo len) + (match-let* ([(affine m o) mo] + [m^-1 (modular-inverse m len)]) + (affine m^-1 (* -1 o m^-1)))) + ;; All shuffling transformation techniques are modulo the number of cards. ;; deal into new stack: reversing the order of the cards, ;; corresponding to the transformation i → -1*i + (length - 1) @@ -39,56 +55,30 @@ ;; deal with increment N: placing a card every n steps, ;; corresponding to the transformation i → n*i -(define (DINS len mo) - (match-let ([(affine m o) mo]) - (affine (% (* m -1) len) - (% (- (sub1 len) o) len)))) +(define (DINS len) + (affine -1 (sub1 len))) -(define (CNC len n mo) - (match-let ([(affine m o) mo]) - (affine m (% (- o n) len)))) +(define (CNC len n) + (affine 1 (* n -1))) -(define (DWIN len n mo) - (match-let ([(affine m o) mo]) - (affine (% (* m n) len) - (% (* o n) len)))) - -;; The corresponding inverse transformations are: -;; DINS: -1*i + (length - 1) ← i -;; CNC: i + n ← i -;; DWIN: n^-1*i ← i -;; where ·^-1 is the modular multiplicative inverse - -(define (inverse-DINS len mo) - (DINS len mo)) - -(define (inverse-CNC len n mo) - (CNC len (* n -1) mo)) - -(define (inverse-DWIN len n mo) - (DWIN len (modular-inverse n len) mo)) +(define (DWIN len n) + (affine n 0)) ;; Shuffling combines all transformations in order. -;; Inverse shuffling combines all inverse transformations in reverse order. +;; Inverse shuffling is simply the inverse transformation. ;; We begin with the identity transformation, I = (1, 0). -(define (parse len T mo) +(define (parse len T) (match T - ["deal into new stack" (DINS len mo)] - [(string-append "cut " s) (CNC len (string->number s) mo)] - [(string-append "deal with increment " s) (DWIN len (string->number s) mo)])) - -(define (inverse-parse len T mo) - (match T - ["deal into new stack" (inverse-DINS len mo)] - [(string-append "cut " s) (inverse-CNC len (string->number s) mo)] - [(string-append "deal with increment " s) (inverse-DWIN len (string->number s) mo)])) + ["deal into new stack" (DINS len)] + [(string-append "cut " s) (CNC len (string->number s))] + [(string-append "deal with increment " s) (DWIN len (string->number s))])) (define (shuffle len) - (foldl (∂ parse len) I input)) + (foldl (λ (T mo) (<> len (parse len T) mo)) I input)) (define (inverse-shuffle len) - (foldr (∂ inverse-parse len) I input)) + (affine-invert (shuffle len) len)) (define part1 (let ([len 10007]) diff --git a/src/23.rkt b/src/23.rkt index 9a8d25c..a219ba5 100644 --- a/src/23.rkt +++ b/src/23.rkt @@ -9,7 +9,7 @@ (string->program (car (problem-input 23)))) (define network - (build-vector 50 (λ (n) (resume-with-input (exec input) n)))) + (build-vector 50 (λ (n) (resume-with-input (resume-with-input (exec input) n) -1)))) (define packets (build-vector 50 (λ (_) (make-queue)))) @@ -32,7 +32,7 @@ (type-case state st [in (resume) (if (queue-empty? input) - (vector-set! network i (resume -1)) + (void) (let* ([x (dequeue! input)] [y (dequeue! input)] [st (resume-with-input (resume x) y)])