advent-of-code/2019/22/src/main.rs

127 lines
4.0 KiB
Rust
Raw Normal View History

2020-01-02 16:05:45 +01:00
use std::collections::HashSet;
2019-12-27 16:35:28 +01:00
use std::io::{self, BufRead};
2020-01-02 16:05:45 +01:00
mod tests;
2019-12-27 16:35:28 +01:00
2020-01-02 16:05:45 +01:00
#[derive(Clone, Copy)]
2019-12-28 13:18:24 +01:00
enum ShuffleOperation {
CutLeft(usize),
CutRight(usize),
DealWithIncrement(usize),
Reverse,
}
2020-01-02 16:05:45 +01:00
impl<'a> From<&'a str> for ShuffleOperation {
fn from(raw: &'a str) -> ShuffleOperation {
let words: Vec<_> = raw.split(' ').collect();
match words[0] {
"cut" => {
let offset: isize = words[1].parse().expect("Not a valid number for cutting");
if offset < 0 {
ShuffleOperation::CutRight(offset.abs() as usize)
} else {
ShuffleOperation::CutLeft(offset as usize)
}
2019-12-27 16:35:28 +01:00
}
2020-01-02 16:05:45 +01:00
"deal" => match words[1] {
// with increment
"with" => ShuffleOperation::DealWithIncrement(words[3].parse().unwrap()),
// into new stack
"into" => ShuffleOperation::Reverse,
_ => unreachable!("Unknown deal command"),
},
_ => unreachable!("Unknown shuffle command"),
2019-12-27 16:35:28 +01:00
}
2019-12-28 13:18:24 +01:00
}
}
2020-01-02 16:05:45 +01:00
fn apply(deck: &mut Vec<usize>, operation: ShuffleOperation) {
match operation {
2019-12-28 13:18:24 +01:00
ShuffleOperation::Reverse => deck.reverse(),
ShuffleOperation::CutLeft(offset) => {
let clone = deck.clone();
let (left, right) = clone.split_at(offset as usize);
*deck = right.to_vec();
deck.append(&mut left.to_vec());
}
ShuffleOperation::CutRight(offset) => {
let offset = deck.len() - offset;
let cut: Vec<_> = deck.drain(0..offset).collect();
cut.into_iter().for_each(|n| deck.push(n));
}
ShuffleOperation::DealWithIncrement(increment) => {
let length = deck.len();
let old_deck = deck.clone();
for i in 0..length {
deck[(i * increment) % length] = old_deck[i];
}
}
2019-12-27 16:35:28 +01:00
};
}
2020-01-02 16:05:45 +01:00
fn get_previous_index(current: usize, operation: ShuffleOperation, deck_size: usize) -> usize {
match operation {
2019-12-28 13:18:24 +01:00
ShuffleOperation::Reverse => deck_size - current - 1,
2020-01-02 16:05:45 +01:00
ShuffleOperation::CutLeft(offset) => (current + offset) % deck_size,
ShuffleOperation::CutRight(offset) => (current + deck_size - offset) % deck_size,
2019-12-28 13:18:24 +01:00
ShuffleOperation::DealWithIncrement(increment) => (0..)
.filter_map(|x| {
2020-01-02 16:05:45 +01:00
let old_position = x * deck_size + current;
if old_position % increment == 0 {
Some(old_position / increment)
2019-12-28 13:18:24 +01:00
} else {
None
}
})
.next()
.unwrap(),
}
}
2019-12-27 16:43:22 +01:00
fn create_deck(len: usize) -> Vec<usize> {
let mut deck = Vec::with_capacity(len);
(0..len).for_each(|n| deck.push(n));
deck
}
2019-12-28 13:18:24 +01:00
fn get_original_index(
initial: usize,
2020-01-02 16:05:45 +01:00
iterations: i128,
2019-12-28 13:18:24 +01:00
deck_size: usize,
2020-01-02 16:05:45 +01:00
operations: &[ShuffleOperation],
) -> i128 {
2019-12-28 13:18:24 +01:00
let mut last = initial;
for operation in operations.iter().rev() {
2020-01-02 16:05:45 +01:00
last = get_previous_index(last, *operation, deck_size);
}
let initial = initial as i128;
let deck_size = deck_size as i128;
let drift = last as i128 - initial;
dbg!(drift);
let new_index = initial + drift * iterations;
if new_index >= 0 {
new_index % deck_size
} else {
(new_index + deck_size * ((new_index.abs() / deck_size) + 1)) % deck_size
2019-12-28 13:18:24 +01:00
}
}
2019-12-27 16:35:28 +01:00
fn main() {
2020-01-02 16:05:45 +01:00
let input: Vec<ShuffleOperation> = io::stdin()
.lock()
.lines()
.map(|l| ShuffleOperation::from(l.unwrap().as_ref()))
.collect();
const DECK_SIZE: usize = 10007;
2019-12-27 16:43:22 +01:00
let mut deck = create_deck(DECK_SIZE);
2019-12-28 13:18:24 +01:00
for operation in &input {
2020-01-02 16:05:45 +01:00
apply(&mut deck, *operation);
2019-12-27 16:35:28 +01:00
}
2019-12-28 13:18:24 +01:00
println!("Part 1: {}", deck.iter().position(|&x| x == 2019).unwrap());
2020-01-02 16:05:45 +01:00
const P2_DECK_SIZE: usize = 119315717514047;
const P2_ITERATIONS: i128 = 101_741_582_076_661;
const P2_INDEX: usize = 2020;
let mut last = P2_INDEX;
println!("Part 2: {}", last);
2019-12-27 16:35:28 +01:00
}