-
Notifications
You must be signed in to change notification settings - Fork 33
Expand file tree
/
Copy pathday13.rs
More file actions
82 lines (70 loc) · 2.74 KB
/
day13.rs
File metadata and controls
82 lines (70 loc) · 2.74 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
//! # Transparent Origami
//!
//! There are 2 possible approaches to tracking the position of dots after each fold:
//! * A `HashSet` that will collapse duplicate entries
//! * An array of sufficient dimensions to track every possible coordinate.
//!
//! We will use both approaches for speed, the first in part one and the second in part two.
//!
//! For part two we can determine the final size of the paper by taking the *last* x and y
//! coordinates from the fold instructions. It's then faster and more convenient to process
//! each point completely and update the final location, than to step through intermediate folds.
use crate::util::grid::*;
use crate::util::hash::*;
use crate::util::iter::*;
use crate::util::parse::*;
use crate::util::point::*;
#[derive(Clone, Copy)]
pub enum Fold {
Horizontal(i32),
Vertical(i32),
}
pub struct Input {
points: Vec<Point>,
folds: Vec<Fold>,
}
/// Parse the input into collections of [`Point`] and [`Fold`] structs.
pub fn parse(input: &str) -> Input {
let (prefix, suffix) = input.split_once("\n\n").unwrap();
let points: Vec<_> = prefix.iter_signed().chunk::<2>().map(|[x, y]| Point::new(x, y)).collect();
let folds: Vec<_> = suffix
.lines()
.map(|line| match line.split_once('=').unwrap() {
("fold along x", x) => Fold::Horizontal(x.signed()),
("fold along y", y) => Fold::Vertical(y.signed()),
_ => unreachable!(),
})
.collect();
Input { points, folds }
}
/// Fold once then count dots. The sample data folds along `y` and my input folded along `x`,
/// testing both possibilities.
pub fn part1(input: &Input) -> usize {
let fold = input.folds[0];
input.points.iter().map(|&p| apply_fold(fold, p)).collect::<FastSet<_>>().len()
}
/// Decode secret message.
///
/// The output is a multi-line string to allow integration testing. The final dimensions of the
/// paper are found from the last `x` and `y` fold coordinates.
pub fn part2(input: &Input) -> String {
let (width, height) = input.folds.iter().fold((0, 0), |(width, height), &fold| match fold {
Fold::Horizontal(x) => (x, height),
Fold::Vertical(y) => (width, y),
});
let mut grid = Grid::new(width + 1, height, '.');
for &start in &input.points {
let end = input.folds.iter().fold(start, |point, &fold| apply_fold(fold, point));
grid[end + RIGHT] = '#';
}
(0..height).for_each(|y| grid[Point::new(0, y)] = '\n');
grid.bytes.iter().collect()
}
#[inline]
fn apply_fold(fold: Fold, point: Point) -> Point {
match fold {
Fold::Horizontal(x) if point.x >= x => Point::new(2 * x - point.x, point.y),
Fold::Vertical(y) if point.y >= y => Point::new(point.x, 2 * y - point.y),
_ => point,
}
}