diff --git a/2021/Cargo.toml b/2021/Cargo.toml index ce383da..1e77142 100644 --- a/2021/Cargo.toml +++ b/2021/Cargo.toml @@ -4,6 +4,7 @@ version = "0.1.0" edition = "2021" [dependencies] +impl_ops = "0.1.1" itertools = "0.10" paste = "1.0" diff --git a/2021/src/bin/day09.rs b/2021/src/bin/day09.rs index bbb38f3..49659ac 100644 --- a/2021/src/bin/day09.rs +++ b/2021/src/bin/day09.rs @@ -60,7 +60,8 @@ fn part2(parsed: &Parsed) -> usize { basins.sort_unstable_by_key(HashSet::len); basins.reverse(); println!("{basins:?}"); - basins.iter().take(3).map(|b| b.len()).product() + // basins.iter().take(3).map(|b| b.len()).product(); + unimplemented!() } fn main() { @@ -81,7 +82,7 @@ mod tests { 9899965678"; test!(part1() == 15); - test!(part2() == 1134); + // test!(part2() == 1134); bench!(part1() == 478); // bench!(part2() == 0); bench_input!(Vec::len => 100); diff --git a/2021/src/bin/day11.rs b/2021/src/bin/day11.rs new file mode 100644 index 0000000..19b759d --- /dev/null +++ b/2021/src/bin/day11.rs @@ -0,0 +1,103 @@ +#![feature(test)] +extern crate test; + +use std::time::Duration; + +use aoc2021::{ + common::*, + grid::{Grid, PositionND}, +}; + +const DAY: usize = 11; +const ROUNDS: usize = 100; +type Parsed = Grid; + +fn parse_input(raw: &str) -> Parsed { + Grid::::from_bytes_2d(raw, |b: u8| b - b'0') +} + +fn part1(parsed: &Parsed) -> usize { + let mut grid = parsed.to_owned(); + let mut flashed = Vec::new(); + let mut flashes = 0; + for _ in 0..ROUNDS { + for (p, energy) in grid.fields.iter_mut() { + *energy += 1; + if energy == &10 { + flashed.push(*p); + } + } + for p in flashed.clone() { + flash(&mut grid, p, &mut flashed); + } + flashes += flashed.len(); + for p in flashed.drain(..) { + *grid.fields.get_mut(&p).unwrap() = 0; + } + } + flashes +} + +fn flash(grid: &mut Parsed, position: PositionND<2>, flashed: &mut Vec>) { + 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 part2(parsed: &Parsed) -> usize { + let mut grid = parsed.to_owned(); + let mut flashed = Vec::new(); + for i in 1.. { + for (p, energy) in grid.fields.iter_mut() { + *energy += 1; + if energy == &10 { + flashed.push(*p); + } + } + for p in flashed.clone() { + flash(&mut grid, p, &mut flashed); + } + if flashed.len() == parsed.len() { + return i; + } + for p in flashed.drain(..) { + *grid.fields.get_mut(&p).unwrap() = 0; + } + } + unreachable!() +} + +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!(Grid::len => 100); +} diff --git a/2021/src/grid.rs b/2021/src/grid.rs index 347029b..5aa4d3b 100644 --- a/2021/src/grid.rs +++ b/2021/src/grid.rs @@ -8,11 +8,11 @@ use itertools::join; use std::{collections::HashMap, fmt::Display, hash::BuildHasher}; #[derive(Debug, Clone, PartialEq)] -pub struct Grid { +pub struct Grid { pub fields: HashMap, T>, } -impl Grid { +impl Grid { pub fn get(&self, pos: &PositionND) -> T { self.fields.get(pos).copied().unwrap_or_else(T::default) } @@ -20,13 +20,22 @@ impl Grid { pub fn insert>>(&mut self, pos: Pos, t: T) { self.fields.insert(pos.into(), t); } + + pub fn from_bytes_2d T + Copy>(raw: &str, mut f: F) -> Grid { + raw.lines() + .enumerate() + .flat_map(move |(y, l)| l.bytes().enumerate().map(move |(x, c)| (PositionND { points: [x as i64, y as i64] }, f(c)))) + .collect() + } + + pub fn len(&self) -> usize { + self.fields.len() + } } -impl std::iter::FromIterator<(PositionND, T)> for Grid { +impl std::iter::FromIterator<(PositionND, T)> for Grid { fn from_iter, T)>>(iter: I) -> Self { - Grid { - fields: iter.into_iter().collect(), - } + Grid { fields: iter.into_iter().collect() } } } diff --git a/2021/src/grid/position.rs b/2021/src/grid/position.rs index a995765..2fe8dde 100644 --- a/2021/src/grid/position.rs +++ b/2021/src/grid/position.rs @@ -1,8 +1,9 @@ extern crate test; use super::direction::*; -use lazy_static::lazy_static; use std::{ - convert::TryInto, hash::Hash, ops::{Add, Mul, Sub} + convert::TryInto, + hash::Hash, + ops::{Add, Mul, Sub}, }; pub trait Position @@ -16,7 +17,7 @@ pub struct PositionND { pub points: [i64; DIMS], } -impl From<[I; D]> for PositionND +impl From<[I; D]> for PositionND where I: TryInto + Copy { fn from(s: [I; D]) -> Self { @@ -56,40 +57,6 @@ impl PositionND { pub fn neighbors(&self) -> [PositionND; num_neighbors(DIMS)] where [PositionND; num_neighbors(DIMS) + 1]: Sized { - // Day 17 gets 25% faster if we cheat by using these cached vectors - if DIMS < 5 { - return match DIMS { - 1 => { - let mut out = [*self; num_neighbors(DIMS)]; - for (out, dir) in out.iter_mut().zip(NEIGHBOR_VECTORS_1D.iter()) { - *out = *out + PositionND::from_padded(dir); - } - out - } - 2 => { - let mut out = [*self; num_neighbors(DIMS)]; - for (out, dir) in out.iter_mut().zip(NEIGHBOR_VECTORS_2D.iter()) { - *out = *out + PositionND::from_padded(dir); - } - out - } - 3 => { - let mut out = [*self; num_neighbors(DIMS)]; - for (out, dir) in out.iter_mut().zip(NEIGHBOR_VECTORS_3D.iter()) { - *out = *out + PositionND::from_padded(dir); - } - out - } - 4 => { - let mut out = [*self; num_neighbors(DIMS)]; - for (out, dir) in out.iter_mut().zip(NEIGHBOR_VECTORS_4D.iter()) { - *out = *out + PositionND::from_padded(dir); - } - out - } - _ => unreachable!(), - }; - } let ns = neighbor_vectors::(); let mut out = [*self; num_neighbors(DIMS)]; for (out, dir) in out.iter_mut().zip(IntoIterator::into_iter(ns).filter(|n| n != &[0; DIMS])) { @@ -99,18 +66,6 @@ impl PositionND { } } -fn build_neighbor_cache() -> Vec<[i64; D]> -where [(); num_neighbors(D) + 1]: { - IntoIterator::into_iter(neighbor_vectors::()).filter(|n| n != &[0; D]).collect() -} - -lazy_static! { - static ref NEIGHBOR_VECTORS_1D: Vec<[i64; 1]> = build_neighbor_cache::<1>(); - static ref NEIGHBOR_VECTORS_2D: Vec<[i64; 2]> = build_neighbor_cache::<2>(); - static ref NEIGHBOR_VECTORS_3D: Vec<[i64; 3]> = build_neighbor_cache::<3>(); - static ref NEIGHBOR_VECTORS_4D: Vec<[i64; 4]> = build_neighbor_cache::<4>(); -} - #[macro_export] macro_rules! dim { ($d: expr) => {{ diff --git a/2021/src/lib.rs b/2021/src/lib.rs index 456a913..720542d 100644 --- a/2021/src/lib.rs +++ b/2021/src/lib.rs @@ -1,3 +1,7 @@ +#![allow(incomplete_features)] +#![feature(generic_const_exprs)] #![feature(associated_type_bounds)] +#![feature(test)] pub mod common; pub mod teststuff; +pub mod grid;