diff --git a/2021/src/common.rs b/2021/src/common.rs index d4057b7..07311a6 100644 --- a/2021/src/common.rs +++ b/2021/src/common.rs @@ -53,7 +53,7 @@ impl<'a, I: FromStr> LineParser<'a, I> { } } -impl<'a, I: FromStr> Iterator for LineParser<'a, I> { +impl Iterator for LineParser<'_, I> { type Item = I; fn next(&mut self) -> Option { @@ -61,6 +61,15 @@ impl<'a, I: FromStr> Iterator for LineParser<'a, I> { } } +impl<'a, I: FromStr> From> for LineParser<'a, I> { + fn from(iter: LineIter<'a>) -> Self { + Self { + iter, + _data: PhantomData, + } + } +} + /// Return two arguments in their natural PartialOrd order pub fn ordered(a: O, b: O) -> (O, O) { if a < b { diff --git a/2021/src/day13.rs b/2021/src/day13.rs index 4df3eda..1f509a6 100644 --- a/2021/src/day13.rs +++ b/2021/src/day13.rs @@ -1,12 +1,16 @@ use std::collections::HashSet; use std::io::Read; +use std::str::FromStr; use nom::branch::alt; use nom::bytes::complete::tag; +use nom::error::Error; use nom::sequence::tuple; +use nom::Finish; use nom::IResult; use crate::common::LineIter; +use crate::common::LineParser; type Coords = (u16, u16); @@ -15,6 +19,21 @@ enum Fold { Y(u16), } +impl FromStr for Fold { + type Err = Error; + + fn from_str(s: &str) -> Result { + let (_, fold) = parse_fold(s) + .finish() + .map_err(|Error { input, code }| Error { + input: input.to_string(), + code, + })?; + + Ok(fold) + } +} + fn parse_coordinates(input: &str) -> IResult<&str, Coords> { use nom::character::complete::char; use nom::character::complete::u16; @@ -44,9 +63,23 @@ fn parse_fold(input: &str) -> IResult<&str, Fold> { Ok((input, fold)) } -fn apply_fold(dots: &mut HashSet, fold: Fold) { - let mut to_fold = Vec::new(); +fn read_dots(reader: &mut LineIter<'_>) -> HashSet { + let mut dots = HashSet::new(); + while let Some(line) = reader.next() { + if line.is_empty() { + break; + } + + let (_, coords) = parse_coordinates(line).unwrap(); + + dots.insert(coords); + } + + dots +} + +fn apply_fold(dots: &mut HashSet, fold: Fold, to_fold: &mut Vec) { match fold { Fold::X(coord) => dots.retain(|&(x, y)| { if x < coord { @@ -95,20 +128,10 @@ fn print_dots(dots: &HashSet) -> String { pub fn part1(input: &mut dyn Read) -> String { let mut reader = LineIter::new(input); - let mut dots = HashSet::new(); + let mut dots = read_dots(&mut reader); - while let Some(line) = reader.next() { - if line == "" { - break; - } - - let (_, coords) = parse_coordinates(line).unwrap(); - - dots.insert(coords); - } - - let fold = parse_fold(reader.next().unwrap()).unwrap().1; - apply_fold(&mut dots, fold); + let fold = reader.next().unwrap().parse().unwrap(); + apply_fold(&mut dots, fold, &mut Vec::new()); dots.len().to_string() } @@ -116,22 +139,10 @@ pub fn part1(input: &mut dyn Read) -> String { pub fn part2(input: &mut dyn Read) -> String { let mut reader = LineIter::new(input); - let mut dots = HashSet::new(); + let mut dots = read_dots(&mut reader); + let mut to_fold = Vec::new(); - while let Some(line) = reader.next() { - if line == "" { - break; - } - - let (_, coords) = parse_coordinates(line).unwrap(); - - dots.insert(coords); - } - - while let Some(line) = reader.next() { - let fold = parse_fold(line).unwrap().1; - apply_fold(&mut dots, fold); - } + LineParser::from(reader).for_each(|fold| apply_fold(&mut dots, fold, &mut to_fold)); print_dots(&dots) }