1use utils::prelude::*;
2
3#[derive(Clone, Debug)]
5pub struct Day18 {
6 input: u128,
7 columns: u32,
8 input_type: InputType,
9}
10
11impl Day18 {
12 pub fn new(input: &str, input_type: InputType) -> Result<Self, InputError> {
13 if input.len() > 128 {
14 Err(InputError::new(input, input, "too many columns"))
15 } else if let Some(index) = input.find(|c| c != '.' && c != '^') {
16 Err(InputError::new(input, index, "expected '.' or '^'"))
17 } else {
18 Ok(Self {
19 input: input
20 .bytes()
21 .fold(0, |acc, b| (acc << 1) | u128::from(b == b'^')),
22 columns: input.len() as u32,
23 input_type,
24 })
25 }
26 }
27
28 #[must_use]
29 pub fn part1(&self) -> u32 {
30 self.count_safe(match self.input_type {
31 InputType::Example => 10,
32 InputType::Real => 40,
33 })
34 }
35
36 #[must_use]
37 pub fn part2(&self) -> u32 {
38 self.count_safe(400000)
39 }
40
41 #[inline]
42 fn count_safe(&self, rows: u32) -> u32 {
43 let mask = u128::MAX.wrapping_shr(128 - self.columns);
44
45 let mut row = self.input;
46 let mut traps = 0;
47 for _ in 0..rows {
48 traps += row.count_ones();
49
50 row = ((row << 1) ^ (row >> 1)) & mask;
53 }
54
55 (rows * self.columns) - traps
56 }
57}
58
59examples!(Day18 -> (u32, u32) [
60 {input: ".^^.^.^^^^", part1: 38},
61]);