From 91f1c1b609605ba85ddeab12ae92c34b28df38c2 Mon Sep 17 00:00:00 2001 From: Xiretza Date: Sat, 9 Dec 2023 12:43:14 +0000 Subject: [PATCH] 2023 day9/rust: add solution --- 2023/day9/rust/Cargo.toml | 10 ++++ 2023/day9/rust/src/main.rs | 102 +++++++++++++++++++++++++++++++++++++ Cargo.lock | 8 +++ Cargo.toml | 1 + 4 files changed, 121 insertions(+) create mode 100644 2023/day9/rust/Cargo.toml create mode 100644 2023/day9/rust/src/main.rs diff --git a/2023/day9/rust/Cargo.toml b/2023/day9/rust/Cargo.toml new file mode 100644 index 0000000..21b826f --- /dev/null +++ b/2023/day9/rust/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "rust_2023_09" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +aoc = { path = "../../../common/rust" } +itertools = "0.12.0" diff --git a/2023/day9/rust/src/main.rs b/2023/day9/rust/src/main.rs new file mode 100644 index 0000000..b7e88fb --- /dev/null +++ b/2023/day9/rust/src/main.rs @@ -0,0 +1,102 @@ +#![warn(clippy::pedantic)] + +use std::{collections::VecDeque, io::stdin}; + +use itertools::Itertools; + +type Value = isize; + +fn make_derivative(xs: &[Value]) -> Option> { + if xs.iter().all_equal() { + None + } else { + Some(xs.iter().tuple_windows().map(|(a, b)| b - a).collect()) + } +} + +#[derive(Debug, Clone, Copy)] +enum Direction { + Forward, + Backward, +} + +#[derive(Debug)] +struct History { + values: VecDeque, + derivatives: Vec>, +} + +impl History { + pub fn new(values: VecDeque) -> Self { + let derivatives = std::iter::successors(Some(values.clone()), |prev| { + let (s1, s2) = prev.as_slices(); + assert!(s2.is_empty()); + make_derivative(s1) + }) + .skip(1) + .collect(); + + Self { + values, + derivatives, + } + } + + pub fn expand(&mut self, direction: Direction) { + Self::expand_values(&mut self.values, &mut self.derivatives, direction); + } + + fn expand_values( + values: &mut VecDeque, + derivatives: &mut [VecDeque], + direction: Direction, + ) { + if !derivatives.is_empty() { + let (next_values, next_derivatives) = derivatives.split_first_mut().unwrap(); + Self::expand_values(next_values, next_derivatives, direction); + } + + match direction { + Direction::Forward => { + let derivative = derivatives.first().map_or(0, |d| *d.back().unwrap()); + values.push_back(*values.back().unwrap() + derivative); + } + Direction::Backward => { + let derivative = derivatives.first().map_or(0, |d| *d.front().unwrap()); + values.push_front(*values.front().unwrap() - derivative); + } + } + } +} + +fn main() { + let mut histories: VecDeque<_> = stdin() + .lines() + .map(Result::unwrap) + .map(|l| History::new(l.split(' ').map(|n| n.parse().unwrap()).collect())) + .collect(); + + for history in &mut histories { + history.expand(Direction::Forward); + } + + println!( + "{}", + histories + .iter() + .map(|h| h.values.back().unwrap()) + .sum::() + ); + + for history in &mut histories { + history.expand(Direction::Backward); + } + + println!( + "{}", + histories + .iter() + .map(|h| h.values.front().unwrap()) + .sum::() + ); +} diff --git a/Cargo.lock b/Cargo.lock index b08ecf3..b014d6c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -679,6 +679,14 @@ dependencies = [ "petgraph", ] +[[package]] +name = "rust_2023_09" +version = "0.1.0" +dependencies = [ + "aoc", + "itertools 0.12.0", +] + [[package]] name = "rustversion" version = "1.0.14" diff --git a/Cargo.toml b/Cargo.toml index 96c1b7c..961b037 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -34,4 +34,5 @@ members = [ "2023/day6/rust", "2023/day7/rust", "2023/day8/rust", + "2023/day9/rust", ]