1type Input = (usize, usize);
8
9struct Basin {
10 width: usize,
11 height: usize,
12 left: Vec<u64>,
13 right: Vec<u64>,
14 vertical: Vec<u64>,
15}
16
17pub fn parse(input: &str) -> Input {
18 let raw: Vec<_> = input.lines().map(str::as_bytes).collect();
20 let width = raw[0].len() - 2;
21 let height = raw.len() - 2;
22
23 let build = |kind| -> Vec<_> {
26 let fold = |x| (1..=height).fold(0, |acc, y| (acc << 1) | u64::from(raw[y][x] != kind));
27 (1..=width).map(fold).collect()
28 };
29
30 let left = build(b'<').repeat(2);
33 let right = build(b'>').repeat(2);
34
35 let up = build(b'^');
37 let down = build(b'v');
38 let mut vertical = Vec::with_capacity(height * width);
39
40 for time in 0..height {
41 for i in 0..width {
42 let up = (up[i] << time) | (up[i] >> (height - time));
43 let down = (down[i] >> time) | (down[i] << (height - time));
44 vertical.push(up & down);
45 }
46 }
47
48 let basin = Basin { width, height, left, right, vertical };
49 let first = expedition(&basin, 0, true);
50 let second = expedition(&basin, first, false);
51 let third = expedition(&basin, second, true);
52
53 (first, third)
54}
55
56pub fn part1(input: &Input) -> usize {
57 input.0
58}
59
60pub fn part2(input: &Input) -> usize {
61 input.1
62}
63
64fn expedition(basin: &Basin, start: usize, forward: bool) -> usize {
65 let Basin { width, height, left, right, vertical } = basin;
66 let mut state = vec![0; width + 1];
67
68 for time in start + 1.. {
69 let left = &left[time % width..];
71 let right = &right[width - time % width..];
72 let vertical = &vertical[width * (time % height)..];
73
74 let mut prev;
77 let mut cur = 0;
78 let mut next = state[0];
79
80 for i in 0..*width {
81 prev = cur;
82 cur = next;
83 next = state[i + 1];
84 state[i] =
87 (cur | (cur >> 1) | (cur << 1) | prev | next) & left[i] & right[i] & vertical[i];
88 }
89
90 if forward {
92 state[0] |= 1 << (height - 1);
94 if state[width - 1] & 1 != 0 {
96 return time + 1;
97 }
98 } else {
99 state[width - 1] |= 1;
101 if state[0] & (1 << (height - 1)) != 0 {
103 return time + 1;
104 }
105 }
106 }
107
108 unreachable!()
109}