Skip to content

Commit 501c34d

Browse files
committed
day16pt2: done
1 parent f924486 commit 501c34d

File tree

4 files changed

+238
-0
lines changed

4 files changed

+238
-0
lines changed

Cargo.lock

Lines changed: 4 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ members = [
3131
"day15",
3232
"day15pt2",
3333
"day16",
34+
"day16pt2",
3435
]
3536

3637
[profile.dev]

day16pt2/Cargo.toml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
[package]
2+
name = "day16pt2"
3+
version = "0.1.0"
4+
edition = "2021"
5+
6+
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
7+
8+
[dependencies]

day16pt2/src/main.rs

Lines changed: 225 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,225 @@
1+
use std::collections::HashSet;
2+
3+
#[derive(Clone, Copy, Eq, PartialEq, Hash)]
4+
struct Beam {
5+
x: i32,
6+
y: i32,
7+
dx: i32,
8+
dy: i32,
9+
}
10+
11+
struct Map {
12+
w: i32,
13+
h: i32,
14+
tiles: Vec<char>,
15+
visited: Vec<bool>,
16+
}
17+
18+
impl Map {
19+
fn new(lines: &[String]) -> Self {
20+
let tiles = lines
21+
.iter()
22+
.flat_map(|line| line.chars())
23+
.collect::<Vec<char>>();
24+
let visited_len = tiles.len();
25+
Self {
26+
w: lines.get(0).map(String::len).unwrap_or(0) as i32,
27+
h: lines.len() as i32,
28+
tiles,
29+
visited: vec![false; visited_len],
30+
}
31+
}
32+
33+
fn index(&self, x: i32, y: i32) -> usize {
34+
(y * self.w + x) as usize
35+
}
36+
37+
fn fire_beam(&mut self, initial_beam: Beam) {
38+
for v in self.visited.iter_mut() {
39+
*v = false;
40+
}
41+
let mut beams: Vec<Beam> = Vec::new();
42+
beams.push(initial_beam);
43+
let mut past_beams: HashSet<Beam> = HashSet::new();
44+
while !beams.is_empty() {
45+
beams.retain(|b| {
46+
b.x >= 0 && b.x < self.w && b.y >= 0 && b.y < self.h && !past_beams.contains(b)
47+
});
48+
let mut new_beams: Vec<Beam> = Vec::new();
49+
for beam in beams.iter_mut() {
50+
past_beams.insert(*beam);
51+
let index = self.index(beam.x, beam.y);
52+
self.visited[index] = true;
53+
match (beam.dx, beam.dy, self.tiles[index]) {
54+
(_, _, '.') => {}
55+
// up beam
56+
(0, -1, '/') => {
57+
// reflect right
58+
beam.dx = 1;
59+
beam.dy = 0;
60+
}
61+
(0, -1, '\\') => {
62+
// reflect left
63+
beam.dx = -1;
64+
beam.dy = 0;
65+
}
66+
(0, -1, '|') => {}
67+
(0, -1, '-') => {
68+
// split left and right
69+
beam.dx = -1;
70+
beam.dy = 0;
71+
new_beams.push(Beam {
72+
x: beam.x,
73+
y: beam.y,
74+
dx: 1,
75+
dy: 0,
76+
});
77+
}
78+
// down beam
79+
(0, 1, '/') => {
80+
// reflect left
81+
beam.dx = -1;
82+
beam.dy = 0;
83+
}
84+
(0, 1, '\\') => {
85+
// reflect right
86+
beam.dx = 1;
87+
beam.dy = 0;
88+
}
89+
(0, 1, '|') => {}
90+
(0, 1, '-') => {
91+
// split left and right
92+
beam.dx = -1;
93+
beam.dy = 0;
94+
new_beams.push(Beam {
95+
x: beam.x,
96+
y: beam.y,
97+
dx: 1,
98+
dy: 0,
99+
});
100+
}
101+
// left beam
102+
(-1, 0, '/') => {
103+
// reflect down
104+
beam.dx = 0;
105+
beam.dy = 1;
106+
}
107+
(-1, 0, '\\') => {
108+
// reflect up
109+
beam.dx = 0;
110+
beam.dy = -1;
111+
}
112+
(-1, 0, '|') => {
113+
// split up and down
114+
beam.dx = 0;
115+
beam.dy = -1;
116+
new_beams.push(Beam {
117+
x: beam.x,
118+
y: beam.y,
119+
dx: 0,
120+
dy: 1,
121+
});
122+
}
123+
(-1, 0, '-') => {}
124+
// right beam
125+
(1, 0, '/') => {
126+
// reflect up
127+
beam.dx = 0;
128+
beam.dy = -1;
129+
}
130+
(1, 0, '\\') => {
131+
// reflect down
132+
beam.dx = 0;
133+
beam.dy = 1;
134+
}
135+
(1, 0, '|') => {
136+
// split up and down
137+
beam.dx = 0;
138+
beam.dy = -1;
139+
new_beams.push(Beam {
140+
x: beam.x,
141+
y: beam.y,
142+
dx: 0,
143+
dy: 1,
144+
});
145+
}
146+
(1, 0, '-') => {}
147+
_ => panic!(),
148+
}
149+
}
150+
beams.extend(new_beams.drain(..));
151+
for beam in beams.iter_mut() {
152+
beam.x += beam.dx;
153+
beam.y += beam.dy;
154+
}
155+
}
156+
}
157+
158+
fn count_energized(&self) -> usize {
159+
self.visited.iter().filter(|&&v| v).count()
160+
}
161+
}
162+
163+
fn main() {
164+
let lines = std::io::stdin()
165+
.lines()
166+
.map(Result::unwrap)
167+
.map(|l| l.to_string())
168+
.collect::<Vec<String>>();
169+
let mut map = Map::new(&lines[..]);
170+
let max_from_left = (0..map.h)
171+
.map(|y| {
172+
map.fire_beam(Beam {
173+
x: 0,
174+
y,
175+
dx: 1,
176+
dy: 0,
177+
});
178+
map.count_energized()
179+
})
180+
.max()
181+
.expect("max_from_left");
182+
let max_from_right = (0..map.h)
183+
.map(|y| {
184+
map.fire_beam(Beam {
185+
x: map.w - 1,
186+
y,
187+
dx: -1,
188+
dy: 0,
189+
});
190+
map.count_energized()
191+
})
192+
.max()
193+
.expect("max_from_right");
194+
let max_from_top = (0..map.w)
195+
.map(|x| {
196+
map.fire_beam(Beam {
197+
x,
198+
y: 0,
199+
dx: 0,
200+
dy: 1,
201+
});
202+
map.count_energized()
203+
})
204+
.max()
205+
.expect("max_from_top");
206+
let max_from_bottom = (0..map.w)
207+
.map(|x| {
208+
map.fire_beam(Beam {
209+
x,
210+
y: map.h - 1,
211+
dx: 0,
212+
dy: -1,
213+
});
214+
map.count_energized()
215+
})
216+
.max()
217+
.expect("max_from_bottom");
218+
println!(
219+
"{}",
220+
[max_from_left, max_from_right, max_from_top, max_from_bottom]
221+
.iter()
222+
.max()
223+
.unwrap()
224+
);
225+
}

0 commit comments

Comments
 (0)