use std::fs::File; use std::io::{BufRead, BufReader, Lines}; use itertools::Itertools; // BOILERPLATE type InputIter = Lines>; fn get_input() -> InputIter { let f = File::open("input").unwrap(); let br = BufReader::new(f); br.lines() } fn main() { println!("Problem 1 solution: {}", problem1(get_input())); println!("Problem 2 solution: {}", problem2(get_input())); } // PARSE #[derive(Debug)] struct History(Vec>); impl From<&str> for History { fn from(s: &str) -> Self { let hist: Vec = s .split_whitespace() .map(|num| num.parse().unwrap()) .collect(); Self(vec![hist]) } } impl History { fn build_row(&mut self) { let last = self.0.last().unwrap(); self.0.push( last.iter() .tuple_windows() .map(|(a, b)| b - a) .collect(), ) } fn build(&mut self) { while !self.0.last().unwrap().iter().all(|x| *x == 0) { self.build_row(); } } fn extrapolate(&mut self) { self.build(); self.0.last_mut().unwrap().push(0); for (lower, upper) in (0..self.0.len()).rev().tuple_windows() { let new_value = self.0[upper].last().unwrap() + self.0[lower].last().unwrap(); self.0[upper].push(new_value); } } } // PROBLEM 1 solution fn problem1(input: Lines) -> i64 { let mut histories: Vec = input.map(|s| History::from(s.unwrap().as_str())).collect(); for history in &mut histories { history.extrapolate(); } histories.iter().map(|history| history.0.first().unwrap().last().unwrap()).sum() } // PROBLEM 2 solution fn problem2(input: Lines) -> u64 { 0 } #[cfg(test)] mod tests { use crate::*; use std::io::Cursor; const EXAMPLE: &str = &"0 3 6 9 12 15 1 3 6 10 15 21 10 13 16 21 30 45"; #[test] fn problem1_example() { let c = Cursor::new(EXAMPLE); assert_eq!(problem1(c.lines()), 114); } #[test] fn problem2_example() { let c = Cursor::new(EXAMPLE); assert_eq!(problem2(c.lines()), 0); } }