From 5a69105ec312efa0f266c050f87db2604e8ea2de Mon Sep 17 00:00:00 2001 From: Jeremy Kaplan Date: Tue, 20 Dec 2022 21:01:40 -0800 Subject: [PATCH] 2022 Day 20 Part 2 --- 2022/src/bin/day20.rs | 105 +++++++++++++++++++++++++----------------- 1 file changed, 64 insertions(+), 41 deletions(-) diff --git a/2022/src/bin/day20.rs b/2022/src/bin/day20.rs index c2fb39c..d8327a4 100644 --- a/2022/src/bin/day20.rs +++ b/2022/src/bin/day20.rs @@ -5,82 +5,105 @@ const INPUT: &str = include_str!("../../input/day20.txt"); fn main() { let ciphertext = parse(INPUT); - let mixed = mix(ciphertext); - println!("{}", grove_hash(mixed)); + println!("Part 1: {}", part1(ciphertext.clone())); + println!("Part 2: {}", part2(ciphertext)); } -fn parse(input: &str) -> Vec { +fn parse(input: &str) -> Vec { aoc::lines(input).map(|s| s.parse().unwrap()).collect() } -fn mix(ciphertext: Vec) -> Vec { +fn part1(ciphertext: Vec) -> i64 { + let mixed = mix(ciphertext, 1); + grove_hash(mixed) +} + +fn part2(ciphertext: Vec) -> i64 { + let decryption_key: i64 = 811589153; + let keyed: Vec = ciphertext.iter().map(|&n| n * decryption_key).collect(); + + let mixed = mix(keyed, 10); + grove_hash(mixed) +} + +fn mix(ciphertext: Vec, times: usize) -> Vec { let mut decrypter = Decrypter::new(&ciphertext); - for (i, &n) in ciphertext.iter().enumerate() { - decrypter.mv(i, n); + for _ in 0..times { + for (i, &n) in ciphertext.iter().enumerate() { + decrypter.mv(i, n); + } } decrypter.read() } -fn grove_hash(msg: Vec) -> i32 { +fn grove_hash(msg: Vec) -> i64 { let zero = msg.iter().position(|&n| n == 0).unwrap(); - let get = |i: usize| -> i32 { msg[(i + zero) % msg.len()] }; + let get = |i: usize| -> i64 { msg[(i + zero) % msg.len()] }; get(1_000) + get(2_000) + get(3_000) } #[derive(Debug, Clone)] struct Decrypter { - message: Vec, - len: usize, - + message: Vec, ptr: VecDeque, + len: usize, + ilen: i64, } impl Decrypter { - fn new(ciphertext: &Vec) -> Self { + fn new(ciphertext: &Vec) -> Self { + let len = ciphertext.len(); Self { message: ciphertext.clone(), - ptr: (0..ciphertext.len()).collect(), - len: ciphertext.len(), + ptr: (0..len).collect(), + len, + ilen: len.try_into().unwrap(), } } - fn read(&self) -> Vec { + fn read(&self) -> Vec { self.ptr.iter().map(|&p| self.message[p]).collect() } - fn mv(&mut self, i: usize, n: i32) { - let mut p = self.ptr.iter().position(|&p| p == i).unwrap(); + fn mv(&mut self, i: usize, n: i64) { + let p = self.ptr.iter().position(|&p| p == i).unwrap(); + if n >= 0 { - for _ in 1..=n { - let q = (p + 1) % self.len; - self.ptr.swap(p, q); + // [a, b, c, i, x, y, z] + self.ptr.rotate_left(p); + // [i, x, y, z, a, b, c] - if q == 0 { - // Swapped off the end, fix. - let extra = self.ptr.pop_back().unwrap(); - self.ptr.push_front(extra); - p = 1; - } else { - p = q; - } - } + let m = self.ptr.pop_front().unwrap(); + // i | [x, y, z, a, b, c] + assert_eq!(i, m); + + let n = delta(n, self.ilen); + self.ptr.rotate_left(n); + self.ptr.push_front(m); } else { - for _ in 1..=(-n) { - let q = (p + self.len - 1) % self.len; - self.ptr.swap(p, q); + // [a, b, c, i, x, y, z] + self.ptr.rotate_right(self.len - p - 1); + // [x, y, z, a, b, c, i] - if q == 0 { - // Swapped off the end, fix. - let extra = self.ptr.pop_front().unwrap(); - self.ptr.push_back(extra); - p = self.len - 1; - } else { - p = q - } - } + let m = self.ptr.pop_back().unwrap(); + // [x, y, z, a, b, c] | i + assert_eq!(i, m); + + let n = delta(n, self.ilen); + self.ptr.rotate_right(n); + self.ptr.push_back(m); } } } + +fn delta(n: i64, len: i64) -> usize { + let n = n.abs(); + // It takes n-1 swaps to get back to where we started, so treat these as extra "hops" over the + // original position. + let skips = n / (len - 1); + let extra = n % len; + ((skips + extra) % len).try_into().unwrap() +}