2020-12-17 21:30:30 +01:00
#![ allow(incomplete_features) ]
#![ feature(test, const_generics, const_evaluatable_checked) ]
2020-12-17 14:04:05 +01:00
extern crate test ;
2020-12-17 14:51:05 +01:00
use aoc2020 ::{
common ::* , grid ::{ cell ::Cell , * }
} ;
2020-12-17 21:30:30 +01:00
use itertools ::Itertools ;
2020-12-17 14:04:05 +01:00
fn read_input ( ) -> String {
read_file ( 17 )
}
2020-12-17 21:30:30 +01:00
fn parse_input < const DIMS : usize , F : FnMut ( ( usize , usize ) ) -> PositionND < DIMS > + Copy > ( raw : & str , mut pos_gen : F ) -> Grid < DIMS , Cell > {
2020-12-17 14:13:02 +01:00
raw . lines ( )
. enumerate ( )
2020-12-17 21:30:30 +01:00
. flat_map ( move | ( y , l ) | {
l . bytes ( )
. enumerate ( )
. map ( move | ( x , b ) | ( PositionND ::< DIMS > ::from_padded ( & [ x as i64 , y as i64 ] ) , b . into ( ) ) )
} )
2020-12-17 16:22:26 +01:00
. filter ( | ( _ , c ) | c = = & Cell ::Alive )
2020-12-17 14:13:02 +01:00
. collect ( )
2020-12-17 14:04:05 +01:00
}
2020-12-17 21:30:30 +01:00
fn count_live_neighbors < const D : usize > ( p : PositionND < D > , grid : & Grid < D , Cell > ) -> usize {
2020-12-17 16:22:26 +01:00
p . neighbors ( ) . iter ( ) . filter ( | & n | grid . get ( n ) = = Cell ::Alive ) . count ( )
2020-12-17 14:04:05 +01:00
}
2020-12-17 21:30:30 +01:00
fn make_step < const D : usize > ( input : Grid < D , Cell > ) -> Grid < D , Cell > {
2020-12-17 14:04:05 +01:00
let readonly = input . clone ( ) ;
2020-12-17 14:13:02 +01:00
input
. fields
. keys ( )
2020-12-17 21:30:30 +01:00
. flat_map ( | p | p . neighbors ( ) . iter ( ) )
2020-12-17 17:17:00 +01:00
. unique ( )
2020-12-17 14:13:02 +01:00
. map ( | pos | {
2020-12-17 16:22:26 +01:00
let cell = readonly . get ( & pos ) ;
2020-12-17 21:30:30 +01:00
let new = match ( & cell , count_live_neighbors ::< D > ( & pos , & readonly ) ) {
2020-12-17 14:13:02 +01:00
( Cell ::Alive , 2 ..= 3 ) = > Cell ::Alive ,
( Cell ::Dead , 3 ) = > Cell ::Alive ,
_ = > Cell ::Dead ,
} ;
( pos , new )
} )
2020-12-17 16:22:26 +01:00
. filter ( | ( _ , c ) | c = = & Cell ::Alive )
2020-12-17 14:13:02 +01:00
. collect ( )
2020-12-17 14:04:05 +01:00
}
2020-12-17 21:30:30 +01:00
fn solve < const D : usize > ( parsed : & Grid < D , Cell > , steps : usize ) -> usize {
2020-12-17 14:04:05 +01:00
let mut clone = parsed . clone ( ) ;
2020-12-17 15:15:51 +01:00
for _ in 0 .. steps {
2020-12-17 14:04:05 +01:00
clone = make_step ( clone ) ;
}
clone . fields . into_iter ( ) . filter ( | ( _ , c ) | c = = & Cell ::Alive ) . count ( )
}
fn main ( ) {
2020-12-17 15:15:51 +01:00
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 ) ) ;
2020-12-17 14:04:05 +01:00
}
#[ cfg(test) ]
mod tests {
use super ::* ;
use aoc2020 ::* ;
use test ::black_box ;
const TEST_INPUT : & str = " .#.
.. #
###" ;
2020-12-17 15:15:51 +01:00
#[ 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 ( ) ;
2020-12-17 16:22:26 +01:00
b . iter ( | | assert_eq! ( parse_input ( black_box ( & raw ) , | ( x , y ) | Position3D ::from ( ( x , y , 0 ) ) ) . fields . len ( ) , 43 ) ) ;
2020-12-17 15:15:51 +01:00
}
#[ bench ]
#[ rustfmt::skip ]
fn bench_4d_parse ( b : & mut test ::Bencher ) {
let raw = read_input ( ) ;
2020-12-17 16:22:26 +01:00
b . iter ( | | assert_eq! ( parse_input ( black_box ( & raw ) , | ( x , y ) | Position4D ::from ( ( x , y , 0 , 0 ) ) ) . fields . len ( ) , 43 ) ) ;
2020-12-17 15:15:51 +01:00
}
#[ 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 ) ) ;
}
2020-12-17 14:04:05 +01:00
}