2020-12-17 21:30:30 +01:00
#![ allow(incomplete_features) ]
2021-11-22 14:34:40 +01:00
#![ feature(test, generic_const_exprs) ]
2020-12-17 14:04:05 +01:00
extern crate test ;
2020-12-17 14:51:05 +01:00
use aoc2020 ::{
2021-07-08 19:05:31 +02:00
common ::* , grid ::{ self , cell ::Cell , * }
2020-12-17 14:51:05 +01:00
} ;
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 )
}
2021-07-08 19:05:31 +02:00
fn parse_input < const DIMS : usize > ( raw : & str ) -> 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
}
2021-07-08 19:05:31 +02:00
fn count_live_neighbors < const D : usize > ( p : & PositionND < D > , grid : & Grid < D , Cell > ) -> usize
2021-07-08 22:17:14 +02:00
where [ ( ) ; grid ::num_neighbors ( D ) + 1 ] : Sized {
2021-07-08 19:05:31 +02:00
IntoIterator ::into_iter ( p . neighbors ( ) )
. filter ( | n | grid . get ( n ) = = Cell ::Alive )
. count ( )
2020-12-17 14:04:05 +01:00
}
2021-07-08 19:05:31 +02:00
fn make_step < const D : usize > ( input : Grid < D , Cell > ) -> Grid < D , Cell >
2021-07-08 22:17:14 +02:00
where [ ( ) ; grid ::num_neighbors ( D ) + 1 ] : Sized {
2020-12-17 14:04:05 +01:00
let readonly = input . clone ( ) ;
2020-12-17 14:13:02 +01:00
input
. fields
. keys ( )
2021-07-08 19:05:31 +02:00
. flat_map ( | p | p . neighbors ( ) )
2020-12-17 17:17:00 +01:00
. unique ( )
2021-07-08 19:05:31 +02:00
. map ( | pos | ( pos , next_state ( & pos , & readonly ) ) )
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
}
2021-07-08 19:05:31 +02:00
fn next_state < const D : usize > ( pos : & PositionND < D > , grid : & Grid < D , Cell > ) -> Cell
2021-07-08 22:17:14 +02:00
where [ ( ) ; grid ::num_neighbors ( D ) + 1 ] : Sized {
2021-07-08 19:05:31 +02:00
let cell = grid . get ( pos ) ;
2021-07-08 19:35:31 +02:00
match ( & cell , count_live_neighbors ::< D > ( pos , grid ) ) {
2021-07-08 19:05:31 +02:00
( Cell ::Alive , 2 ..= 3 ) = > Cell ::Alive ,
( Cell ::Dead , 3 ) = > Cell ::Alive ,
_ = > Cell ::Dead ,
2021-07-08 19:35:31 +02:00
}
2021-07-08 19:05:31 +02:00
}
fn solve < const D : usize > ( parsed : & Grid < D , Cell > , steps : usize ) -> usize
2021-07-08 22:17:14 +02:00
where [ ( ) ; grid ::num_neighbors ( D ) + 1 ] : Sized {
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 ( ) ;
2021-07-08 19:05:31 +02:00
let input = parse_input ::< 3 > ( & raw ) ;
2020-12-17 15:15:51 +01:00
println! ( " Part 1: {} " , solve ( & input , 6 ) ) ;
2021-07-08 19:05:31 +02:00
let input = parse_input ::< 4 > ( & raw ) ;
2020-12-17 15:15:51 +01:00
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 = " .#.
.. #
###" ;
2021-07-08 19:05:31 +02:00
#[ test ]
fn test_make_step ( ) {
let input = parse_input ::< 3 > ( TEST_INPUT ) ;
let changed = make_step ( input . clone ( ) ) ;
let expected = Grid {
fields : IntoIterator ::into_iter ( [
( PositionND { points : [ 1 , 3 , 0 ] } , Cell ::Alive ) ,
( PositionND { points : [ 0 , 1 , 0 ] } , Cell ::Alive ) ,
( PositionND { points : [ 2 , 2 , 0 ] } , Cell ::Alive ) ,
( PositionND { points : [ 2 , 2 , 1 ] } , Cell ::Alive ) ,
( PositionND { points : [ 0 , 1 , 1 ] } , Cell ::Alive ) ,
( PositionND { points : [ 2 , 1 , 0 ] } , Cell ::Alive ) ,
( PositionND { points : [ 1 , 3 , - 1 ] } , Cell ::Alive ) ,
( PositionND { points : [ 0 , 1 , - 1 ] } , Cell ::Alive ) ,
( PositionND { points : [ 1 , 2 , 0 ] } , Cell ::Alive ) ,
( PositionND { points : [ 1 , 3 , 1 ] } , Cell ::Alive ) ,
( PositionND { points : [ 2 , 2 , - 1 ] } , Cell ::Alive ) ,
] )
. collect ( ) ,
} ;
assert_eq! ( changed , expected ) ;
}
#[ test ]
fn test_count_live_neighbors ( ) {
let input = parse_input ::< 2 > ( TEST_INPUT ) ;
let one_one = PositionND { points : [ 1 , 1 ] } ;
let live = count_live_neighbors ( & one_one , & input ) ;
assert_eq! ( live , 5 ) ;
}
#[ test ]
fn test_next_state ( ) {
let input = parse_input ::< 2 > ( TEST_INPUT ) ;
let one_one = PositionND { points : [ 1 , 1 ] } ;
assert_eq! ( next_state ( & one_one , & input ) , Cell ::Dead ) ;
let one_three = PositionND { points : [ 1 , 3 ] } ;
assert_eq! ( next_state ( & one_three , & input ) , Cell ::Alive ) ;
}
2020-12-17 15:15:51 +01:00
#[ test ]
fn test_3d ( ) {
2021-07-08 19:05:31 +02:00
let input = parse_input ::< 3 > ( TEST_INPUT ) ;
assert_eq! ( solve ( & input , 1 ) , 11 ) ;
assert_eq! ( solve ( & input , 2 ) , 21 ) ;
2020-12-17 15:15:51 +01:00
assert_eq! ( solve ( & input , 6 ) , 112 ) ;
}
#[ test ]
fn test_4d ( ) {
2021-07-08 19:05:31 +02:00
let input = parse_input ::< 4 > ( TEST_INPUT ) ;
2020-12-17 15:15:51 +01:00
assert_eq! ( solve ( & input , 6 ) , 848 ) ;
}
#[ bench ]
fn bench_3d_parse ( b : & mut test ::Bencher ) {
let raw = read_input ( ) ;
2021-07-08 19:05:31 +02:00
b . iter ( | | assert_eq! ( parse_input ::< 3 > ( black_box ( & raw ) ) . 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 ( ) ;
2021-07-08 19:05:31 +02:00
b . iter ( | | assert_eq! ( parse_input ::< 4 > ( black_box ( & raw ) ) . fields . len ( ) , 43 ) ) ;
2020-12-17 15:15:51 +01:00
}
#[ bench ]
fn bench_3d ( b : & mut test ::Bencher ) {
2021-07-08 19:05:31 +02:00
let input = parse_input ::< 3 > ( & read_input ( ) ) ;
2020-12-17 15:15:51 +01:00
b . iter ( | | assert_eq! ( solve ( & input , 6 ) , 348 ) ) ;
}
#[ bench ]
fn bench_4d ( b : & mut test ::Bencher ) {
2021-07-08 19:05:31 +02:00
let input = parse_input ::< 4 > ( & read_input ( ) ) ;
2020-12-17 15:15:51 +01:00
b . iter ( | | assert_eq! ( solve ( & input , 6 ) , 2236 ) ) ;
}
2020-12-17 14:04:05 +01:00
}