1use crate::util::grid::*;
17use crate::util::hash::*;
18use crate::util::point::*;
19use State::*;
20
21type Input = (u32, u32);
22
23struct Graph {
24 grid: Grid<u8>,
25 seen: Grid<[bool; 2]>,
26 state: Grid<State>,
27 stack: Vec<usize>,
28 nodes: Vec<Node>,
29}
30
31struct Node {
32 tiles: BitSet,
33 from: FastSet<Point>,
34 to: FastSet<Point>,
35}
36
37impl Node {
38 fn new() -> Self {
39 Node { tiles: BitSet::new(), from: FastSet::new(), to: FastSet::new() }
40 }
41}
42
43struct BitSet {
45 bits: [u64; 190],
46}
47
48impl BitSet {
49 fn new() -> Self {
50 BitSet { bits: [0; 190] }
51 }
52
53 fn insert(&mut self, position: Point) {
54 let index = (110 * position.y + position.x) as usize;
55 let base = index / 64;
56 let offset = index % 64;
57 self.bits[base] |= 1 << offset;
58 }
59
60 fn union(&mut self, other: &BitSet) {
61 self.bits.iter_mut().zip(&other.bits).for_each(|(a, b)| *a |= b);
62 }
63
64 fn size(&self) -> u32 {
65 self.bits.iter().map(|&b| b.count_ones()).sum()
66 }
67}
68
69#[derive(Clone, Copy)]
71enum State {
72 Todo,
73 OnStack(usize),
74 Done(usize),
75}
76
77pub fn parse(input: &str) -> Input {
79 let grid = Grid::parse(input);
80 let width = grid.width;
81 let height = grid.height;
82
83 let graph = &mut Graph {
84 grid,
85 seen: Grid::new(width, height, [false; 2]),
86 state: Grid::new(width, height, Todo),
87 stack: Vec::new(),
88 nodes: Vec::new(),
89 };
90
91 let part_one = follow(graph, ORIGIN, RIGHT);
92 let mut part_two = part_one;
93
94 for x in 0..width {
95 part_two = part_two.max(follow(graph, Point::new(x, 0), DOWN));
96 part_two = part_two.max(follow(graph, Point::new(x, height - 1), UP));
97 }
98
99 for y in 0..height {
100 part_two = part_two.max(follow(graph, Point::new(0, y), RIGHT));
101 part_two = part_two.max(follow(graph, Point::new(width - 1, y), LEFT));
102 }
103
104 (part_one, part_two)
105}
106
107pub fn part1(input: &Input) -> u32 {
108 input.0
109}
110
111pub fn part2(input: &Input) -> u32 {
112 input.1
113}
114
115fn follow(graph: &mut Graph, mut position: Point, mut direction: Point) -> u32 {
121 let mut node = Node::new();
122
123 while graph.grid.contains(position) {
124 match graph.grid[position] {
125 b'|' | b'-' => {
127 let index = match graph.state[position] {
128 Todo => strong_connect(graph, position),
129 Done(index) => index,
130 OnStack(_) => unreachable!(),
131 };
132 node.tiles.union(&graph.nodes[index].tiles);
133 break;
134 }
135 b'\\' => direction = Point::new(direction.y, direction.x),
137 b'/' => direction = Point::new(-direction.y, -direction.x),
138 _ => {
141 let index = (direction == LEFT || direction == RIGHT) as usize;
142 if graph.seen[position][index] {
143 return 0;
144 }
145 }
146 }
147
148 node.tiles.insert(position);
149 position += direction;
150 }
151
152 node.tiles.size()
153}
154
155fn beam(graph: &mut Graph, node: &mut Node, mut position: Point, mut direction: Point) {
157 while graph.grid.contains(position) {
158 match graph.grid[position] {
159 b'|' => {
160 if direction == UP || direction == DOWN {
163 node.from.insert(position);
164 } else {
165 node.to.insert(position);
166 break;
167 }
168 }
169 b'-' => {
170 if direction == LEFT || direction == RIGHT {
171 node.from.insert(position);
172 } else {
173 node.to.insert(position);
174 break;
175 }
176 }
177 b'\\' => direction = Point::new(direction.y, direction.x),
179 b'/' => direction = Point::new(-direction.y, -direction.x),
180 _ => {
184 let index = (direction == LEFT || direction == RIGHT) as usize;
185 if graph.seen[position][index] {
186 break;
187 }
188 graph.seen[position][index] = true;
189 }
190 }
191
192 node.tiles.insert(position);
193 position += direction;
194 }
195}
196
197fn strong_connect(graph: &mut Graph, position: Point) -> usize {
199 let index = graph.nodes.len();
202 graph.stack.push(index);
203 graph.nodes.push(Node::new());
204
205 let mut node = Node::new();
208
209 if graph.grid[position] == b'|' {
210 beam(graph, &mut node, position, UP);
211 beam(graph, &mut node, position + DOWN, DOWN);
212 } else {
213 beam(graph, &mut node, position, LEFT);
214 beam(graph, &mut node, position + RIGHT, RIGHT);
215 }
216
217 node.from.iter().for_each(|&p| graph.state[p] = OnStack(index));
219
220 let mut lowlink = index;
222
223 for &next in &node.to {
224 match graph.state[next] {
225 Todo => lowlink = lowlink.min(strong_connect(graph, next)),
226 OnStack(other) => lowlink = lowlink.min(other),
227 Done(_) => (),
228 }
229 }
230
231 if lowlink == index {
233 while let Some(next) = graph.stack.pop()
235 && next != index
236 {
237 let other = &graph.nodes[next];
238 node.tiles.union(&other.tiles);
239 node.from.extend(&other.from);
240 node.to.extend(&other.to);
241 }
242
243 node.from.iter().for_each(|&p| graph.state[p] = Done(index));
245
246 for &next in node.to.difference(&node.from) {
248 if let Done(other) = graph.state[next] {
249 node.tiles.union(&graph.nodes[other].tiles);
250 }
251 }
252 }
253
254 graph.nodes[index] = node;
256 lowlink
257}