1
0
aoc-2021/src/day13.rs

148 lines
2.9 KiB
Rust

use std::collections::HashSet;
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Dot(u32, u32);
#[derive(Debug)]
pub enum Fold {
X(u32),
Y(u32),
}
pub struct InputData {
dots: Vec<Dot>,
folds: Vec<Fold>,
}
fn parse_dot(line: &str) -> Dot {
let (x, y) = line.split_once(',').unwrap();
return Dot(x.parse().unwrap(), y.parse().unwrap());
}
fn parse_fold(line: &str) -> Fold {
let (axis, coordinate_str) = line.split_once('=').unwrap();
let coordinate = coordinate_str.parse().unwrap();
match axis {
"fold along x" => Fold::X(coordinate),
"fold along y" => Fold::Y(coordinate),
_ => unreachable!("Unable to parse fold direction"),
}
}
pub fn parse_input(input: &str) -> InputData {
let (dots_section, folds_section) = input.split_once("\n\n").unwrap();
let dots = dots_section.lines().map(parse_dot).collect();
let folds = folds_section.lines().map(parse_fold).collect();
return InputData { dots, folds };
}
fn perform_fold(dots: &HashSet<Dot>, fold: &Fold) -> HashSet<Dot> {
let mut folded_dots = HashSet::new();
for dot in dots.iter() {
let folded_dot = match fold {
Fold::X(x) => {
if dot.0 > *x {
Dot(2 * x - dot.0, dot.1)
} else {
dot.clone()
}
}
Fold::Y(y) => {
if dot.1 > *y {
Dot(dot.0, 2 * y - dot.1)
} else {
dot.clone()
}
}
};
folded_dots.insert(folded_dot);
}
return folded_dots;
}
pub fn part1(input: &InputData) -> usize {
let mut folded_dots = HashSet::new();
for dot in &input.dots {
folded_dots.insert(dot.clone());
}
folded_dots = perform_fold(&folded_dots, &input.folds[0]);
folded_dots.len() as usize
}
fn determine_dot_bounds(dots: &HashSet<Dot>) -> (u32, u32, u32, u32) {
let mut min_x = u32::MAX;
let mut min_y = u32::MAX;
let mut max_x = u32::MIN;
let mut max_y = u32::MIN;
for dot in dots {
min_x = min_x.min(dot.0);
min_y = min_y.min(dot.1);
max_x = max_x.max(dot.0);
max_y = max_y.max(dot.1);
}
return (min_x, min_y, max_x, max_y);
}
fn render_dots(dots: &HashSet<Dot>) {
let (min_x, min_y, max_x, max_y) = determine_dot_bounds(dots);
for y in min_y..=max_y {
for x in min_x..=max_x {
if dots.contains(&Dot(x, y)) {
print!("#");
} else {
print!(".");
}
}
print!("\n");
}
}
pub fn part2(input: &InputData) {
let mut folded_dots = HashSet::new();
for dot in &input.dots {
folded_dots.insert(dot.clone());
}
for fold in &input.folds {
folded_dots = perform_fold(&folded_dots, fold);
}
render_dots(&folded_dots);
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn part1_example() {
let dots = vec![
Dot(6, 10),
Dot(0, 14),
Dot(9, 10),
Dot(0, 3),
Dot(10, 4),
Dot(4, 11),
Dot(6, 0),
Dot(6, 12),
Dot(4, 1),
Dot(0, 13),
Dot(10, 12),
Dot(3, 4),
Dot(3, 0),
Dot(8, 4),
Dot(1, 10),
Dot(2, 14),
Dot(8, 10),
Dot(9, 0),
];
let folds = vec![Fold::Y(7), Fold::X(5)];
let result = part1(&InputData { dots, folds });
assert_eq!(result, 17);
}
}