summaryrefslogtreecommitdiff
path: root/2021/src/bin/day_13.rs
diff options
context:
space:
mode:
Diffstat (limited to '2021/src/bin/day_13.rs')
-rw-r--r--2021/src/bin/day_13.rs136
1 files changed, 136 insertions, 0 deletions
diff --git a/2021/src/bin/day_13.rs b/2021/src/bin/day_13.rs
new file mode 100644
index 0000000..547c7a2
--- /dev/null
+++ b/2021/src/bin/day_13.rs
@@ -0,0 +1,136 @@
+use nom::{
+ branch::alt,
+ bytes::complete::tag,
+ character::complete::{char as nom_char, line_ending, u32 as nom_u32},
+ combinator::map,
+ multi::{many0, separated_list1},
+ sequence::tuple,
+ IResult,
+};
+use std::{collections::BTreeSet, fmt, fs};
+
+fn main() -> Result<(), Box<dyn std::error::Error>> {
+ let input = fs::read_to_string("inputs/day_13.txt")?;
+ let mut page = parse_page(&input).unwrap().1;
+ page.do_next_fold();
+ dbg!(page.count_points());
+ while page.do_next_fold() {}
+ println!("{}", page);
+
+ Ok(())
+}
+
+#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
+struct Point {
+ x: u32,
+ y: u32,
+}
+
+#[derive(Debug)]
+enum Fold {
+ X(u32),
+ Y(u32),
+}
+
+#[derive(Debug)]
+struct Page {
+ points: BTreeSet<Point>,
+ folds: Vec<Fold>,
+}
+
+impl Page {
+ fn do_next_fold(&mut self) -> bool {
+ let fold = self.folds.pop();
+ match fold {
+ Some(Fold::X(x)) => {
+ self.points = std::mem::take(&mut self.points)
+ .into_iter()
+ .filter(|point| point.x != x)
+ .map(|point| {
+ if point.x > x {
+ Point {
+ x: x - (point.x - x),
+ y: point.y,
+ }
+ } else {
+ point
+ }
+ })
+ .collect();
+ true
+ }
+ Some(Fold::Y(y)) => {
+ self.points = std::mem::take(&mut self.points)
+ .into_iter()
+ .filter(|point| point.y != y)
+ .map(|point| {
+ if point.y > y {
+ Point {
+ x: point.x,
+ y: y - (point.y - y),
+ }
+ } else {
+ point
+ }
+ })
+ .collect();
+ true
+ }
+ None => false,
+ }
+ }
+
+ fn count_points(&self) -> usize {
+ self.points.len()
+ }
+}
+
+impl fmt::Display for Page {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
+ let width = self.points.iter().map(|p| p.x).max().unwrap_or(0);
+ let height = self.points.iter().map(|p| p.y).max().unwrap_or(0);
+ for y in 0..=height {
+ for x in 0..=width {
+ let p = Point { x, y };
+ if self.points.contains(&p) {
+ write!(f, "#")?;
+ } else {
+ write!(f, ".")?;
+ }
+ }
+ writeln!(f)?;
+ }
+ Ok(())
+ }
+}
+
+fn parse_page(input: &str) -> IResult<&str, Page> {
+ let (input, points) = separated_list1(line_ending, parse_point)(input)?;
+ let (input, _) = many0(line_ending)(input)?;
+ let (input, mut folds) = separated_list1(line_ending, parse_fold)(input)?;
+ folds.reverse();
+ Ok((
+ input,
+ Page {
+ points: points.into_iter().collect(),
+ folds,
+ },
+ ))
+}
+
+fn parse_fold(input: &str) -> IResult<&str, Fold> {
+ alt((
+ map(tuple((tag("fold along x="), nom_u32)), |(_, val)| {
+ Fold::X(val)
+ }),
+ map(tuple((tag("fold along y="), nom_u32)), |(_, val)| {
+ Fold::Y(val)
+ }),
+ ))(input)
+}
+
+fn parse_point(input: &str) -> IResult<&str, Point> {
+ map(tuple((nom_u32, nom_char(','), nom_u32)), |(x, _, y)| {
+ Point { x, y }
+ })(input)
+}