2022-12-08 14:53:11 +01:00
#![ feature(test, get_many_mut) ]
2022-12-08 11:36:21 +01:00
extern crate test ;
2022-12-08 12:16:39 +01:00
use itertools ::Itertools ;
2022-12-08 17:43:05 +01:00
use rayon ::prelude ::* ;
2022-12-08 11:36:21 +01:00
use std ::iter ::repeat ;
use aoc2022 ::{ boilerplate , common ::* } ;
2022-12-08 12:32:14 +01:00
const DAY : usize = 8 ;
2022-12-08 11:36:21 +01:00
type Parsed = Vec < Vec < u8 > > ;
fn parse_input ( raw : & str ) -> Parsed {
raw . lines ( ) . map ( | l | l . as_bytes ( ) . to_vec ( ) ) . collect ( )
}
2022-12-08 12:32:14 +01:00
fn is_visible_1d < ' a > ( iter : impl IntoIterator < Item = & ' a u8 > , rev : bool ) -> Vec < bool > {
let mut v : Vec < _ > = iter
. into_iter ( )
2022-12-08 11:36:21 +01:00
. scan ( 0 , | max , tree | {
let visible = tree > max ;
* max = * tree . max ( max ) ;
Some ( visible )
} )
2022-12-08 12:32:14 +01:00
. collect ( ) ;
if rev {
v . reverse ( ) ;
}
v
}
fn transpose < T : Copy > ( v : & Vec < Vec < T > > ) -> Vec < Vec < T > > {
2022-12-08 14:53:11 +01:00
let mut v = v . clone ( ) ;
let size = v . len ( ) ;
for i in 0 .. size {
for j in i + 1 .. size {
let [ a , b ] = v . get_many_mut ( [ i , j ] ) . unwrap ( ) ;
std ::mem ::swap ( & mut a [ j ] , & mut b [ i ] ) ;
}
}
v
2022-12-08 12:32:14 +01:00
}
fn horizontally_visible ( v : & [ Vec < u8 > ] ) -> Vec < Vec < bool > > {
v . iter ( ) . map ( | l | is_visible_1d ( l , false ) . into_iter ( ) . zip ( is_visible_1d ( l . iter ( ) . rev ( ) , true ) ) . map ( | ( a , b ) | a | | b ) . collect ( ) ) . collect ( )
2022-12-08 11:36:21 +01:00
}
fn part1 ( parsed : & Parsed ) -> usize {
2022-12-08 12:32:14 +01:00
let horizontal = horizontally_visible ( parsed ) ;
let vertical = horizontally_visible ( & transpose ( parsed ) ) ;
( 0 .. parsed . len ( ) ) . flat_map ( | i | repeat ( i ) . zip ( 0 .. parsed . len ( ) ) ) . filter ( | & ( i , j ) | horizontal [ i ] [ j ] | | vertical [ j ] [ i ] ) . count ( )
2022-12-08 11:36:21 +01:00
}
fn part2 ( parsed : & Parsed ) -> usize {
2022-12-08 12:16:39 +01:00
let size = parsed . len ( ) ; // input is always square
2022-12-08 14:53:11 +01:00
let transposed = transpose ( parsed ) ;
2022-12-08 12:16:39 +01:00
( 1 .. size - 1 )
2022-12-08 17:43:05 +01:00
. into_par_iter ( )
. flat_map ( | i | rayon ::iter ::repeat ( i ) . zip ( 1 .. size - 1 ) )
2022-12-08 12:16:39 +01:00
. map ( | ( i , j ) | {
let tree = parsed [ i ] [ j ] ;
2022-12-08 14:53:11 +01:00
let a = visible_trees ( tree , transposed [ j ] [ ( i + 1 ) .. size ] . iter ( ) ) ;
let b = visible_trees ( tree , transposed [ j ] [ 0 .. i ] . iter ( ) . rev ( ) ) ;
let c = visible_trees ( tree , parsed [ i ] [ ( j + 1 ) .. size ] . iter ( ) ) ;
let d = visible_trees ( tree , parsed [ i ] [ 0 .. j ] . iter ( ) . rev ( ) ) ;
2022-12-08 12:16:39 +01:00
a * b * c * d
} )
. max ( )
. unwrap ( )
2022-12-08 11:36:21 +01:00
}
2022-12-08 12:32:14 +01:00
#[ inline ] // this inline actually saves ~40% runtime
2022-12-08 14:53:11 +01:00
fn visible_trees < ' a , I : Iterator < Item = & ' a u8 > > ( tree : u8 , heights : I ) -> usize {
let mut heights = heights . copied ( ) . peekable ( ) ;
2022-12-08 12:32:14 +01:00
heights . peeking_take_while ( | & t | t < tree ) . count ( ) + heights . peek ( ) . map ( | _ | 1 ) . unwrap_or ( 0 )
}
2022-12-08 14:53:11 +01:00
// These have to be separate variables because the test outputs are used as function names and
// can’t contain special characters.
2022-12-08 11:36:21 +01:00
#[ cfg(test) ]
const TEST_OUTPUT : & [ bool ] = & [ true , true , false , true , false ] ;
2022-12-08 14:53:11 +01:00
#[ cfg(test) ]
const TRANSPOSE_OUTPUT : & [ [ u8 ; 3 ] ; 3 ] = & [ [ 1 , 4 , 7 ] , [ 2 , 5 , 8 ] , [ 3 , 6 , 9 ] ] ;
2022-12-08 11:36:21 +01:00
boilerplate! {
2022-12-09 12:50:12 +01:00
TEST_INPUT = = " \
30373 \ n \
25512 \ n \
65332 \ n \
33549 \ n \
35390 \
" ,
2022-12-08 11:36:21 +01:00
tests : {
part1 : { TEST_INPUT = > 21 } ,
2022-12-08 12:16:39 +01:00
part2 : { TEST_INPUT = > 8 } ,
2022-12-08 11:36:21 +01:00
} ,
unittests : {
2022-12-08 12:32:14 +01:00
is_visible_1d : { [ 1 , 3 , 2 , 4 , 2 ] . iter ( ) , false = > TEST_OUTPUT , } ,
2022-12-08 14:53:11 +01:00
transpose : { & vec! [ vec! [ 1 , 2 , 3 ] , vec! [ 4 , 5 , 6 ] , vec! [ 7 , 8 , 9 ] ] = > TRANSPOSE_OUTPUT } ,
2022-12-08 11:36:21 +01:00
} ,
bench1 = = 1543 ,
2022-12-08 12:16:39 +01:00
bench2 = = 595080 ,
2022-12-08 11:36:21 +01:00
bench_parse : Vec ::len = > 99 ,
}