From 938eda0d220aded933a5868fa13ad87280d99dbf Mon Sep 17 00:00:00 2001 From: Bert Peters Date: Wed, 1 Dec 2021 20:35:27 +0100 Subject: [PATCH] Rework day 1 Simplify part 2 a lot, by not actually computing the sums because they do not matter, only the changes do. Also eliminate the allocation overhead while parsing line-by-line input. Fixes the existing clippy error because the offending line no longer exists. --- 2021/src/common.rs | 45 +++++++++++++++++++++++++++++++++++++++++++++ 2021/src/day01.rs | 27 +++++---------------------- 2021/src/lib.rs | 1 + 3 files changed, 51 insertions(+), 22 deletions(-) create mode 100644 2021/src/common.rs diff --git a/2021/src/common.rs b/2021/src/common.rs new file mode 100644 index 0000000..3cb3826 --- /dev/null +++ b/2021/src/common.rs @@ -0,0 +1,45 @@ +use std::io::BufRead; +use std::io::BufReader; +use std::io::Read; +use std::marker::PhantomData; +use std::str::FromStr; + +/// Line-based iterator/parser +/// +/// For each line of the input, attempt to parse it as the requested type. Iteration is stopped on +/// the first IO error or parse error, silently. Leading and trailing whitespace is stripped before +/// attempting to parse. +pub struct LineParser<'a, I> +where + I: FromStr, +{ + reader: BufReader<&'a mut dyn Read>, + buffer: String, + _data: PhantomData, +} + +impl<'a, I: FromStr> LineParser<'a, I> { + pub fn new(input: &'a mut dyn Read) -> Self { + Self { + reader: BufReader::new(input), + buffer: String::new(), + _data: PhantomData, + } + } + + fn next_line(&mut self) -> Option<&str> { + self.buffer.clear(); + + self.reader.read_line(&mut self.buffer).ok()?; + + Some(self.buffer.trim()) + } +} + +impl<'a, I: FromStr> Iterator for LineParser<'a, I> { + type Item = I; + + fn next(&mut self) -> Option { + self.next_line()?.parse().ok() + } +} diff --git a/2021/src/day01.rs b/2021/src/day01.rs index 81c1611..1c3acd1 100644 --- a/2021/src/day01.rs +++ b/2021/src/day01.rs @@ -1,15 +1,9 @@ -use std::io::BufRead; -use std::io::BufReader; use std::io::Read; -fn read_input(input: &mut dyn Read) -> Vec { - let reader = BufReader::new(input); +use crate::common::LineParser; - // TODO: optimize allocations out - reader - .lines() - .map(|l| l.unwrap().parse().unwrap()) - .collect() +fn read_input(input: &mut dyn Read) -> Vec { + LineParser::new(input).collect() } pub fn part1(input: &mut dyn Read) -> String { @@ -25,20 +19,9 @@ pub fn part1(input: &mut dyn Read) -> String { pub fn part2(input: &mut dyn Read) -> String { let numbers = read_input(input); - let mut last = None; - numbers - .windows(3) - .filter(|w| { - let sum: u32 = w.iter().sum(); - - let prev = last.replace(sum); - - match prev { - Some(n) if n < sum => true, - _ => false, - } - }) + .windows(4) + .filter(|w| w[3] > w[0]) .count() .to_string() } diff --git a/2021/src/lib.rs b/2021/src/lib.rs index dde6c89..f54b5d8 100644 --- a/2021/src/lib.rs +++ b/2021/src/lib.rs @@ -2,6 +2,7 @@ use std::io::Read; type Solution = fn(&mut dyn Read) -> String; +mod common; mod day01; mod day02; mod day03;