-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmain.rs
127 lines (110 loc) · 3.96 KB
/
main.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
#![warn(clippy::all, clippy::pedantic, clippy::nursery)]
pub fn main() {
let data = include_str!("input.txt");
println!("Part 1: {}", part_one(data));
println!("Part 2: {}", part_two(data));
}
fn part_one(data: &str) -> usize {
data.split("\n\n")
.map(|pat| Pattern::new(pat).summarise(0))
.sum()
}
fn part_two(data: &str) -> usize {
data.split("\n\n")
.map(|pat| Pattern::new(pat).summarise(1))
.sum()
}
struct Pattern<'a> {
data: &'a [u8],
width: usize,
height: usize,
}
impl<'a> Pattern<'a> {
fn new(data: &'a str) -> Self {
let height = data.lines().count();
let width = data.lines().next().unwrap().chars().count();
Self {
data: data.as_bytes(),
width,
height,
}
}
fn row_reflection(&self, error_count: usize) -> Option<usize> {
(0..self.height - 1)
.find(|&fold_row| {
let range = std::cmp::min(fold_row + 1, self.height - fold_row - 1);
(0..range)
.try_fold(0, |outer, offset| {
(0..self.width)
.try_fold(0, |inner, col| {
let lower = (fold_row - offset) * (self.width + 1) + col;
let upper = lower + (2 * offset + 1) * (self.width + 1);
let errs = usize::from(self.data[lower] != self.data[upper]);
if inner + errs > error_count {
Err(0)
} else {
Ok(inner + errs)
}
})
.and_then(|inner| {
if outer + inner > error_count {
Err(0)
} else {
Ok(outer + inner)
}
})
})
.map_or(false, |sum| sum == error_count)
})
.map(|r| r + 1)
}
fn col_reflection(&self, error_count: usize) -> Option<usize> {
(0..self.width - 1)
.find(|&fold_col| {
let range = std::cmp::min(fold_col + 1, self.width - fold_col - 1);
(0..range)
.try_fold(0, |outer, offset| {
(0..self.height)
.try_fold(0, |inner, row| {
let lower = row * (self.width + 1) + (fold_col - offset);
let upper = lower + (2 * offset + 1);
let errs = usize::from(self.data[lower] != self.data[upper]);
if inner + errs > error_count {
Err(0)
} else {
Ok(inner + errs)
}
})
.and_then(|inner| {
if outer + inner > error_count {
Err(0)
} else {
Ok(outer + inner)
}
})
})
.map_or(false, |sum| sum == error_count)
})
.map(|r| r + 1)
}
fn summarise(&self, error_count: usize) -> usize {
self.row_reflection(error_count)
.map(|r| r * 100)
.or_else(|| self.col_reflection(error_count))
.unwrap()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn one() {
let data = include_str!("test.txt");
assert_eq!(405, part_one(data));
}
#[test]
fn two() {
let data = include_str!("test.txt");
assert_eq!(400, part_two(data));
}
}