-
Notifications
You must be signed in to change notification settings - Fork 0
/
day13.rs
132 lines (125 loc) · 3.35 KB
/
day13.rs
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
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
use super::util;
use itertools::Itertools;
use std::cmp::{max, min};
use std::collections::HashSet;
use std::error::Error;
fn run<'a, I, S>(
lines: I,
limit: Option<usize>,
) -> Result<HashSet<(i32, i32)>, Box<dyn Error + Send + Sync>>
where
I: IntoIterator<Item = &'a S>,
S: AsRef<str> + 'a,
{
let mut iter = lines.into_iter();
let mut points = HashSet::new();
for line in &mut iter {
let line = line.as_ref();
if line.is_empty() {
break;
}
let mut iter = line.split(',');
let x = iter.next().ok_or(util::Error)?.parse()?;
let y = iter.next().ok_or(util::Error)?.parse()?;
if iter.next().is_none() {
points.insert((x, y));
} else {
return Err(util::Error.into());
}
}
for (i, line) in iter.enumerate() {
let line = line.as_ref();
if let Some(fold_x) = line.strip_prefix("fold along x=") {
let fold_x: i32 = fold_x.parse()?;
points = points
.drain()
.map(|(x, y)| (fold_x - i32::abs(x - fold_x), y))
.collect();
} else if let Some(fold_y) = line.strip_prefix("fold along y=") {
let fold_y: i32 = fold_y.parse()?;
points = points
.drain()
.map(|(x, y)| (x, fold_y - i32::abs(y - fold_y)))
.collect();
} else {
return Err(util::Error.into());
}
if limit.map_or(false, |limit| i + 1 >= limit) {
break;
}
}
Ok(points)
}
pub fn part1<'a, I, S>(lines: I) -> Result<usize, Box<dyn Error + Send + Sync>>
where
I: IntoIterator<Item = &'a S>,
S: AsRef<str> + 'a,
{
Ok(run(lines, Some(1))?.len())
}
pub fn part2<'a, I, S>(lines: I) -> Result<String, Box<dyn Error + Send + Sync>>
where
I: IntoIterator<Item = &'a S>,
S: AsRef<str> + 'a,
{
let points = run(lines, None)?;
let ((x0, y0), (x1, y1)) = points.iter().fold(
((i32::MAX, i32::MAX), (i32::MIN, i32::MIN)),
|((x0, y0), (x1, y1)), &(x, y)| ((min(x0, x), min(y0, y)), (max(x1, x), max(y1, y))),
);
Ok((y0..=y1)
.map(|y| {
(x0..=x1)
.map(|x| {
if points.contains(&(x, y)) {
'\u{2593}'
} else {
'\u{2591}'
}
})
.collect::<String>()
})
.join("\n"))
}
#[cfg(test)]
mod tests {
use super::*;
use pretty_assertions::assert_eq;
use std::error::Error;
static EXAMPLE: &[&str] = &[
"6,10",
"0,14",
"9,10",
"0,3",
"10,4",
"4,11",
"6,0",
"6,12",
"4,1",
"0,13",
"10,12",
"3,4",
"3,0",
"8,4",
"1,10",
"2,14",
"8,10",
"9,0",
"",
"fold along y=7",
"fold along x=5",
];
#[test]
fn part1_examples() -> Result<(), Box<dyn Error + Send + Sync>> {
assert_eq!(17, part1(EXAMPLE)?);
Ok(())
}
#[test]
fn part2_examples() -> Result<(), Box<dyn Error + Send + Sync>> {
assert_eq!(
"▓▓▓▓▓\n▓░░░▓\n▓░░░▓\n▓░░░▓\n▓▓▓▓▓".to_string(),
part2(EXAMPLE)?
);
Ok(())
}
}