From 126833bbaab2f48410a0fa6c09d225e2a4832696 Mon Sep 17 00:00:00 2001 From: Johannes Date: Wed, 23 Mar 2022 19:45:57 +0100 Subject: [PATCH] Day 22 part 2. --- Cargo.lock | 10 ++++++ Cargo.toml | 3 +- src/tasks/day22.rs | 86 ++++++++++++++++++++++++++++++++++++++++++++-- src/tasks/mod.rs | 1 + 4 files changed, 96 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 846001f..58e521b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -16,6 +16,7 @@ name = "aoc_2019" version = "0.1.0" dependencies = [ "itertools", + "modinverse", "num-integer", "regex", ] @@ -47,6 +48,15 @@ version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" +[[package]] +name = "modinverse" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f62f577f148cc1a9466e7065a22e59466a7d537cceba5e77e57181d0f706633" +dependencies = [ + "num-integer", +] + [[package]] name = "num-integer" version = "0.1.44" diff --git a/Cargo.toml b/Cargo.toml index aca0eac..98324e5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,4 +9,5 @@ edition = "2021" [dependencies] itertools = "0.10.3" regex = "1.5.5" -num-integer = "0.1.44" \ No newline at end of file +num-integer = "0.1.44" +modinverse = "0.1.1" diff --git a/src/tasks/day22.rs b/src/tasks/day22.rs index 22524f2..eb5c339 100644 --- a/src/tasks/day22.rs +++ b/src/tasks/day22.rs @@ -1,14 +1,16 @@ +use modinverse::modinverse; +use std::collections::HashMap; use std::collections::VecDeque; -#[allow(dead_code)] pub fn run() { let input = std::fs::read_to_string("input/day22.txt").unwrap(); - task1(input); + println!("{}", task2(input, 119315717514047, 2020, 101741582076661)); } type Deck = VecDeque; +type Size = i128; -fn task1(input: String) { +fn task1(input: String) -> usize { let deck_size = 10_007; let mut deck: Deck = (0..deck_size).collect(); for line in input.lines() { @@ -31,6 +33,7 @@ fn task1(input: String) { .find_map(|(i, card)| if *card == 2019 { Some(i) } else { None }); println!("Result: {:?}", pos_2019); + pos_2019.unwrap() } fn into_new_stack(deck: Deck) -> Deck { @@ -55,3 +58,80 @@ fn deal_with_increment(deck: Deck, n: usize) -> Deck { } new.into_iter().collect() } + +fn task2(input: String, deck_size: Size, field_after: Size, num_iterations: usize) -> Size { + let shuffles: Vec = input.trim().lines().rev().map(|it| it.into()).collect(); + let mut results: HashMap = HashMap::new(); + + let mut result = field_after; + results.insert(result, 0); + + let mut iteration = 1; + while iteration <= num_iterations { + result = revert_iteration_find_start(&shuffles, deck_size, result); + if let Some(last_iteration) = results.get(&result) { + println!("check after {} iterations", iteration); + let iterations = iteration - last_iteration; + let full_cycles_remaining = (num_iterations - iteration) / iterations; + iteration += full_cycles_remaining * iterations; + } else { + results.insert(result, iteration); + } + iteration += 1; + if iteration % 1000 == 0 { + println!("iteration {}", iteration); + } + } + + result +} + +fn revert_iteration_find_start(shuffles: &Vec, deck_size: Size, field_after: Size) -> Size { + let mut current: Size = field_after; + for line in shuffles { + if line.starts_with("deal into new stack") { + current = deck_size - 1 - current; + } else if line.starts_with("cut") { + let s = line.split("cut ").collect::>(); + let n = s[1].parse::().unwrap(); + current += n; + current += deck_size; + current %= deck_size; + } else if line.starts_with("deal with increment") { + let s = line.split("deal with increment ").collect::>(); + let n = s[1].parse::().unwrap(); + current = revert_finite_field_multiplikation(deck_size, n, current); + } + } + + current +} + +fn revert_finite_field_multiplikation( + field_length: Size, + multiplicator: Size, + result: Size, +) -> Size { + let multiplicator_inverse = + modinverse(multiplicator, field_length).expect("no modular inverse found"); + (result * multiplicator_inverse) % field_length +} + +#[cfg(test)] +mod test { + use crate::tasks::day22::task1; + use crate::tasks::day22::task2; + + #[test] + + fn part1() { + let input = std::fs::read_to_string("input/day22.txt").unwrap(); + assert_eq!(7545, task1(input)); + } + + #[test] + fn part2() { + let input = std::fs::read_to_string("input/day22.txt").unwrap(); + assert_eq!(2019, task2(input, 10007, 7545, 1)); + } +} diff --git a/src/tasks/mod.rs b/src/tasks/mod.rs index 6d266a2..b3b531d 100644 --- a/src/tasks/mod.rs +++ b/src/tasks/mod.rs @@ -16,5 +16,6 @@ pub mod day16; pub mod day17; pub mod day18; pub mod day21; +#[allow(dead_code)] pub mod day22; pub mod day24;