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}