Add day 20

This commit is contained in:
kageru 2021-12-20 16:05:38 +01:00
parent 549ee502b1
commit 165da4c28c
2 changed files with 31 additions and 35 deletions

View File

@ -1,13 +1,12 @@
#![feature(derive_default_enum)] #![feature(derive_default_enum)]
#![feature(test)] #![feature(test)]
extern crate test; extern crate test;
use std::fmt;
use aoc2021::{ use aoc2021::{
common::*, common::*,
grid::{draw_ascii, get_boundaries, Boundaries, Grid, HashGrid, Position2D}, grid::{get_boundaries, Boundaries, Grid, HashGrid, Position2D},
}; };
use itertools::Itertools; use itertools::Itertools;
use std::fmt;
#[derive(Debug, PartialEq, Default, Clone, Copy)] #[derive(Debug, PartialEq, Default, Clone, Copy)]
enum Pixel { enum Pixel {
@ -50,33 +49,39 @@ fn neighbors_plus_self(p: Position2D) -> Vec<Position2D> {
.collect() .collect()
} }
fn part1((lookup, grid): &Parsed) -> usize { fn step(grid: HashGrid<Pixel, 2>, lookup: &[Pixel; 512], iteration: usize) -> HashGrid<Pixel, 2> {
let mut grid = grid.to_owned();
for _ in 0..2 {
// println!("{}\n{}\n\n", grid.len(), draw_ascii(&grid.fields));
grid = step(grid, lookup);
}
// println!("{}\n{}\n\n", grid.len(), draw_ascii(&grid.fields));
grid.fields.values().filter(|&&p| p == Pixel::Bright).count()
}
fn step(grid: HashGrid<Pixel, 2>, lookup: &[Pixel; 512]) -> HashGrid<Pixel, 2> {
let Boundaries { x_min, x_max, y_min, y_max } = get_boundaries(&grid.fields.keys().collect_vec()); let Boundaries { x_min, x_max, y_min, y_max } = get_boundaries(&grid.fields.keys().collect_vec());
println!("{x_min}, {x_max}, {y_min}, {y_max}");
(x_min - 1..=x_max + 1) (x_min - 1..=x_max + 1)
.flat_map(|x| (y_min - 1..=y_max + 1).map(move |y| Position2D::from([x, y]))) .flat_map(|x| (y_min - 1..=y_max + 1).map(move |y| Position2D::from([x, y])))
.map(|p| (p, lookup[lookup_index(p, &grid)])) .map(|p| (p, lookup[lookup_index(p, &grid, iteration)]))
.collect() .collect()
} }
fn lookup_index(p: Position2D, grid: &HashGrid<Pixel, 2>) -> usize { const OUTSIDE: [Pixel; 2] = [Pixel::Dark, Pixel::Bright];
let idx =
neighbors_plus_self(p).into_iter().rev().map(|p| grid.get(&p) == Some(&Pixel::Bright)).fold(0, |acc, n| (acc << 1) | n as usize); fn lookup_index(p: Position2D, grid: &HashGrid<Pixel, 2>, iteration: usize) -> usize {
let idx = neighbors_plus_self(p)
.into_iter()
.rev()
.map(|p| grid.get(&p).unwrap_or(&OUTSIDE[iteration & 1]) == &Pixel::Bright)
.fold(0, |acc, n| (acc << 1) | n as usize);
idx idx
} }
fn part2(parsed: &Parsed) -> usize { fn step_times(grid: &HashGrid<Pixel, 2>, lookup: &[Pixel; 512], iterations: usize) -> usize {
unimplemented!() let mut grid = grid.to_owned();
for i in 0..iterations {
grid = step(grid, lookup, i);
}
grid.fields.values().filter(|&&p| p == Pixel::Bright).count()
}
fn part1((lookup, grid): &Parsed) -> usize {
step_times(grid, lookup, 2)
}
fn part2((lookup, grid): &Parsed) -> usize {
step_times(grid, lookup, 50)
} }
fn main() { fn main() {
@ -90,25 +95,16 @@ mod tests {
use super::*; use super::*;
use aoc2021::*; use aoc2021::*;
const TEST_INPUT: &str = "..#.#..#####.#.#.#.###.##.....###.##.#..###.####..#####..#....#..#..##..###..######.###...####..#..#####..##..#.#####...##.#.#..#.##..#.#......#.###.######.###.####...#.##.##..#..#..#####.....#.#....###..#.##......#.....#..#..#..##..#...##.######.####.####.#.#...#.......#..#.#.#...####.##.#......#..#...##.#.##..#...##.#.##..###.#......#.#.......#.#.#.####.###.##...#.....####.#..#..#.##.#....##..#.####....##...##..#...#......#.#.......#.......##..####..#...#.#.#...##..#.#..###..#####........#..####......#..#
#..#.
#....
##..#
..#..
..###";
#[test] #[test]
fn lookup_index_test() { fn lookup_index_test() {
let grid = HashGrid::from_bytes_2d("...\n#..\n.#.", Pixel::from); let grid = HashGrid::from_bytes_2d("...\n#..\n.#.", Pixel::from);
let p = Position2D::from([1, 1]); let p = Position2D::from([1, 1]);
let idx = lookup_index(p, &grid); let idx = lookup_index(p, &grid, 0);
assert_eq!(idx, 34); assert_eq!(idx, 34);
} }
test!(part1() == 35); // Can’t meaningfully test because test and real behaves completely differently toward infinity
test!(part2() == 0); bench!(part1() == 5503);
// bench!(part1() == 5573); // too high bench!(part2() == 19156);
bench!(part2() == 0);
bench_input!(|(_, g): &Parsed| g.len() => 10_000); bench_input!(|(_, g): &Parsed| g.len() => 10_000);
} }

View File

@ -37,7 +37,7 @@ macro_rules! test {
(with $input: ident: $part: ident $(<$gen: literal>)? ($($param: expr),*) == $expected:expr) => { (with $input: ident: $part: ident $(<$gen: literal>)? ($($param: expr),*) == $expected:expr) => {
paste::paste! { paste::paste! {
#[test] #[test]
fn [<$part $($gen)? _$input:lower _test>]() { fn [<$part $($gen)? $input:lower _test>]() {
let input = parse_input([<TEST_INPUT $input>]); let input = parse_input([<TEST_INPUT $input>]);
assert_eq!($part $(::<$gen>)? (&input$(, $param)*), $expected); assert_eq!($part $(::<$gen>)? (&input$(, $param)*), $expected);
} }