use std::fmt::Display; use std::io::Read; use std::ops::Index; use crate::common::BitSet; type Translation = [bool; 512]; struct Field { width: usize, height: usize, infinity: bool, finite: BitSet, } impl Field { pub fn from_input<'a>(input: impl Iterator) -> Self { let mut input = input.peekable(); let width = input.peek().unwrap().len(); let mut finite = BitSet::new(); let len = input .flatten() .enumerate() .map(|(index, &c)| { if c == b'#' { finite.insert(index); } }) .count(); debug_assert_eq!(len % width, 0); let height = len / width; Self { width, height, finite, infinity: false, } } pub fn advance(&mut self, translation: &[bool; 512]) { const INDEX_MASK: usize = (1 << 9) - 1; let new_width = self.width + 2; let new_height = self.height + 2; let mut new_finite = BitSet::with_capacity(new_width * new_height); for y in 0..new_height { let mut mask = if self.infinity { INDEX_MASK } else { 0 }; for x in 0..new_width { const COLUMN_MASK: usize = 0b001001001; let mut submask = if self.infinity { COLUMN_MASK } else { 0 }; for y in y.saturating_sub(2)..=y { submask = (submask << 3) | (self[(x, y)] as usize); } mask <<= 1; mask &= !COLUMN_MASK; mask |= submask; mask &= INDEX_MASK; if translation[mask] { let index = x + y * new_width; new_finite.insert(index); } } } self.width += 2; self.height += 2; self.finite = new_finite; self.infinity = translation[if self.infinity { INDEX_MASK } else { 0 }]; } pub fn len(&self) -> usize { assert!(!self.infinity); self.finite.len() } } impl Index<(usize, usize)> for Field { type Output = bool; #[inline] fn index(&self, (x, y): (usize, usize)) -> &Self::Output { if x >= self.width || y >= self.height { return &self.infinity; } let index = x + y * self.width; if self.finite.contains(index) { &true } else { &false } } } impl Display for Field { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { for y in 0..self.height { for x in 0..self.width { if self[(x, y)] { write!(f, "#")? } else { write!(f, ".")? } } writeln!(f)?; } Ok(()) } } fn read_input(input: &mut dyn Read) -> (Translation, Field) { let mut buffer = Vec::new(); input.read_to_end(&mut buffer).unwrap(); let mut translation = [false; 512]; let mut it = buffer.split(|&b| b == b'\n'); translation .iter_mut() .zip(it.next().unwrap()) .for_each(|(t, &c)| *t = c == b'#'); let field = Field::from_input(it.skip(1)); (translation, field) } fn parts_common(input: &mut dyn Read, count: usize) -> String { let (translation, mut field) = read_input(input); for _ in 0..count { field.advance(&translation); } field.len().to_string() } pub fn part1(input: &mut dyn Read) -> String { parts_common(input, 2) } pub fn part2(input: &mut dyn Read) -> String { parts_common(input, 50) } #[cfg(test)] mod tests { use crate::test_implementation; use super::*; const SAMPLE: &[u8] = include_bytes!("samples/20.txt"); #[test] fn sample_part1() { test_implementation(part1, SAMPLE, 35); } #[test] fn sample_part2() { test_implementation(part2, SAMPLE, 3351); } }