enum PairsState<N> {
Fresh,
Running(N),
Finished,
}
struct Pairs<I, N> {
inner: I,
state: PairsState<N>,
}
impl<I: Iterator<Item = N>, N> Pairs<I, N> {
fn new(inner: I) -> Self {
Self {
inner,
state: PairsState::Fresh,
}
}
}
impl<I: Iterator<Item = N>, N: Copy> Iterator for Pairs<I, N> {
type Item = (N, N);
fn next(&mut self) -> Option<Self::Item> {
match self.state {
PairsState::Fresh => match self.inner.next() {
None => {
self.state = PairsState::Finished;
None
}
Some(x) => {
self.state = PairsState::Running(x);
self.next()
}
},
PairsState::Running(last) => match self.inner.next() {
None => {
self.state = PairsState::Finished;
None
}
Some(x) => {
self.state = PairsState::Running(x);
Some((last, x))
}
},
PairsState::Finished => None,
}
}
}
struct SlidingWindow<I, N> {
inner: I,
size: usize,
window: std::collections::VecDeque<N>,
}
impl<I, N> SlidingWindow<I, N> {
fn new(inner: I, size: usize) -> Self {
Self {
inner,
size,
window: std::collections::VecDeque::new(),
}
}
}
impl<I: Iterator<Item = N>, N: Copy> Iterator for SlidingWindow<I, N> {
type Item = Vec<N>;
fn next(&mut self) -> Option<Self::Item> {
match self.inner.next() {
None => None,
Some(x) => {
self.window.push_back(x);
if self.window.len() < self.size {
self.next()
} else {
let result = self.window.iter().copied().collect();
self.window.pop_front();
Some(result)
}
}
}
}
}
fn count_increments<I: Iterator<Item = N>, N: Copy + std::cmp::PartialOrd>(
source: I,
) -> usize {
Pairs::new(source)
.map(|(last, current)| if current > last { 1 } else { 0 })
.sum()
}
fn main() {
use std::fs::File;
use std::io::BufRead;
use std::io::BufReader;
use std::path::Path;
let args: Vec<_> = std::env::args().collect();
let file = BufReader::new(
File::open(<String as AsRef<Path>>::as_ref(&args[1])).unwrap(),
);
let measurements: Vec<u64> = file
.lines()
.flat_map(|line| {
line.ok().and_then(|line| str::parse(line.as_ref()).ok())
})
.collect();
println!(
"Depth measurement increases {} times (measurements); {} times (moving window)",
count_increments(measurements.iter()),
count_increments(
SlidingWindow::new(measurements.iter(), 3).map(|w| w.into_iter().sum::<u64>())
)
);
}