From 0f9d48314e1c9a0b589bad80501d8a9641b4312e Mon Sep 17 00:00:00 2001 From: Johannes Date: Sat, 8 Oct 2022 14:41:47 +0200 Subject: [PATCH] Day 16 part 2 --- src/main.rs | 2 +- src/tasks/day16.rs | 174 +++++++++++++++++++++++++++++---------------- 2 files changed, 112 insertions(+), 64 deletions(-) diff --git a/src/main.rs b/src/main.rs index c34fd51..04c45b6 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,5 +3,5 @@ extern crate core; mod tasks; fn main() { - tasks::day25::run(); + tasks::day16::run(); } diff --git a/src/tasks/day16.rs b/src/tasks/day16.rs index 5e8bfe6..4bceb8b 100644 --- a/src/tasks/day16.rs +++ b/src/tasks/day16.rs @@ -1,16 +1,30 @@ -use itertools::Itertools; -use num_integer::Integer; +use std::collections::HashMap; use std::iter; +use itertools::Itertools; + +const BASE_PATTERN: [i32; 4] = [0, 1, 0, -1]; const INPUT: &str = "59750530221324194853012320069589312027523989854830232144164799228029162830477472078089790749906142587998642764059439173975199276254972017316624772614925079238407309384923979338502430726930592959991878698412537971672558832588540600963437409230550897544434635267172603132396722812334366528344715912756154006039512272491073906389218927420387151599044435060075148142946789007756800733869891008058075303490106699737554949348715600795187032293436328810969288892220127730287766004467730818489269295982526297430971411865028098708555709525646237713045259603175397623654950719275982134690893685598734136409536436003548128411943963263336042840301380655801969822"; #[allow(dead_code)] pub fn run() { let input = to_digits(INPUT); task1(input.clone()); + task2(to_digits("02935109699940807407585447034323")); task2(input.clone()); } +fn task1(input: Vec) -> String { + let mut s = S { input, cache: HashMap::new() }; + s.prep(); + let result = format!("{:.*}", 8, (0..8).map(|position| { + let r = s.get(position, 100); + r + }).join("")); + println!("Task 1: {result}"); + result +} + fn to_digits(input: &str) -> Vec { input .chars() @@ -18,71 +32,88 @@ fn to_digits(input: &str) -> Vec { .collect_vec() } -fn task1(input: Vec) -> String { - let p = [0, 1, 0, -1]; - let result = (0..100).fold(input, |old, _| { - (1..=old.len()) - .map(|position| { - let pattern = p - .iter() - .map(|x| std::iter::repeat(*x).take(position)) - .flatten(); - let val: i32 = old - .iter() - .zip(std::iter::repeat(pattern).flatten().skip(1)) - .map(|(value, multiplier)| value * multiplier) - .sum(); - val.abs() % 10 - }) - .collect_vec() - }); - let result = format!("{:.*}", 8, result.iter().join("")); - println!("Task 1: {result}"); +fn task2(input: Vec) -> String { + let big_input = iter::repeat(input.clone().into_iter()) + .take(10_000) + .flatten() + .collect_vec(); + + let mut s = S { input: big_input, cache: HashMap::new() }; + let result_position = format!("{}", input.split_at(7).0.iter().join("")).parse::().unwrap(); + s.prep_after(result_position); + let result = format!("{:.*}", 8, (0..8).map(|position| { + let r = s.get(position + result_position, 100); + r + }).join("")); + + println!("Task 2: {result}"); result } -fn task2(input: Vec) -> String { - let l = input.len() * 10_000; - let big_input = iter::repeat(input.clone().into_iter()) - .flatten() - .take(l) - .collect_vec(); - let p = [0, 1, 0, -1]; - let result = (0..100).fold(big_input, |old, _| { - (1..=old.len()) - .map(|position| { - let pattern = p.iter().map(|x| iter::repeat(*x).take(position)).flatten(); - let iter = iter::repeat(pattern).flatten().skip(1); - let repeats_after = (4 * position).lcm(&input.len()); - if repeats_after > l { - l - } else { - repeats_after - }; - let part: i32 = iter::repeat(input.iter()) - .flatten() - .zip(iter.clone()) - .take(repeats_after) - .map(|(value, multiplier)| value * multiplier) - .sum(); - let part_fits = l / repeats_after; - let most_parts = part * part_fits as i32; +type V = i32; - let number_rest = l / repeats_after; - let part_rest: i32 = iter - .zip(iter::repeat(input.iter()).flatten()) - .take(number_rest) - .map(|(value, multiplier)| value * multiplier) - .sum(); +struct S { + input: Vec, + cache: HashMap<(usize, usize), V>, +} - (part_rest + most_parts) % 10 - }) - .collect_vec() - }); - let offset = input[0..7].iter().join("").parse::().unwrap(); - let message = result[offset..offset + 8].iter().join(""); - println!("Task 2: {}", message); - message +impl S { + fn pattern(&self, position: usize, size: usize) -> Vec { + let pattern = BASE_PATTERN.iter().map(|x| iter::repeat(*x).take(position)).flatten(); + let iter = iter::repeat(pattern).flatten().skip(1).take(size); + iter.collect() + } + + fn get(&mut self, index: usize, phase: usize) -> V { + if phase == 0 { + return self.input[index]; + } + + if self.cache.contains_key(&(phase, index)) { + return self.cache[&(phase, index)]; + } + + if index == self.input.len() - 1 { + let v = self.get(index, phase - 1); + self.cache.insert((phase, index), v); + return v; + } + + if index > (self.input.len() / 2 + 1) { + let v = self.get(index + 1, phase) + self.get(index, phase - 1); + let v = v.abs() % 10; + self.cache.insert((phase, index), v); + return v; + } + + let pattern = self.pattern(index + 1, self.input.len()); + let val: i32 = pattern + .iter() + .enumerate() + .map(|(i, p)| if *p == 0 { 0 } else { *p * self.get(i, phase - 1) }) + .sum(); + let result = val.abs() % 10; + self.cache.insert((phase, index), result); + result + } + + fn prep(&mut self) { + for phase in 1..=100 { + for i in 1..self.input.len() / 2 { + self.get(self.input.len() - i, phase); + } + } + println!("preparation done") + } + + fn prep_after(&mut self, start: usize) { + for phase in 1..=100 { + for i in (start..self.input.len()).rev() { + self.get(i, phase); + } + } + println!("preparation done") + } } #[cfg(test)] @@ -104,13 +135,30 @@ mod test { "52432133" ); } + #[test] fn test_part_1_solution() { assert_eq!(task1(to_digits(INPUT)), "84487724"); } #[test] - fn test_part_2() { + fn test_part_2_solution() { + assert_eq!(task2(to_digits(INPUT)), "84692524"); + } + + #[test] + fn test_trivial() { + let mut s = S { input: to_digits("12345678"), cache: HashMap::new() }; + s.prep(); + let result = format!("{:.*}", 8, (0..8).map(|position| { + let r = s.get(position, 1); + r + }).join("")); + assert_eq!(result, "48226158"); + } + + #[test] + fn test_part_2_examples() { assert_eq!( task2(to_digits("02935109699940807407585447034323")), "78725270"