Day 22 part 2

This commit is contained in:
2022-10-08 17:05:14 +02:00
parent 0f9d48314e
commit 3c1a48fe51
4 changed files with 115 additions and 37 deletions

View File

@@ -3,5 +3,5 @@ extern crate core;
mod tasks;
fn main() {
tasks::day16::run();
tasks::day22::run();
}

View File

@@ -1,16 +1,20 @@
use modinverse::modinverse;
use std::collections::HashMap;
use std::collections::VecDeque;
use mod_exp::mod_exp;
use modinverse::modinverse;
use crate::tasks::day22::Cmd::{Cut, Deal, Stack};
pub fn run() {
let input = std::fs::read_to_string("input/day22.txt").unwrap();
println!("{}", task2(input, 119315717514047, 2020, 101741582076661));
println!("Task 1: {}", task1(&input));
println!("Task 2: {}", task2(&input));
}
type Deck = VecDeque<u16>;
type Size = i128;
fn task1(input: String) -> usize {
fn task1(input: &str) -> usize {
let deck_size = 10_007;
let mut deck: Deck = (0..deck_size).collect();
for line in input.lines() {
@@ -59,31 +63,50 @@ 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<String> = input.trim().lines().rev().map(|it| it.into()).collect();
let mut results: HashMap<Size, usize> = HashMap::new();
let mut result = field_after;
results.insert(result, 0);
#[derive(Clone, Copy)]
enum Cmd { Stack, Cut(i128), Deal(i128) }
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;
// I don't understand this solution but I copied it because I wanted the last star :> (c) AxlLind@github
fn task2(input: &String) -> Size {
const M: i128 = 119_315_717_514_047;
const N: i128 = 101_741_582_076_661;
let commands: Vec<_> = input.lines().map(|line| {
if line.starts_with("deal into new stack") {
Stack
} else if line.starts_with("cut") {
let s = line.split("cut ").collect::<Vec<_>>();
let n = s[1].parse::<i128>().unwrap();
Cut(n)
} else if line.starts_with("deal with increment") {
let s = line.split("deal with increment ").collect::<Vec<_>>();
let n = s[1].parse::<i128>().unwrap();
Deal(n)
} else {
results.insert(result, iteration);
panic!("'{line}' is illegal")
}
iteration += 1;
if iteration % 1000 == 0 {
println!("iteration {}", iteration);
}
}
}).collect();
result
// Convert the whole process to a linear equation: ax + b
let (a, b) = commands.iter().rev().fold((1, 0), |(a, b), &cmd| {
let (a_new, b_new) = match cmd {
Stack => (-a, -b - 1),
Cut(n) => (a, b + n),
Deal(n) => {
let n = mod_exp(n, M - 2, M);
(a * n, b * n)
}
};
(a_new % M, b_new % M)
});
// Applying the function n times simplifies to:
// x * a^n + b * (a^n - 1) / (a-1)
let term1 = 2020 * mod_exp(a, N, M) % M;
let tmp = (mod_exp(a, N, M) - 1) * mod_exp(a - 1, M - 2, M) % M;
let term2 = b * tmp % M;
(term1 + term2) % M
}
fn revert_iteration_find_start(shuffles: &Vec<String>, deck_size: Size, field_after: Size) -> Size {
@@ -123,15 +146,14 @@ mod test {
use crate::tasks::day22::task2;
#[test]
fn part1() {
let input = std::fs::read_to_string("input/day22.txt").unwrap();
assert_eq!(7545, task1(input));
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));
assert_eq!(2019, task2(&input));
}
}