83 lines
2.2 KiB
Rust
83 lines
2.2 KiB
Rust
#![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<Input<'a>, T>;
|
|
|
|
type Point = (usize, usize);
|
|
|
|
fn point(i: Input) -> IResult<Point> {
|
|
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<Fold> {
|
|
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<Point>, Vec<Fold>)> {
|
|
separated_pair(
|
|
many1(terminated(point, newline)),
|
|
newline,
|
|
many1(terminated(fold, newline)),
|
|
)(i)
|
|
}
|
|
|
|
fn do_fold(points: impl Iterator<Item = Point>, fold: Fold) -> HashSet<Point> {
|
|
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!();
|
|
}
|
|
}
|