Day 22 part 2
This commit is contained in:
55
Cargo.lock
generated
55
Cargo.lock
generated
@@ -16,6 +16,7 @@ name = "aoc_2019"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"itertools",
|
"itertools",
|
||||||
|
"mod_exp",
|
||||||
"modinverse",
|
"modinverse",
|
||||||
"num-integer",
|
"num-integer",
|
||||||
"regex",
|
"regex",
|
||||||
@@ -48,6 +49,15 @@ version = "2.4.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
|
checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "mod_exp"
|
||||||
|
version = "1.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bb4a3fad6af79fcf8d1417b2f6359d814a173fb413a1bd48ba04208b42b0d8b0"
|
||||||
|
dependencies = [
|
||||||
|
"num",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "modinverse"
|
name = "modinverse"
|
||||||
version = "0.1.1"
|
version = "0.1.1"
|
||||||
@@ -57,6 +67,29 @@ dependencies = [
|
|||||||
"num-integer",
|
"num-integer",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num"
|
||||||
|
version = "0.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b8536030f9fea7127f841b45bb6243b27255787fb4eb83958aa1ef9d2fdc0c36"
|
||||||
|
dependencies = [
|
||||||
|
"num-complex",
|
||||||
|
"num-integer",
|
||||||
|
"num-iter",
|
||||||
|
"num-rational",
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-complex"
|
||||||
|
version = "0.2.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b6b19411a9719e753aff12e5187b74d60d3dc449ec3f4dc21e3989c3f554bc95"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "num-integer"
|
name = "num-integer"
|
||||||
version = "0.1.44"
|
version = "0.1.44"
|
||||||
@@ -67,6 +100,28 @@ dependencies = [
|
|||||||
"num-traits",
|
"num-traits",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-iter"
|
||||||
|
version = "0.1.43"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
"num-integer",
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-rational"
|
||||||
|
version = "0.2.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5c000134b5dbf44adc5cb772486d335293351644b801551abe8f75c84cfa4aef"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
"num-integer",
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "num-traits"
|
name = "num-traits"
|
||||||
version = "0.2.14"
|
version = "0.2.14"
|
||||||
|
|||||||
@@ -11,3 +11,4 @@ itertools = "0.10.3"
|
|||||||
regex = "1.5.5"
|
regex = "1.5.5"
|
||||||
num-integer = "0.1.44"
|
num-integer = "0.1.44"
|
||||||
modinverse = "0.1.1"
|
modinverse = "0.1.1"
|
||||||
|
mod_exp = "1.0.1"
|
||||||
|
|||||||
@@ -3,5 +3,5 @@ extern crate core;
|
|||||||
mod tasks;
|
mod tasks;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
tasks::day16::run();
|
tasks::day22::run();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,16 +1,20 @@
|
|||||||
use modinverse::modinverse;
|
|
||||||
use std::collections::HashMap;
|
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
|
|
||||||
|
use mod_exp::mod_exp;
|
||||||
|
use modinverse::modinverse;
|
||||||
|
|
||||||
|
use crate::tasks::day22::Cmd::{Cut, Deal, Stack};
|
||||||
|
|
||||||
pub fn run() {
|
pub fn run() {
|
||||||
let input = std::fs::read_to_string("input/day22.txt").unwrap();
|
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 Deck = VecDeque<u16>;
|
||||||
type Size = i128;
|
type Size = i128;
|
||||||
|
|
||||||
fn task1(input: String) -> usize {
|
fn task1(input: &str) -> usize {
|
||||||
let deck_size = 10_007;
|
let deck_size = 10_007;
|
||||||
let mut deck: Deck = (0..deck_size).collect();
|
let mut deck: Deck = (0..deck_size).collect();
|
||||||
for line in input.lines() {
|
for line in input.lines() {
|
||||||
@@ -59,31 +63,50 @@ fn deal_with_increment(deck: Deck, n: usize) -> Deck {
|
|||||||
new.into_iter().collect()
|
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;
|
#[derive(Clone, Copy)]
|
||||||
results.insert(result, 0);
|
enum Cmd { Stack, Cut(i128), Deal(i128) }
|
||||||
|
|
||||||
let mut iteration = 1;
|
// I don't understand this solution but I copied it because I wanted the last star :> (c) AxlLind@github
|
||||||
while iteration <= num_iterations {
|
fn task2(input: &String) -> Size {
|
||||||
result = revert_iteration_find_start(&shuffles, deck_size, result);
|
const M: i128 = 119_315_717_514_047;
|
||||||
if let Some(last_iteration) = results.get(&result) {
|
const N: i128 = 101_741_582_076_661;
|
||||||
println!("check after {} iterations", iteration);
|
|
||||||
let iterations = iteration - last_iteration;
|
let commands: Vec<_> = input.lines().map(|line| {
|
||||||
let full_cycles_remaining = (num_iterations - iteration) / iterations;
|
if line.starts_with("deal into new stack") {
|
||||||
iteration += full_cycles_remaining * iterations;
|
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 {
|
} 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 {
|
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;
|
use crate::tasks::day22::task2;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
||||||
fn part1() {
|
fn part1() {
|
||||||
let input = std::fs::read_to_string("input/day22.txt").unwrap();
|
let input = std::fs::read_to_string("input/day22.txt").unwrap();
|
||||||
assert_eq!(7545, task1(input));
|
assert_eq!(7545, task1(&input));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn part2() {
|
fn part2() {
|
||||||
let input = std::fs::read_to_string("input/day22.txt").unwrap();
|
let input = std::fs::read_to_string("input/day22.txt").unwrap();
|
||||||
assert_eq!(2019, task2(input, 10007, 7545, 1));
|
assert_eq!(2019, task2(&input));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user