#![allow(clippy::needless_range_loop)] #![forbid(elided_lifetimes_in_paths, unsafe_code)] use aoc23::read; use chumsky::{prelude::*, text::int}; struct History(Vec<i64>); impl History { fn parser() -> impl Parser<char, Self, Error = Simple<char>> { one_of(['-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9']) .repeated() .at_least(1) .separated_by(just(" ")) .map(|nums: Vec<Vec<char>>| { Self( nums.into_iter() .map(|num| num.into_iter().collect::<String>().parse().unwrap()) .collect() ) }) } } fn parser() -> impl Parser<char, Vec<History>, Error = Simple<char>> { History::parser() .then_ignore(just("\n")) .repeated() .then_ignore(end()) } impl History { fn diff(&self) -> Self { // intentionally reserve one space extra for .extend() let mut diffs = Vec::with_capacity(self.0.len()); if self.0.len() > 1 { for i in 1 .. self.0.len() { diffs.push(self.0[i] - self.0[i - 1]); } } Self(diffs) } fn extend(&mut self) { if self.0.iter().any(|num| *num != 0) { let mut diff = self.diff(); diff.extend(); self.0.push(self.0.last().unwrap() + diff.0.last().unwrap()); } else { self.0.push(0); } } } fn main() -> anyhow::Result<()> { let histories = read("inputs/day9.txt", parser())?; let mut sum = 0; for mut h in histories { h.extend(); sum += h.0.last().unwrap(); } println!("{sum}"); Ok(()) }