1use utils::bit::bitwise_count8;
2use utils::prelude::*;
3
4#[derive(Clone, Debug)]
6pub struct Day18 {
7    masks: [[u64; 52]; 2],
8}
9
10impl Day18 {
11    pub fn new(input: &str, _: InputType) -> Result<Self, InputError> {
12        let mut tree_mask = [0u64; 52];
14        let mut lumberyard_mask = [0u64; 52];
15
16        let mut row = 0;
17        for line in input.lines() {
18            if row >= 50 {
19                return Err(InputError::new(input, line, "too many rows"));
20            }
21            if line.len() > 50 {
22                return Err(InputError::new(input, line, "too many columns"));
23            }
24            for (col, b) in line.bytes().enumerate() {
25                match b {
26                    b'.' => {}
27                    b'|' => tree_mask[row + 1] |= 1 << (col + 1),
28                    b'#' => lumberyard_mask[row + 1] |= 1 << (col + 1),
29                    _ => {
30                        return Err(InputError::new(input, b as char, "expected '.', '|', '#'"));
31                    }
32                };
33            }
34            row += 1;
35        }
36
37        if row != 50 {
38            return Err(InputError::new(input, 0, "expected 50 rows"));
39        }
40
41        Ok(Self {
42            masks: [tree_mask, lumberyard_mask],
43        })
44    }
45
46    #[must_use]
47    pub fn part1(&self) -> u32 {
48        let mut masks = &mut self.masks.clone();
49        let mut temp = &mut [[0u64; _]; _];
50
51        for _ in 0..10 {
52            Self::advance(masks, temp);
53            (masks, temp) = (temp, masks);
54        }
55
56        Self::resource_value(masks)
57    }
58
59    #[must_use]
60    pub fn part2(&self) -> u32 {
61        let (mut power, mut lambda) = (1, 1);
63
64        let mut tortoise = &mut self.masks.clone();
65        let mut hare = &mut self.masks.clone();
66        let mut temp = &mut [[0u64; _]; _];
67
68        Self::advance(hare, temp);
69        (hare, temp) = (temp, hare);
70
71        while tortoise != hare {
72            if power == lambda {
73                *tortoise = *hare;
74                power *= 2;
75                lambda = 0;
76            }
77
78            Self::advance(hare, temp);
79            (hare, temp) = (temp, hare);
80
81            lambda += 1;
82        }
83
84        *tortoise = self.masks;
85        *hare = self.masks;
86        for _ in 0..lambda {
87            Self::advance(hare, temp);
88            (hare, temp) = (temp, hare);
89        }
90
91        let mut mu = 0;
92        while tortoise != hare {
93            Self::advance(tortoise, temp);
94            (tortoise, temp) = (temp, tortoise);
95
96            Self::advance(hare, temp);
97            (hare, temp) = (temp, hare);
98
99            mu += 1;
100        }
101
102        let mut minutes = 1_000_000_000 - mu;
103        minutes -= (minutes / lambda) * lambda;
104
105        while minutes > 0 {
106            Self::advance(hare, temp);
107            (hare, temp) = (temp, hare);
108
109            minutes -= 1;
110        }
111
112        Self::resource_value(hare)
113    }
114
115    #[inline(never)]
116    fn advance([trees, yards]: &[[u64; 52]; 2], [next_trees, next_yards]: &mut [[u64; 52]; 2]) {
117        const COLUMNS_MASK: u64 = ((1 << 50) - 1) << 1;
118
119        for row in 1..51 {
121            let (gte1_trees, gte3_trees) = Self::adjacent_gte1_gte3(trees, row);
122            let (gte1_yards, gte3_yards) = Self::adjacent_gte1_gte3(yards, row);
123
124            let open_to_trees = !trees[row] & !yards[row] & gte3_trees;
125            let trees_to_yard = trees[row] & gte3_yards;
126            let yard_to_open = yards[row] & !(gte1_trees & gte1_yards);
127
128            next_trees[row] = ((trees[row] & !trees_to_yard) | open_to_trees) & COLUMNS_MASK;
129            next_yards[row] = ((yards[row] & !yard_to_open) | trees_to_yard) & COLUMNS_MASK;
130        }
131    }
132
133    #[inline]
134    pub fn adjacent_gte1_gte3(mask: &[u64; 52], row: usize) -> (u64, u64) {
135        let adjacent = [
136            mask[row - 1] << 1,
137            mask[row - 1],
138            mask[row - 1] >> 1,
139            mask[row] << 1,
140            mask[row] >> 1,
141            mask[row + 1] << 1,
142            mask[row + 1],
143            mask[row + 1] >> 1,
144        ];
145
146        let [bit0, bit1, bit2, bit3] = bitwise_count8(&adjacent);
147        let gte1 = bit0 | bit1 | bit2 | bit3;
148        let gte3 = (bit0 & bit1) | bit2 | bit3;
149
150        (gte1, gte3)
151    }
152
153    #[inline]
154    fn resource_value([trees, yards]: &[[u64; 52]; 2]) -> u32 {
155        let tree_count = trees.iter().map(|m| m.count_ones()).sum::<u32>();
156        let yard_count = yards.iter().map(|m| m.count_ones()).sum::<u32>();
157        tree_count * yard_count
158    }
159}
160
161examples!(Day18 -> (u32, u32) []);