advent-of-code/2021/day13/rust/src/main.rs
2022-12-01 19:24:06 +01:00

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!();
}
}