2023-12-03 09:31:34 +01:00
#![ feature(test, try_blocks) ]
extern crate test ;
2023-12-03 10:25:35 +01:00
2023-12-03 09:31:34 +01:00
use aoc2023 ::{
boilerplate ,
common ::* ,
2023-12-03 16:25:25 +01:00
position ::{ Position2D , PositionND } ,
2023-12-03 09:31:34 +01:00
} ;
use itertools ::Itertools ;
const DAY : usize = 3 ;
2023-12-03 16:25:25 +01:00
type I = i32 ;
2023-12-03 10:25:35 +01:00
type Grid < ' a > = Vec < & ' a [ u8 ] > ;
2023-12-03 20:21:13 +01:00
type Region = ( usize , ( usize , usize ) ) ;
type Parsed < ' a > = ( Grid < ' a > , Vec < Vec < Region > > ) ;
2023-12-03 09:31:34 +01:00
fn parse_input ( raw : & str ) -> Parsed {
2023-12-03 10:25:35 +01:00
let grid = raw . lines ( ) . map ( | l | l . as_bytes ( ) ) . collect_vec ( ) ;
let number_positions = grid
2023-12-03 09:31:34 +01:00
. iter ( )
. enumerate ( )
2023-12-03 15:18:21 +01:00
. map ( | ( x , l ) | {
l . iter ( )
. enumerate ( )
2023-12-03 20:21:13 +01:00
. filter_map ( move | ( y , c ) | c . is_ascii_digit ( ) . then_some ( ( x , ( y , y ) ) ) )
2023-12-03 15:18:21 +01:00
. coalesce (
2023-12-03 20:21:13 +01:00
| ( x1 , ( y11 , y12 ) ) , ( x2 , ( y21 , y22 ) ) | {
if y12 + 1 = = y21 {
Ok ( ( x1 , ( y11 , y22 ) ) )
2023-12-03 15:18:21 +01:00
} else {
2023-12-03 20:21:13 +01:00
Err ( ( ( x1 , ( y11 , y12 ) ) , ( x2 , ( y21 , y22 ) ) ) )
2023-12-03 15:18:21 +01:00
}
} ,
)
2023-12-03 20:21:13 +01:00
. collect ( )
2023-12-03 15:18:21 +01:00
} )
2023-12-03 20:21:13 +01:00
. collect ( ) ;
2023-12-03 10:25:35 +01:00
( grid , number_positions )
2023-12-03 09:31:34 +01:00
}
2023-12-03 20:21:13 +01:00
fn parse_at ( grid : & Grid , ( x , ( y1 , y2 ) ) : Region ) -> usize {
String ::from_utf8_lossy ( & grid [ x ] [ y1 ..= y2 ] ) . parse ( ) . unwrap ( )
2023-12-03 10:25:35 +01:00
}
fn part1 ( ( grid , number_positions ) : & Parsed ) -> usize {
number_positions
. iter ( )
2023-12-03 15:18:21 +01:00
. flatten ( )
2023-12-03 10:25:35 +01:00
. cloned ( )
2023-12-03 20:21:13 +01:00
. filter_map ( | ( x , ( y1 , y2 ) ) | {
let start = PositionND ( [ x as I , y1 as I ] ) ;
let end = PositionND ( [ x as I , y2 as I ] ) ;
2023-12-03 10:25:35 +01:00
start
. neighbors ( )
. into_iter ( )
. chain ( end . neighbors ( ) )
. any ( | PositionND ( [ x , y ] ) | {
! matches! ( grid . get ( x as usize ) . and_then ( | ys | ys . get ( y as usize ) ) , Some ( b '0' ..= b '9' | b '.' ) | None )
} )
2023-12-03 20:21:13 +01:00
. then ( | | parse_at ( grid , ( x , ( y1 , y2 ) ) ) )
2023-12-03 10:25:35 +01:00
} )
. sum ( )
}
2023-12-03 20:21:13 +01:00
fn part_of ( PositionND ( [ _ , y ] ) : Position2D < I > , ( _ , ( y1 , y2 ) ) : & Region ) -> bool {
( y1 ..= y2 ) . contains ( & & ( y as usize ) )
2023-12-03 10:25:35 +01:00
}
fn part2 ( ( grid , number_positions ) : & Parsed ) -> usize {
grid . iter ( )
. enumerate ( )
2023-12-03 16:25:25 +01:00
. flat_map ( | ( x , ys ) | ys . iter ( ) . enumerate ( ) . filter_map ( move | ( y , & b ) | ( b = = b '*' ) . then_some ( PositionND ( [ x as I , y as I ] ) ) ) )
2023-12-03 10:25:35 +01:00
. filter_map ( | p | {
let neighbors = p . neighbors ( ) ;
2023-12-03 16:25:25 +01:00
number_positions [ ( p . 0 [ 0 ] . dec ( ) as usize ) ..= ( p . 0 [ 0 ] . inc ( ) as usize ) ]
2023-12-03 10:25:35 +01:00
. iter ( )
2023-12-03 15:18:21 +01:00
. flatten ( )
2023-12-03 20:21:13 +01:00
. filter_map ( | & np | neighbors . iter ( ) . find_map ( | & n | part_of ( n , & np ) . then ( | | parse_at ( grid , np ) ) ) )
2023-12-03 10:25:35 +01:00
. collect_tuple ( )
} )
. map ( | ( a , b ) | a * b )
. sum ( )
2023-12-03 09:31:34 +01:00
}
boilerplate! {
TEST_INPUT = = " 467..114..
.. . * .. .. ..
.. 35 .. 633.
.. .. .. #.. .
617 * .. .. ..
.. .. . + . 58.
.. 592 .. .. .
.. .. .. 755.
.. . $ . * .. ..
. 664.59 8 .. " ,
tests : {
part1 : { TEST_INPUT = > 4361 } ,
2023-12-03 10:25:35 +01:00
part2 : { TEST_INPUT = > 467835 } ,
2023-12-03 09:31:34 +01:00
} ,
bench1 = = 536202 ,
2023-12-03 10:25:35 +01:00
bench2 = = 78272573 ,
2023-12-03 15:18:21 +01:00
bench_parse : | ( g , ns ) : & Parsed | ( g . len ( ) , ns . len ( ) ) = > ( 140 , 140 ) ,
2023-12-03 09:31:34 +01:00
}