aoc2023/9/src/main.rs
2023-12-08 21:41:30 -08:00

116 lines
2.7 KiB
Rust

use itertools::Itertools;
use std::fs::File;
use std::io::{BufRead, BufReader, Lines};
// BOILERPLATE
type InputIter = Lines<BufReader<File>>;
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<Vec<i64>>);
impl From<&str> for History {
fn from(s: &str) -> Self {
let hist: Vec<i64> = 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);
}
}
fn extrapolate2(&mut self) {
self.build();
self.0.last_mut().unwrap().insert(0, 0);
for (lower, upper) in (0..self.0.len()).rev().tuple_windows() {
let new_value = self.0[upper].first().unwrap() - self.0[lower].first().unwrap();
self.0[upper].insert(0, new_value);
}
}
}
// PROBLEM 1 solution
fn problem1<T: BufRead>(input: Lines<T>) -> i64 {
let mut histories: Vec<History> = 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<T: BufRead>(input: Lines<T>) -> i64 {
let mut histories: Vec<History> = input.map(|s| History::from(s.unwrap().as_str())).collect();
for history in &mut histories {
history.extrapolate2();
}
histories
.iter()
.map(|history| history.0.first().unwrap().first().unwrap())
.sum()
}
#[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()), 2);
}
}