Files
adventofcode/2020/src/day11.rs

168 lines
3.8 KiB
Rust

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<u8>], 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<u8>], 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<u8>]) {
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);
}
}