1use std::iter::repeat_n;
10
11pub struct Input {
12 rules: Vec<usize>,
13 state: Tunnel,
14}
15
16#[derive(Clone)]
17pub struct Tunnel {
18 plants: Vec<usize>,
19 start: i64,
20 sum: i64,
21}
22
23pub fn parse(input: &str) -> Input {
24 let lines: Vec<_> = input.lines().map(str::as_bytes).collect();
25 let plants: Vec<_> = lines[0][15..].iter().map(|b| (b & 1) as usize).collect();
27 let mut rules = vec![0; 32];
29
30 for line in &lines[2..] {
32 let binary = line.iter().fold(0, |acc, b| (acc << 1) | (b & 1) as usize);
33 rules[binary >> 5] = binary & 1;
34 }
35
36 Input { rules, state: Tunnel { plants, start: 0, sum: 0 } }
37}
38
39pub fn part1(input: &Input) -> i64 {
40 let mut current = input.state.clone();
41
42 for _ in 0..20 {
43 current = step(&input.rules, ¤t);
44 }
45
46 current.sum
47}
48
49pub fn part2(input: &Input) -> i64 {
50 let mut current = input.state.clone();
51 let mut delta = 0;
52 let mut generations = 0;
53
54 loop {
55 let next = step(&input.rules, ¤t);
56 let next_delta = next.sum - current.sum;
57
58 if delta == next_delta {
60 break current.sum + delta * (50_000_000_000 - generations);
61 }
62
63 current = next;
64 delta = next_delta;
65 generations += 1;
66 }
67}
68
69fn step(rules: &[usize], tunnel: &Tunnel) -> Tunnel {
70 let mut index = 0;
71 let mut sum = 0;
72 let mut position = tunnel.start - 2;
73 let mut plants = Vec::with_capacity(1_000);
74
75 for plant in tunnel.plants.iter().copied().chain(repeat_n(0, 4)) {
77 index = ((index << 1) | plant) & 0b11111;
78
79 sum += position * rules[index] as i64;
80 position += 1;
81
82 plants.push(rules[index]);
83 }
84
85 Tunnel { plants, start: tunnel.start - 2, sum }
87}