From 6d72191e2ce5d423ca03c894d2dad1d3061bd4f3 Mon Sep 17 00:00:00 2001 From: Justin Wernick Date: Tue, 19 Apr 2022 20:27:29 +0200 Subject: Refile for merging repos --- 2021/src/bin/day_13.rs | 136 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 136 insertions(+) create mode 100644 2021/src/bin/day_13.rs (limited to '2021/src/bin/day_13.rs') 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> { + 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, + folds: Vec, +} + +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) +} -- cgit v1.2.3