-
Notifications
You must be signed in to change notification settings - Fork 1
/
day16.rs
127 lines (113 loc) · 3.68 KB
/
day16.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
use std::collections::VecDeque;
use ndarray::Array2;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
enum Dir {
N = 1,
E = 2,
S = 3,
W = 4,
}
use Dir::*;
impl Dir {
fn apply(&self, pos: (usize, usize)) -> (usize, usize) {
match self {
N => (pos.0.wrapping_sub(1), pos.1),
E => (pos.0, pos.1 + 1),
S => (pos.0 + 1, pos.1),
W => (pos.0, pos.1.wrapping_sub(1)),
}
}
}
#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, Hash)]
enum Mirror {
#[default]
Empty,
MirrorRight, // /
MirrorLeft, // \
SplitVertical, // |
SplitHorizontal, // -
}
impl Mirror {
fn redirect(&self, dir: Dir) -> Vec<Dir> {
match (self, dir) {
(Mirror::Empty, _) => vec![dir],
(Mirror::MirrorRight, E) => vec![N],
(Mirror::MirrorRight, S) => vec![W],
(Mirror::MirrorRight, N) => vec![E],
(Mirror::MirrorRight, W) => vec![S],
(Mirror::MirrorLeft, E) => vec![S],
(Mirror::MirrorLeft, N) => vec![W],
(Mirror::MirrorLeft, S) => vec![E],
(Mirror::MirrorLeft, W) => vec![N],
(Mirror::SplitVertical, N | S) => vec![dir],
(Mirror::SplitVertical, E | W) => vec![N, S],
(Mirror::SplitHorizontal, E | W) => vec![dir],
(Mirror::SplitHorizontal, N | S) => vec![E, W],
}
}
}
impl From<u8> for Mirror {
fn from(c: u8) -> Mirror {
match c {
b'/' => Mirror::MirrorRight,
b'\\' => Mirror::MirrorLeft,
b'|' => Mirror::SplitVertical,
b'-' => Mirror::SplitHorizontal,
_ => Mirror::Empty,
}
}
}
fn read_input(input: String) -> Array2<Mirror> {
let lines: Vec<_> = input.lines().collect();
let n_lines = lines.len();
let elements: Vec<_> = lines.iter()
.flat_map(|l| l.bytes().map(Mirror::from))
.collect();
Array2::from_shape_vec((n_lines, elements.len() / n_lines), elements)
.unwrap()
}
fn beam(field: &Array2<Mirror>, start_pos: (usize, usize), dir: Dir) -> u32 {
let mut beams = VecDeque::from([(start_pos, dir)]);
// For counting unique energized fields
let mut energized = vec![false; field.len()];
// For finding cycles, directions are also included in the key
let mut positions = vec![false; field.len() * 4];
while let Some((pos, dir)) = beams.pop_front() {
if let Some(mirror) = field.get(pos) {
let fkey = pos.0 * field.ncols() + pos.1;
energized[fkey] = true;
let key = (pos.0 * field.ncols() + pos.1) * 4 + dir as usize;
if positions[key] {
// Cycle detected, stop looking at this beam
continue;
} else {
positions[key] = true;
}
for new_dir in mirror.redirect(dir) {
let new_pos = new_dir.apply(pos);
beams.push_back((new_pos, new_dir));
}
}
}
energized.iter().filter(|&e| *e).count() as u32
}
fn part1(input: String) {
let field = read_input(input);
let energized = beam(&field, (0, 0), E);
println!("{}", energized);
}
fn part2(input: String) {
let field = read_input(input);
let mut max = 0;
let n = field.nrows();
// Input is quadratic
assert!(n == field.ncols());
for i in 0..n {
max = max.max(beam(&field, (i, 0), E)); // Left edge
max = max.max(beam(&field, (0, i), S)); // Top edge
max = max.max(beam(&field, (i, n), W)); // Right edge
max = max.max(beam(&field, (n, i), N)); // Bottom edge
}
println!("{max}");
}
util::aoc_main!("day16.txt");