use std::io::Read; use std::mem::swap; use bytecount::naive_count_32; use crate::common::read_char_grid; use crate::Solution; fn neighbours(grid: &[Vec], r: usize, c: usize) -> usize { let mut n = 0; if r > 0 { let range = c.saturating_sub(1)..grid[r - 1].len().min(c + 2); n += naive_count_32(&grid[r - 1][range], b'#'); } if r < grid.len() - 1 { let range = c.saturating_sub(1)..grid[r + 1].len().min(c + 2); n += naive_count_32(&grid[r + 1][range], b'#'); } if c > 0 && grid[r][c - 1] == b'#' { n += 1; } if c < grid[r].len() - 1 && grid[r][c + 1] == b'#' { n += 1; } n } fn neighbours2(grid: &[Vec], r: usize, c: usize) -> usize { let mut n = 0; let directions = [ (-1, -1), (-1, 0), (-1, 1), (0, -1), (0, 1), (1, -1), (1, 0), (1, 1), ]; let r = r as isize; let c = c as isize; for &(dr, dc) in &directions { let mut nr = r + dr; let mut nc = c + dc; // Don't write conditions like this kids while nr >= 0 && nr < (grid.len() as isize) && nc >= 0 && nc < (grid[nr as usize].len() as isize) { match grid[nr as usize][nc as usize] { b'#' => { n += 1; break; } b'L' => break, _ => { nr += dr; nc += dc; } } } } n } #[allow(unused)] fn print(grid: &[Vec]) { for line in grid { let s: String = line.iter().map(|&c| c as char).collect(); println!("{}", s); } } #[derive(Default)] pub struct Day11; impl Solution for Day11 { fn part1(&mut self, input: &mut dyn Read) -> String { let mut state = read_char_grid(input); let mut next = state.clone(); loop { for (r, row) in state.iter().enumerate() { for (c, s) in row.iter().enumerate() { let e = match *s { b'#' if neighbours(&state, r, c) >= 4 => b'L', b'L' if neighbours(&state, r, c) == 0 => b'#', s => s, }; next[r][c] = e; } } if state == next { return state .iter() .flatten() .filter(|&&s| s == b'#') .count() .to_string(); } swap(&mut state, &mut next); } } fn part2(&mut self, input: &mut dyn Read) -> String { let mut state = read_char_grid(input); let mut next = state.clone(); loop { for (r, row) in state.iter().enumerate() { for (c, s) in row.iter().enumerate() { let e = match *s { b'#' if neighbours2(&state, r, c) >= 5 => b'L', b'L' if neighbours2(&state, r, c) == 0 => b'#', s => s, }; next[r][c] = e; } } if state == next { return state .iter() .flatten() .filter(|&&s| s == b'#') .count() .to_string(); } swap(&mut state, &mut next); } } } #[cfg(test)] mod tests { use crate::test_implementation; use super::*; const SAMPLE: &[u8] = include_bytes!("../samples/11.txt"); #[test] fn sample_part1() { test_implementation!(Day11, 1, SAMPLE, 37); } #[test] fn sample_part2() { test_implementation!(Day11, 2, SAMPLE, 26); } }