-
Notifications
You must be signed in to change notification settings - Fork 0
/
20.rs
119 lines (104 loc) · 3.41 KB
/
20.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
type ImageMap = Vec<Vec<bool>>;
fn main() {
let input = include_str!("../../input/20.txt");
println!("Part 1: {}", part_1(input));
println!("Part 2: {}", part_2(input));
}
fn part_1(input: &str) -> usize {
process_image(input, 2)
}
fn part_2(input: &str) -> usize {
process_image(input, 50)
}
fn parse_input(input: &str, iterations: usize) -> (ImageMap, Vec<bool>) {
let (r, img) = input.split_once("\n\n").unwrap();
let first_line = r.replace('\n', "");
let rules = first_line.chars().map(|c| c == '#').collect();
let map: ImageMap = img
.lines()
.map(|line| {
let mut map_line = vec![false; iterations]
.into_iter()
.chain(line.chars().map(|c| c == '#'))
.collect::<Vec<bool>>();
map_line.resize(line.len() + iterations * 2, false);
map_line
})
.collect();
let padding: ImageMap = vec![vec![false; map[0].len() + iterations * 2]; iterations];
let mut res_map = padding.clone();
res_map.extend(map);
res_map.extend(padding);
(res_map, rules)
}
fn process_image(input: &str, iterations: usize) -> usize {
let (image_map, rules) = parse_input(input, iterations);
let (map, _) = (0..iterations).fold((image_map, false), |(map, default), _| {
(
map.iter()
.enumerate()
.map(|(r, row)| {
row.iter()
.enumerate()
.map(|(c, _)| get_new_pixel((r, c), &map, &rules, default))
.collect()
})
.collect(),
if default {
rules[0b1_1111_1111]
} else if rules[0] {
true
} else {
default
},
)
});
map.iter().flatten().filter(|&v| *v).count()
}
fn get_new_pixel(rc: (usize, usize), map: &[Vec<bool>], rules: &[bool], default: bool) -> bool {
let (r, c) = (rc.0 as isize, rc.1 as isize);
let pixel = |col: isize, row: isize| {
if col < 0 || row < 0 || col as usize >= map.len() || row as usize >= map.len() {
default
} else {
map[row as usize][col as usize]
}
};
rules[(r - 1..r + 2).fold(0, |n, row| {
(c - 1..c + 2).fold(n, |num, col| {
let number = num << 1;
if pixel(col, row) {
number + 1
} else {
number
}
})
})]
}
#[cfg(test)]
mod day_20_tests {
use super::*;
static INPUT: &str =
"..#.#..#####.#.#.#.###.##.....###.##.#..###.####..#####..#....#..#..##..##
#..######.###...####..#..#####..##..#.#####...##.#.#..#.##..#.#......#.###
.######.###.####...#.##.##..#..#..#####.....#.#....###..#.##......#.....#.
.#..#..##..#...##.######.####.####.#.#...#.......#..#.#.#...####.##.#.....
.#..#...##.#.##..#...##.#.##..###.#......#.#.......#.#.#.####.###.##...#..
...####.#..#..#.##.#....##..#.####....##...##..#...#......#.#.......#.....
..##..####..#...#.#.#...##..#.#..###..#####........#..####......#..#
#..#.
#....
##..#
..#..
..###";
#[test]
fn test_part_1() {
assert_eq!(part_1(INPUT), 35);
assert_eq!(part_1(include_str!("../../input/20.txt")), 5361);
}
#[test]
fn test_part_2() {
assert_eq!(part_2(INPUT), 3351);
assert_eq!(part_2(include_str!("../../input/20.txt")), 16826);
}
}