parent
a06c73a488
commit
c6b1ec262f
|
@ -4,6 +4,7 @@ version = "0.1.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
impl_ops = "0.1.1"
|
||||||
itertools = "0.10"
|
itertools = "0.10"
|
||||||
paste = "1.0"
|
paste = "1.0"
|
||||||
|
|
||||||
|
|
|
@ -60,7 +60,8 @@ fn part2(parsed: &Parsed) -> usize {
|
||||||
basins.sort_unstable_by_key(HashSet::len);
|
basins.sort_unstable_by_key(HashSet::len);
|
||||||
basins.reverse();
|
basins.reverse();
|
||||||
println!("{basins:?}");
|
println!("{basins:?}");
|
||||||
basins.iter().take(3).map(|b| b.len()).product()
|
// basins.iter().take(3).map(|b| b.len()).product();
|
||||||
|
unimplemented!()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
@ -81,7 +82,7 @@ mod tests {
|
||||||
9899965678";
|
9899965678";
|
||||||
|
|
||||||
test!(part1() == 15);
|
test!(part1() == 15);
|
||||||
test!(part2() == 1134);
|
// test!(part2() == 1134);
|
||||||
bench!(part1() == 478);
|
bench!(part1() == 478);
|
||||||
// bench!(part2() == 0);
|
// bench!(part2() == 0);
|
||||||
bench_input!(Vec::len => 100);
|
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};
|
use std::{collections::HashMap, fmt::Display, hash::BuildHasher};
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[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>,
|
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 {
|
pub fn get(&self, pos: &PositionND<D>) -> T {
|
||||||
self.fields.get(pos).copied().unwrap_or_else(T::default)
|
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) {
|
pub fn insert<Pos: Into<PositionND<D>>>(&mut self, pos: Pos, t: T) {
|
||||||
self.fields.insert(pos.into(), 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 {
|
fn from_iter<I: IntoIterator<Item = (PositionND<D>, T)>>(iter: I) -> Self {
|
||||||
Grid {
|
Grid { fields: iter.into_iter().collect() }
|
||||||
fields: iter.into_iter().collect(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
extern crate test;
|
extern crate test;
|
||||||
use super::direction::*;
|
use super::direction::*;
|
||||||
use lazy_static::lazy_static;
|
|
||||||
use std::{
|
use std::{
|
||||||
convert::TryInto, hash::Hash, ops::{Add, Mul, Sub}
|
convert::TryInto,
|
||||||
|
hash::Hash,
|
||||||
|
ops::{Add, Mul, Sub},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub trait Position
|
pub trait Position
|
||||||
|
@ -16,7 +17,7 @@ pub struct PositionND<const DIMS: usize> {
|
||||||
pub points: [i64; DIMS],
|
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
|
where I: TryInto<i64> + Copy
|
||||||
{
|
{
|
||||||
fn from(s: [I; D]) -> Self {
|
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)]
|
pub fn neighbors(&self) -> [PositionND<DIMS>; num_neighbors(DIMS)]
|
||||||
where [PositionND<DIMS>; num_neighbors(DIMS) + 1]: Sized {
|
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 ns = neighbor_vectors::<DIMS>();
|
||||||
let mut out = [*self; num_neighbors(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])) {
|
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_export]
|
||||||
macro_rules! dim {
|
macro_rules! dim {
|
||||||
($d: expr) => {{
|
($d: expr) => {{
|
||||||
|
|
|
@ -1,3 +1,7 @@
|
||||||
|
#![allow(incomplete_features)]
|
||||||
|
#![feature(generic_const_exprs)]
|
||||||
#![feature(associated_type_bounds)]
|
#![feature(associated_type_bounds)]
|
||||||
|
#![feature(test)]
|
||||||
pub mod common;
|
pub mod common;
|
||||||
pub mod teststuff;
|
pub mod teststuff;
|
||||||
|
pub mod grid;
|
||||||
|
|
Loading…
Reference in New Issue
Block a user