1pub struct Input {
9 width: usize,
10 height: usize,
11 horizontal: Vec<u128>,
12 vertical: Vec<u128>,
13}
14
15pub fn parse(input: &str) -> Input {
16 let raw: Vec<_> = input.lines().map(|line| &line.as_bytes()[1..line.len() - 1]).collect();
18
19 let width = raw[0].len();
20 let height = raw.len() - 2;
21 let build = |kind| -> Vec<_> {
24 let fold = |row: &&[u8]| row.iter().fold(0, |acc, &b| (acc << 1) | (b != kind) as u128);
25 raw[1..=height].iter().map(fold).collect()
26 };
27 let left = build(b'<');
29 let right = build(b'>');
30 let up = build(b'^');
31 let down = build(b'v');
32
33 let mut horizontal = Vec::with_capacity(width * height);
36 for time in 0..width {
37 for i in 0..height {
38 let left = (left[i] << time) | (left[i] >> (width - time));
39 let right = (right[i] >> time) | (right[i] << (width - time));
40 horizontal.push(left & right);
41 }
42 }
43
44 let mut vertical = Vec::with_capacity(height * height);
46 for time in 0..height {
47 for i in 0..height {
48 let up = up[(i + time) % height];
49 let down = down[(height + i - time % height) % height];
50 vertical.push(up & down);
51 }
52 }
53
54 Input { width, height, horizontal, vertical }
55}
56
57pub fn part1(input: &Input) -> usize {
58 expedition(input, 0, true)
59}
60
61pub fn part2(input: &Input) -> usize {
62 let first = expedition(input, 0, true);
63 let second = expedition(input, first, false);
64 expedition(input, second, true)
65}
66
67fn expedition(input: &Input, start: usize, forward: bool) -> usize {
68 let Input { width, height, horizontal, vertical } = input;
69 let mut time = start;
70 let mut state = vec![0; height + 1];
71
72 loop {
73 time += 1;
74 let mut prev;
77 let mut cur = 0;
78 let mut next = state[0];
79
80 for i in 0..*height {
81 prev = cur;
82 cur = next;
83 next = state[i + 1];
84 state[i] = (cur | (cur >> 1) | (cur << 1) | prev | next)
87 & horizontal[height * (time % width) + i]
88 & vertical[height * (time % height) + i];
89 }
90
91 if forward {
93 state[0] |= 1 << (width - 1);
95 if state[height - 1] & 1 != 0 {
97 break time + 1;
98 }
99 } else {
100 state[height - 1] |= 1;
102 if state[0] & (1 << (width - 1)) != 0 {
104 break time + 1;
105 }
106 }
107 }
108}