advent-of-code/2021/src/bin/day11.rs

85 lines
1.8 KiB
Rust

#![feature(bool_to_option)]
#![feature(test)]
extern crate test;
use aoc2021::{
common::*,
grid::{Grid, HashGrid, PositionND},
};
const DAY: usize = 11;
const ROUNDS: usize = 100;
type Parsed = HashGrid<u8, 2>;
fn parse_input(raw: &str) -> Parsed {
HashGrid::<u8, 2>::from_bytes_2d(raw, |b: u8| b - b'0')
}
fn part1(parsed: &Parsed) -> usize {
let mut grid = parsed.to_owned();
(0..ROUNDS).map(|_| make_step(&mut grid)).sum()
}
fn part2(parsed: &Parsed) -> usize {
let mut grid = parsed.to_owned();
(0..).position(|_| make_step(&mut grid) == parsed.len()).unwrap() + 1
}
fn make_step(grid: &mut Parsed) -> usize {
let mut flashed: Vec<_> = grid
.fields
.iter_mut()
.filter_map(|(p, energy)| {
*energy += 1;
(*energy == 10).then_some(*p)
})
.collect();
for p in flashed.clone() {
flash(grid, &p, &mut flashed);
}
for p in &flashed {
*grid.fields.get_mut(p).unwrap() = 0;
}
flashed.len()
}
fn flash(grid: &mut Parsed, position: &PositionND<2>, flashed: &mut Vec<PositionND<2>>) {
for n in position.neighbors() {
if let Some(p) = grid.fields.get_mut(&n) {
*p += 1;
if p == &10 {
flashed.push(n);
flash(grid, &n, flashed);
}
}
}
}
fn main() {
let input = parse_input(&read_file(DAY));
println!("Part 1: {}", part1(&input));
println!("Part 2: {}", part2(&input));
}
#[cfg(test)]
mod tests {
use super::*;
use aoc2021::*;
const TEST_INPUT: &str = "5483143223
2745854711
5264556173
6141336146
6357385478
4167524645
2176841721
6882881134
4846848554
5283751526";
test!(part1() == 1656);
test!(part2() == 195);
bench!(part1() == 1741);
bench!(part2() == 440);
bench_input!(HashGrid::len => 100);
}