2020-12-17 14:04:05 +01:00
#![ feature(test) ]
extern crate test ;
2020-12-17 17:17:00 +01:00
use itertools ::Itertools ;
2020-12-17 14:51:05 +01:00
use aoc2020 ::{
common ::* , grid ::{ cell ::Cell , * }
} ;
2020-12-17 14:04:05 +01:00
fn read_input ( ) -> String {
read_file ( 17 )
}
2020-12-17 15:15:51 +01:00
fn parse_input < P : Position , F : FnMut ( ( usize , usize ) ) -> P + Copy > ( raw : & str , mut pos_gen : F ) -> Grid < P , Cell > {
2020-12-17 14:13:02 +01:00
raw . lines ( )
. enumerate ( )
2020-12-17 15:15:51 +01:00
. flat_map ( move | ( y , l ) | l . bytes ( ) . enumerate ( ) . map ( move | ( x , b ) | ( pos_gen ( ( x , y ) ) , 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 15:15:51 +01:00
fn count_live_neighbors < P : Position > ( p : & P , grid : & Grid < P , 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 15:15:51 +01:00
fn make_step < P : Position > ( input : Grid < P , Cell > ) -> Grid < P , Cell > {
2020-12-17 14:04:05 +01:00
let readonly = input . clone ( ) ;
2020-12-17 14:13:02 +01:00
input
. fields
. keys ( )
. flat_map ( | p | p . neighbors ( ) )
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 14:13:02 +01:00
let new = match ( & cell , count_live_neighbors ( & pos , & readonly ) ) {
( 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 15:15:51 +01:00
fn solve < P : Position > ( parsed : & Grid < P , 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
}