mirror of
https://github.com/bertptrs/adventofcode.git
synced 2025-12-25 21:00:31 +01:00
168 lines
3.8 KiB
Rust
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);
|
|
}
|
|
}
|