Skip to content

Commit df752e6

Browse files
committed
2018 day 17
1 parent c4aa844 commit df752e6

File tree

2 files changed

+158
-0
lines changed

2 files changed

+158
-0
lines changed

crates/year2018/src/day17.rs

Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
use utils::prelude::*;
2+
3+
/// Simulating water flow in a 2D grid.
4+
#[derive(Clone, Debug)]
5+
pub struct Day17 {
6+
part1: u32,
7+
part2: u32,
8+
}
9+
10+
#[repr(u8)]
11+
#[derive(Clone, Copy, Debug, PartialEq)]
12+
enum State {
13+
Empty,
14+
Flowing,
15+
Filled,
16+
}
17+
18+
impl Day17 {
19+
pub fn new(input: &str, _: InputType) -> Result<Self, InputError> {
20+
let segments = parser::byte_range(b'x'..=b'y')
21+
.with_suffix(b'=')
22+
.then(parser::number_range(1..=2999).with_suffix(", "))
23+
.then(parser::byte_range(b'x'..=b'y').with_suffix(b'='))
24+
.then(parser::number_range(1..=2999).with_suffix(".."))
25+
.then(parser::number_range(1..=2999))
26+
.map_res(|(axis1, c1, axis2, c2, c3)| {
27+
if axis1 == axis2 {
28+
Err("expected line segment")
29+
} else if c2 > c3 {
30+
Err("expected range to be sorted")
31+
} else {
32+
Ok((axis1, c1, c2, c3))
33+
}
34+
})
35+
.parse_lines(input)?;
36+
37+
if segments.is_empty() {
38+
return Err(InputError::new(input, 0, "expected at least one line"));
39+
}
40+
41+
let (mut x_min, mut x_max, mut y_min, mut y_max) = (500, 500, usize::MAX, 0);
42+
for &(axis, c1, c2, c3) in &segments {
43+
if axis == b'x' {
44+
x_min = x_min.min(c1);
45+
x_max = x_max.max(c1);
46+
y_min = y_min.min(c2);
47+
y_max = y_max.max(c3);
48+
} else {
49+
x_min = x_min.min(c2);
50+
x_max = x_max.max(c3);
51+
y_min = y_min.min(c1);
52+
y_max = y_max.max(c1);
53+
}
54+
}
55+
56+
// Reserve the top row for the spring
57+
y_min -= 1;
58+
// Padding to avoid wrapping around rows
59+
x_min -= 1;
60+
x_max += 1;
61+
62+
let width = x_max - x_min + 1;
63+
let height = y_max - y_min + 1;
64+
let mut grid = vec![State::Empty; width * height];
65+
for &(axis, c1, c2, c3) in &segments {
66+
if axis == b'x' {
67+
let x = c1 - x_min;
68+
for y in c2 - y_min..=c3 - y_min {
69+
grid[y * width + x] = State::Filled;
70+
}
71+
} else {
72+
let y = c1 - y_min;
73+
for x in c2 - x_min..=c3 - x_min {
74+
grid[y * width + x] = State::Filled;
75+
}
76+
}
77+
}
78+
79+
let mut counts = [0; 3];
80+
Self::flow(&mut grid, width, &mut counts, 500 - x_min);
81+
82+
Ok(Self {
83+
part1: counts[State::Filled as usize] + counts[State::Flowing as usize],
84+
part2: counts[State::Filled as usize],
85+
})
86+
}
87+
88+
fn flow(grid: &mut [State], width: usize, counts: &mut [u32; 3], index: usize) -> State {
89+
if index >= grid.len() {
90+
return State::Flowing;
91+
}
92+
if grid[index] != State::Empty {
93+
return grid[index];
94+
}
95+
96+
if Self::flow(grid, width, counts, index + width) == State::Flowing {
97+
grid[index] = State::Flowing;
98+
if index >= width {
99+
counts[State::Flowing as usize] += 1;
100+
}
101+
return State::Flowing;
102+
}
103+
104+
let mut left = index;
105+
while grid[left - 1] == State::Empty {
106+
left -= 1;
107+
if Self::flow(grid, width, counts, left + width) == State::Flowing {
108+
break;
109+
}
110+
}
111+
112+
let mut right = index;
113+
while grid[right + 1] == State::Empty {
114+
right += 1;
115+
if Self::flow(grid, width, counts, right + width) == State::Flowing {
116+
break;
117+
}
118+
}
119+
120+
let state = if grid[left - 1] == State::Filled && grid[right + 1] == State::Filled {
121+
State::Filled
122+
} else {
123+
State::Flowing
124+
};
125+
126+
grid[left..=right].fill(state);
127+
if index >= width {
128+
counts[state as usize] += (right - left + 1) as u32;
129+
}
130+
state
131+
}
132+
133+
#[must_use]
134+
pub fn part1(&self) -> u32 {
135+
self.part1
136+
}
137+
138+
#[must_use]
139+
pub fn part2(&self) -> u32 {
140+
self.part2
141+
}
142+
}
143+
144+
examples!(Day17 -> (u32, u32) [
145+
{
146+
input: "x=495, y=2..7\n\
147+
y=7, x=495..501\n\
148+
x=501, y=3..7\n\
149+
x=498, y=2..4\n\
150+
x=506, y=1..2\n\
151+
x=498, y=10..13\n\
152+
x=504, y=10..13\n\
153+
y=13, x=498..504",
154+
part1: 57,
155+
part2: 29,
156+
},
157+
]);

crates/year2018/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,5 @@ utils::year!(2018 => year2018, ${
1818
14 => day14::Day14,
1919
15 => day15::Day15,
2020
16 => day16::Day16,
21+
17 => day17::Day17,
2122
});

0 commit comments

Comments
 (0)