aoc/year2025/
day11.rs

1//! # Reactor
2type Input = Vec<Vec<usize>>;
3
4pub fn parse(input: &str) -> Input {
5    let mut graph = vec![vec![]; 26 * 26 * 26];
6
7    for line in input.lines() {
8        let mut edges = line.split_ascii_whitespace();
9        let from = edges.next().unwrap();
10        graph[to_index(from)].extend(edges.map(to_index));
11    }
12
13    graph
14}
15
16pub fn part1(input: &Input) -> u64 {
17    paths(input, "you", "out")
18}
19
20pub fn part2(input: &Input) -> u64 {
21    let one = paths(input, "svr", "fft") * paths(input, "fft", "dac") * paths(input, "dac", "out");
22    let two = paths(input, "svr", "dac") * paths(input, "dac", "fft") * paths(input, "fft", "out");
23    one + two
24}
25
26fn paths(input: &Input, from: &str, to: &str) -> u64 {
27    let mut cache = vec![u64::MAX; input.len()];
28    dfs(input, &mut cache, to_index(from), to_index(to))
29}
30
31fn dfs(input: &Input, cache: &mut [u64], node: usize, end: usize) -> u64 {
32    if node == end {
33        1
34    } else if cache[node] == u64::MAX {
35        let result = input[node].iter().map(|&next| dfs(input, cache, next, end)).sum();
36        cache[node] = result;
37        result
38    } else {
39        cache[node]
40    }
41}
42
43fn to_index(s: &str) -> usize {
44    s.bytes().take(3).fold(0, |acc, b| 26 * acc + usize::from(b - b'a'))
45}