parent
a06c73a488
commit
c6b1ec262f
|
@ -4,6 +4,7 @@ version = "0.1.0"
|
|||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
impl_ops = "0.1.1"
|
||||
itertools = "0.10"
|
||||
paste = "1.0"
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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<u8, 2>;
|
||||
|
||||
fn parse_input(raw: &str) -> Parsed {
|
||||
Grid::<u8, 2>::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<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 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);
|
||||
}
|
|
@ -8,11 +8,11 @@ use itertools::join;
|
|||
use std::{collections::HashMap, fmt::Display, hash::BuildHasher};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct Grid<const D: usize, T: Display + Default> {
|
||||
pub struct Grid<T: Default, const D: usize> {
|
||||
pub fields: HashMap<PositionND<D>, T>,
|
||||
}
|
||||
|
||||
impl<const D: usize, T: Display + Default + Copy> Grid<D, T> {
|
||||
impl<T: Default + Copy, const D: usize> Grid<T, D> {
|
||||
pub fn get(&self, pos: &PositionND<D>) -> T {
|
||||
self.fields.get(pos).copied().unwrap_or_else(T::default)
|
||||
}
|
||||
|
@ -20,13 +20,22 @@ impl<const D: usize, T: Display + Default + Copy> Grid<D, T> {
|
|||
pub fn insert<Pos: Into<PositionND<D>>>(&mut self, pos: Pos, t: T) {
|
||||
self.fields.insert(pos.into(), t);
|
||||
}
|
||||
|
||||
pub fn from_bytes_2d<F: FnMut(u8) -> T + Copy>(raw: &str, mut f: F) -> Grid<T, 2> {
|
||||
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<const D: usize, T: Display + Default> std::iter::FromIterator<(PositionND<D>, T)> for Grid<D, T> {
|
||||
impl<T: Default, const D: usize> std::iter::FromIterator<(PositionND<D>, T)> for Grid<T, D> {
|
||||
fn from_iter<I: IntoIterator<Item = (PositionND<D>, T)>>(iter: I) -> Self {
|
||||
Grid {
|
||||
fields: iter.into_iter().collect(),
|
||||
}
|
||||
Grid { fields: iter.into_iter().collect() }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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<const DIMS: usize> {
|
|||
pub points: [i64; DIMS],
|
||||
}
|
||||
|
||||
impl<const D: usize, I> From<[I; D]> for PositionND<D>
|
||||
impl<I, const D: usize> From<[I; D]> for PositionND<D>
|
||||
where I: TryInto<i64> + Copy
|
||||
{
|
||||
fn from(s: [I; D]) -> Self {
|
||||
|
@ -56,40 +57,6 @@ impl<const DIMS: usize> PositionND<DIMS> {
|
|||
|
||||
pub fn neighbors(&self) -> [PositionND<DIMS>; num_neighbors(DIMS)]
|
||||
where [PositionND<DIMS>; 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::<DIMS>();
|
||||
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<const DIMS: usize> PositionND<DIMS> {
|
|||
}
|
||||
}
|
||||
|
||||
fn build_neighbor_cache<const D: usize>() -> Vec<[i64; D]>
|
||||
where [(); num_neighbors(D) + 1]: {
|
||||
IntoIterator::into_iter(neighbor_vectors::<D>()).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) => {{
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue
Block a user