From 656ca6e0b7c77eb0650c4d441f7522e90c6b395c Mon Sep 17 00:00:00 2001 From: kageru Date: Thu, 2 Jan 2020 16:05:45 +0100 Subject: [PATCH] More D22 WIP --- 2019/22/notes | 1 + 2019/22/src/main.rs | 251 ++++++++++--------------------------------- 2019/22/src/tests.rs | 201 ++++++++++++++++++++++++++++++++++ 3 files changed, 260 insertions(+), 193 deletions(-) create mode 100644 2019/22/notes create mode 100644 2019/22/src/tests.rs diff --git a/2019/22/notes b/2019/22/notes new file mode 100644 index 0000000..f1c1302 --- /dev/null +++ b/2019/22/notes @@ -0,0 +1 @@ +43719219567200 too low diff --git a/2019/22/src/main.rs b/2019/22/src/main.rs index d6cc81a..9a577cf 100644 --- a/2019/22/src/main.rs +++ b/2019/22/src/main.rs @@ -1,5 +1,8 @@ +use std::collections::HashSet; use std::io::{self, BufRead}; +mod tests; +#[derive(Clone, Copy)] enum ShuffleOperation { CutLeft(usize), CutRight(usize), @@ -7,30 +10,32 @@ enum ShuffleOperation { Reverse, } -fn parse_operation(operation: &str) -> ShuffleOperation { - let words: Vec<_> = operation.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) +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) + } } + "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"), } - "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"), } } -fn apply(deck: &mut Vec, operation: &str) { - match parse_operation(operation) { +fn apply(deck: &mut Vec, operation: ShuffleOperation) { + match operation { ShuffleOperation::Reverse => deck.reverse(), ShuffleOperation::CutLeft(offset) => { let clone = deck.clone(); @@ -53,27 +58,16 @@ fn apply(deck: &mut Vec, operation: &str) { }; } -fn get_previous_index(current: usize, operation: &str, deck_size: usize) -> usize { - match parse_operation(operation) { +fn get_previous_index(current: usize, operation: ShuffleOperation, deck_size: usize) -> usize { + match operation { ShuffleOperation::Reverse => deck_size - current - 1, - ShuffleOperation::CutLeft(offset) => { - if current >= deck_size - offset { - current - (deck_size - offset) - } else { - current + offset - } - } - ShuffleOperation::CutRight(offset) => { - if current < offset { - deck_size - offset + current - } else { - current - offset - } - } + ShuffleOperation::CutLeft(offset) => (current + offset) % deck_size, + ShuffleOperation::CutRight(offset) => (current + deck_size - offset) % deck_size, ShuffleOperation::DealWithIncrement(increment) => (0..) .filter_map(|x| { - if (x * deck_size + current) % increment == 0 { - Some((x * deck_size + current) / increment) + let old_position = x * deck_size + current; + if old_position % increment == 0 { + Some(old_position / increment) } else { None } @@ -91,171 +85,42 @@ fn create_deck(len: usize) -> Vec { fn get_original_index( initial: usize, - iterations: u128, + iterations: i128, deck_size: usize, - operations: &[String], -) -> u128 { + operations: &[ShuffleOperation], +) -> i128 { let mut last = initial; for operation in operations.iter().rev() { - last = get_previous_index(last, operation, deck_size); + 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 } - let drift = (last - initial) as u128; - (P2_INDEX as u128 + drift * iterations) % deck_size as u128 } -const DECK_SIZE: usize = 10007; -const P2_DECK_SIZE: usize = 119315717514047; -const P2_ITERATIONS: u128 = 101741582076661; -const P2_INDEX: usize = 2020; - fn main() { - let input: Vec<_> = io::stdin().lock().lines().map(|l| l.unwrap()).collect(); + let input: Vec = io::stdin() + .lock() + .lines() + .map(|l| ShuffleOperation::from(l.unwrap().as_ref())) + .collect(); + const DECK_SIZE: usize = 10007; let mut deck = create_deck(DECK_SIZE); for operation in &input { - apply(&mut deck, operation); + apply(&mut deck, *operation); } println!("Part 1: {}", deck.iter().position(|&x| x == 2019).unwrap()); - let p2 = get_original_index(P2_INDEX, P2_ITERATIONS, P2_DECK_SIZE, &input); - println!("Part 2: {}", p2); -} - -mod tests { - use super::*; - - const EXAMPLE_1: &str = "deal with increment 7 -deal into new stack -deal into new stack"; - const EXAMPLE_2: &str = "cut 6 -deal with increment 7 -deal into new stack"; - const EXAMPLE_3: &str = "deal with increment 7 -deal with increment 9 -cut -2"; - const EXAMPLE_4: &str = "deal into new stack -cut -2 -deal with increment 7 -cut 8 -cut -4 -deal with increment 7 -cut 3 -deal with increment 9 -deal with increment 3 -cut -1"; - /// Example 4 but with an even number of reversals - const EXAMPLE_5: &str = "deal into new stack -cut -2 -deal with increment 7 -cut 8 -cut -4 -deal with increment 7 -cut 3 -deal into new stack -deal with increment 9 -deal with increment 3 -cut -1"; - - #[test] - fn deal_test() { - let mut deck = create_deck(10); - for line in EXAMPLE_1.lines() { - apply(&mut deck, line); - } - assert_eq!(deck, &[0, 3, 6, 9, 2, 5, 8, 1, 4, 7]); - } - - #[test] - fn cut_deal_test() { - let mut deck = create_deck(10); - for line in EXAMPLE_2.lines() { - apply(&mut deck, line); - } - assert_eq!(deck, &[3, 0, 7, 4, 1, 8, 5, 2, 9, 6]); - } - - #[test] - fn test_all() { - let mut deck = create_deck(10); - for line in EXAMPLE_4.lines() { - apply(&mut deck, line); - } - assert_eq!(deck, &[9, 2, 5, 8, 1, 4, 7, 0, 3, 6]); - } - - // tests for part 2 - #[test] - fn reverse_stack_deal_test() { - assert_eq!( - reverse_step("deal into new stack", 10), - [9, 8, 7, 6, 5, 4, 3, 2, 1, 0] - ); - } - - #[test] - fn reverse_cut_test() { - assert_eq!(reverse_step("cut 3", 10), [3, 4, 5, 6, 7, 8, 9, 0, 1, 2]); - assert_eq!(reverse_step("cut -4", 10), [6, 7, 8, 9, 0, 1, 2, 3, 4, 5]); - } - - #[test] - fn reverse_increment_test() { - assert_eq!( - reverse_step("deal with increment 3", 10), - [0, 7, 4, 1, 8, 5, 2, 9, 6, 3] - ); - } - - #[test] - fn full_reverse_test1() { - assert_eq!(index_before_instructions(0, EXAMPLE_1), 0); - assert_eq!(index_before_instructions(2, EXAMPLE_1), 6); - } - - #[test] - fn full_reverse_test2() { - assert_eq!(index_before_instructions(0, EXAMPLE_2), 3); - assert_eq!(index_before_instructions(6, EXAMPLE_2), 5); - } - - #[test] - fn full_reverse_test3() { - assert_eq!(index_before_instructions(0, EXAMPLE_3), 6); - assert_eq!(index_before_instructions(9, EXAMPLE_3), 9); - } - - #[test] - fn test_twice() { - let mut deck = create_deck(10); - for line in EXAMPLE_5.lines() { - apply(&mut deck, line); - } - for line in EXAMPLE_5.lines() { - apply(&mut deck, line); - } - assert_eq!(deck, &[2, 1, 0, 9, 8, 7, 6, 5, 4, 3]); - } - - #[test] - fn interpolate_drift_test() { - //get_original_index(0, 1, 10, EXAMPLE_4); - } - - #[test] - fn full_reverse_test4() { - let instructions = EXAMPLE_4; - assert_eq!(index_before_instructions(1, instructions), 2); - } - - fn index_before_instructions(mut last: usize, instructions: &str) -> usize { - for line in instructions.lines().rev() { - last = get_previous_index(last, line, 10); - } - last - } - - fn reverse_step(instruction: &str, len: usize) -> Vec { - (0..len) - .into_iter() - .map(|n| get_previous_index(n, instruction, 10)) - .collect() - } + + 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); } diff --git a/2019/22/src/tests.rs b/2019/22/src/tests.rs new file mode 100644 index 0000000..130b423 --- /dev/null +++ b/2019/22/src/tests.rs @@ -0,0 +1,201 @@ +use super::*; + +const EXAMPLE_1: &str = "deal with increment 7 +deal into new stack +deal into new stack"; +const EXAMPLE_2: &str = "cut 6 +deal with increment 7 +deal into new stack"; +const EXAMPLE_3: &str = "deal with increment 7 +deal with increment 9 +cut -2"; +const EXAMPLE_4: &str = "deal into new stack +cut -2 +deal with increment 7 +cut 8 +cut -4 +deal with increment 7 +cut 3 +deal with increment 9 +deal with increment 3 +cut -1"; +/// Example 4 but with an even number of reversals +const EXAMPLE_5: &str = "deal into new stack +cut -2 +deal with increment 7 +cut 8 +cut -4 +deal with increment 7 +cut 3 +deal into new stack +deal with increment 9 +deal with increment 3 +cut -1"; + +#[test] +fn deal_test() { + let mut deck = create_deck(10); + for line in EXAMPLE_1.lines().map(|l| l.into()) { + apply(&mut deck, line); + } + assert_eq!(deck, &[0, 3, 6, 9, 2, 5, 8, 1, 4, 7]); +} + +#[test] +fn cut_deal_test() { + let mut deck = create_deck(10); + for line in EXAMPLE_2.lines().map(|l| l.into()) { + apply(&mut deck, line); + } + assert_eq!(deck, &[3, 0, 7, 4, 1, 8, 5, 2, 9, 6]); +} + +#[test] +fn test_all() { + let mut deck = create_deck(10); + for line in EXAMPLE_4.lines().map(|l| l.into()) { + apply(&mut deck, line); + } + assert_eq!(deck, &[9, 2, 5, 8, 1, 4, 7, 0, 3, 6]); +} + +// tests for part 2 +#[test] +fn reverse_stack_deal_test() { + assert_eq!( + reverse_step("deal into new stack", 10), + [9, 8, 7, 6, 5, 4, 3, 2, 1, 0] + ); +} + +#[test] +fn reverse_cut_test() { + assert_eq!(reverse_step("cut 3", 10), [3, 4, 5, 6, 7, 8, 9, 0, 1, 2]); + assert_eq!(reverse_step("cut -4", 10), [6, 7, 8, 9, 0, 1, 2, 3, 4, 5]); +} + +#[test] +fn reverse_increment_test() { + assert_eq!( + reverse_step("deal with increment 3", 10), + [0, 7, 4, 1, 8, 5, 2, 9, 6, 3] + ); +} + +#[test] +fn full_reverse_test1() { + assert_eq!(index_before_instructions(0, EXAMPLE_1), 0); + assert_eq!(index_before_instructions(2, EXAMPLE_1), 6); +} + +#[test] +fn full_reverse_test2() { + assert_eq!(index_before_instructions(0, EXAMPLE_2), 3); + assert_eq!(index_before_instructions(6, EXAMPLE_2), 5); +} + +#[test] +fn full_reverse_test3() { + assert_eq!(index_before_instructions(0, EXAMPLE_3), 6); + assert_eq!(index_before_instructions(9, EXAMPLE_3), 9); +} + +#[test] +fn test_twice() { + let mut deck = create_deck(10); + for line in EXAMPLE_5.lines().map(|l| l.into()) { + apply(&mut deck, line); + } + for line in EXAMPLE_5.lines().map(|l| l.into()) { + apply(&mut deck, line); + } + assert_eq!(deck, &[2, 1, 0, 9, 8, 7, 6, 5, 4, 3]); +} + +#[test] +fn get_original_index_test() { + let instructions = EXAMPLE_1; + let mut deck = create_deck(10); + for line in instructions.lines().map(|l| l.into()) { + apply(&mut deck, line); + } + assert_eq!(deck, &[0, 3, 6, 9, 2, 5, 8, 1, 4, 7]); + assert_eq!( + deck, + (0..10) + .map(|n| index_before_instructions(n, instructions)) + .collect::>() + ); + assert_eq!( + deck, + (0..10) + .map(|n| get_original_index( + n, + 1, + 10, + &instructions + .lines() + .map(|l| l.into()) + .collect::>() + ) as usize) + .collect::>() + ); + + assert_eq!( + (0..10) + .map(|n| index_before_instructions(n, EXAMPLE_4)) + .collect::>(), + (0..10) + .map(|n| get_original_index( + n, + 1, + 10, + &EXAMPLE_4.lines().map(|l| l.into()).collect::>() + ) as usize) + .collect::>() + ); +} + +#[test] +fn interpolate_drift_test() { + const INSTRUCTIONS: &str = EXAMPLE_5; + const ITERATIONS: usize = 4; + let mut deck = create_deck(10); + for _ in 0..ITERATIONS { + for line in INSTRUCTIONS.lines().map(|l| l.into()) { + apply(&mut deck, line); + } + } + assert_eq!( + deck, + (0..10) + .map(|n| get_original_index( + n, + ITERATIONS as i128, + 10, + &INSTRUCTIONS + .lines() + .map(|l| l.into()) + .collect::>() + ) as usize) + .collect::>() + ); +} + +#[test] +fn full_reverse_test4() { + assert_eq!(index_before_instructions(1, EXAMPLE_4), 2); +} + +fn index_before_instructions(mut last: usize, instructions: &str) -> usize { + for line in instructions.lines().rev().map(|l| l.into()) { + last = get_previous_index(last, line, 10); + } + last +} + +fn reverse_step(instruction: &str, len: usize) -> Vec { + (0..len) + .map(|n| get_previous_index(n, instruction.into(), 10)) + .collect() +}