2022 Day 20 Part 2
This commit is contained in:
parent
1e6ca99e1e
commit
5a69105ec3
1 changed files with 66 additions and 43 deletions
|
|
@ -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()
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue