Watch
1
0
Fork
You've already forked advent-of-code
0

2022 Day 20 Part 2

This commit is contained in:
Jeremy Kaplan 2022-12-20 21:01:40 -08:00
commit 5a69105ec3

View file

@ -5,82 +5,105 @@ const INPUT: &str = include_str!("../../input/day20.txt");
fn main() { fn main() {
let ciphertext = parse(INPUT); let ciphertext = parse(INPUT);
let mixed = mix(ciphertext); println!("Part 1: {}", part1(ciphertext.clone()));
println!("{}", grove_hash(mixed)); println!("Part 2: {}", part2(ciphertext));
} }
fn parse(input: &str) -> Vec<i32> { fn parse(input: &str) -> Vec<i64> {
aoc::lines(input).map(|s| s.parse().unwrap()).collect() aoc::lines(input).map(|s| s.parse().unwrap()).collect()
} }
fn mix(ciphertext: Vec<i32>) -> Vec<i32> { fn part1(ciphertext: Vec<i64>) -> i64 {
let mixed = mix(ciphertext, 1);
grove_hash(mixed)
}
fn part2(ciphertext: Vec<i64>) -> i64 {
let decryption_key: i64 = 811589153;
let keyed: Vec<i64> = ciphertext.iter().map(|&n| n * decryption_key).collect();
let mixed = mix(keyed, 10);
grove_hash(mixed)
}
fn mix(ciphertext: Vec<i64>, times: usize) -> Vec<i64> {
let mut decrypter = Decrypter::new(&ciphertext); let mut decrypter = Decrypter::new(&ciphertext);
for (i, &n) in ciphertext.iter().enumerate() { for _ in 0..times {
decrypter.mv(i, n); for (i, &n) in ciphertext.iter().enumerate() {
decrypter.mv(i, n);
}
} }
decrypter.read() decrypter.read()
} }
fn grove_hash(msg: Vec<i32>) -> i32 { fn grove_hash(msg: Vec<i64>) -> i64 {
let zero = msg.iter().position(|&n| n == 0).unwrap(); 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) get(1_000) + get(2_000) + get(3_000)
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
struct Decrypter { struct Decrypter {
message: Vec<i32>, message: Vec<i64>,
len: usize,
ptr: VecDeque<usize>, ptr: VecDeque<usize>,
len: usize,
ilen: i64,
} }
impl Decrypter { impl Decrypter {
fn new(ciphertext: &Vec<i32>) -> Self { fn new(ciphertext: &Vec<i64>) -> Self {
let len = ciphertext.len();
Self { Self {
message: ciphertext.clone(), message: ciphertext.clone(),
ptr: (0..ciphertext.len()).collect(), ptr: (0..len).collect(),
len: ciphertext.len(), len,
ilen: len.try_into().unwrap(),
} }
} }
fn read(&self) -> Vec<i32> { fn read(&self) -> Vec<i64> {
self.ptr.iter().map(|&p| self.message[p]).collect() self.ptr.iter().map(|&p| self.message[p]).collect()
} }
fn mv(&mut self, i: usize, n: i32) { fn mv(&mut self, i: usize, n: i64) {
let mut p = self.ptr.iter().position(|&p| p == i).unwrap(); let p = self.ptr.iter().position(|&p| p == i).unwrap();
if n >= 0 { if n >= 0 {
for _ in 1..=n { // [a, b, c, i, x, y, z]
let q = (p + 1) % self.len; self.ptr.rotate_left(p);
self.ptr.swap(p, q); // [i, x, y, z, a, b, c]
if q == 0 { let m = self.ptr.pop_front().unwrap();
// Swapped off the end, fix. // i | [x, y, z, a, b, c]
let extra = self.ptr.pop_back().unwrap(); assert_eq!(i, m);
self.ptr.push_front(extra);
p = 1; let n = delta(n, self.ilen);
} else { self.ptr.rotate_left(n);
p = q; self.ptr.push_front(m);
}
}
} else { } else {
for _ in 1..=(-n) { // [a, b, c, i, x, y, z]
let q = (p + self.len - 1) % self.len; self.ptr.rotate_right(self.len - p - 1);
self.ptr.swap(p, q); // [x, y, z, a, b, c, i]
if q == 0 { let m = self.ptr.pop_back().unwrap();
// Swapped off the end, fix. // [x, y, z, a, b, c] | i
let extra = self.ptr.pop_front().unwrap(); assert_eq!(i, m);
self.ptr.push_back(extra);
p = self.len - 1; let n = delta(n, self.ilen);
} else { self.ptr.rotate_right(n);
p = q 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()
}