#![warn(clippy::pedantic)] use std::collections::HashSet; use std::io::{stdin, Read}; use nom::bytes::complete::tag; use nom::character::complete::{anychar, newline, u32}; use nom::combinator::{map, map_opt}; use nom::multi::many1; use nom::sequence::{preceded, separated_pair, terminated}; type Input<'a> = &'a str; type IResult<'a, T> = nom::IResult, T>; type Point = (usize, usize); fn point(i: Input) -> IResult { separated_pair(map(u32, |i| i as usize), tag(","), map(u32, |i| i as usize))(i) } #[derive(Clone, Copy, PartialEq, Eq, Debug)] enum Fold { X(usize), Y(usize), } fn fold(i: Input) -> IResult { map_opt( preceded( tag("fold along "), separated_pair(anychar, tag("="), map(u32, |i| i as usize)), ), |(dimension, position)| match dimension { 'x' => Some(Fold::X(position)), 'y' => Some(Fold::Y(position)), _ => None, }, )(i) } fn input(i: Input) -> IResult<(Vec, Vec)> { separated_pair( many1(terminated(point, newline)), newline, many1(terminated(fold, newline)), )(i) } fn do_fold(points: impl Iterator, fold: Fold) -> HashSet { let transform = |x, n| if x < n { x } else { n - (x - n) }; points .map(|(x, y)| match fold { Fold::X(n) => (transform(x, n), y), Fold::Y(n) => (x, transform(y, n)), }) .collect() } fn main() { let mut data = String::new(); stdin().lock().read_to_string(&mut data).unwrap(); let (points, folds) = input(&data).unwrap().1; let mut points: HashSet<_> = points.into_iter().collect(); let mut folds = folds.into_iter(); points = do_fold(points.into_iter(), folds.next().unwrap()); println!("{}", points.len()); for fold in folds { points = do_fold(points.into_iter(), fold); } for row in 0..=points.iter().map(|&(_, y)| y).max().unwrap() { for col in 0..=points.iter().map(|&(x, _)| x).max().unwrap() { if points.contains(&(col, row)) { print!("#"); } else { print!("."); } } println!(); } }