#![feature(test)] extern crate test; use aoc2020::{ common::*, grid::{cell::Cell, *} }; fn read_input() -> String { read_file(17) } fn parse_input P + Copy>(raw: &str, mut pos_gen: F) -> Grid { raw.lines() .enumerate() .flat_map(move |(y, l)| l.bytes().enumerate().map(move |(x, b)| (pos_gen((x, y)), b.into()))) .collect() } fn count_live_neighbors(p: &P, grid: &Grid) -> usize { p.neighbors().iter().filter(|&n| grid.get(*n) == Cell::Alive).count() } fn make_step(input: Grid) -> Grid { let readonly = input.clone(); input .fields .keys() .flat_map(|p| p.neighbors()) .map(|pos| { let cell = readonly.get(pos); let new = match (&cell, count_live_neighbors(&pos, &readonly)) { (Cell::Alive, 2..=3) => Cell::Alive, (Cell::Dead, 3) => Cell::Alive, _ => Cell::Dead, }; (pos, new) }) .collect() } fn solve(parsed: &Grid, steps: usize) -> usize { let mut clone = parsed.clone(); for _ in 0..steps { clone = make_step(clone); } clone.fields.into_iter().filter(|(_, c)| c == &Cell::Alive).count() } fn main() { let raw = read_input(); let input = parse_input(&raw, |(x, y)| Position3D::from((x, y, 0))); println!("Part 1: {}", solve(&input, 6)); let input = parse_input(&raw, |(x, y)| Position4D::from((x, y, 0, 0))); println!("Part 2: {}", solve(&input, 6)); } #[cfg(test)] mod tests { use super::*; use aoc2020::*; use test::black_box; const TEST_INPUT: &str = ".#. ..# ###"; #[test] fn test_3d() { let input = parse_input(TEST_INPUT, |(x, y)| Position3D::from((x, y, 0))); assert_eq!(solve(&input, 6), 112); } #[test] fn test_4d() { let input = parse_input(TEST_INPUT, |(x, y)| Position4D::from((x, y, 0, 0))); assert_eq!(solve(&input, 6), 848); } #[bench] fn bench_3d_parse(b: &mut test::Bencher) { let raw = read_input(); b.iter(|| assert_eq!(parse_input(black_box(&raw), |(x, y)| Position3D::from((x, y, 0))).fields.len(), 64)); } #[bench] #[rustfmt::skip] fn bench_4d_parse(b: &mut test::Bencher) { let raw = read_input(); b.iter(|| assert_eq!(parse_input(black_box(&raw), |(x, y)| Position4D::from((x, y, 0, 0))).fields.len(), 64)); } #[bench] fn bench_3d(b: &mut test::Bencher) { let input = parse_input(&read_input(), |(x, y)| Position3D::from((x, y, 0))); b.iter(|| assert_eq!(solve(&input, 6), 348)); } #[bench] fn bench_4d(b: &mut test::Bencher) { let input = parse_input(&read_input(), |(x, y)| Position4D::from((x, y, 0, 0))); b.iter(|| assert_eq!(solve(&input, 6), 2236)); } }