2023-12-18 12:35:13 +01:00
#![ feature(test) ]
extern crate test ;
use aoc2023 ::{
boilerplate ,
common ::* ,
direction ::Direction ::{ self , * } ,
position ::{ Position2D , PositionND } ,
} ;
2023-12-18 14:57:40 +01:00
use itertools ::Itertools ;
2023-12-18 12:35:13 +01:00
const DAY : usize = 18 ;
type I = isize ;
type Pos = Position2D < I > ;
2023-12-18 15:09:09 +01:00
type Parsed = Vec < ( ( Direction , I ) , ( Direction , I ) ) > ;
fn parse_dir ( c : u8 ) -> Direction {
match c {
b 'R' | b '0' = > Right ,
b 'D' | b '1' = > Down ,
b 'L' | b '2' = > Left ,
b 'U' | b '3' = > Up ,
_ = > unreachable! ( ) ,
}
}
2023-12-18 12:35:13 +01:00
fn parse_input ( raw : & str ) -> Parsed {
raw . lines ( )
. map ( | line | line . split ( ' ' ) . collect_tuple ( ) . unwrap ( ) )
. map ( | ( d , l , c ) | {
2023-12-18 15:09:09 +01:00
( ( parse_dir ( d . as_bytes ( ) [ 0 ] ) , parse_num ( l ) ) , ( parse_dir ( c . as_bytes ( ) [ 7 ] ) , I ::from_str_radix ( & c [ 2 .. 7 ] , 16 ) . unwrap ( ) ) )
2023-12-18 12:35:13 +01:00
} )
. collect ( )
}
2023-12-18 14:57:40 +01:00
fn part1 ( instructions : & Parsed ) -> isize {
2023-12-18 15:09:09 +01:00
solve ( instructions . iter ( ) . map ( | ( a , _ ) | a ) )
}
fn part2 ( instructions : & Parsed ) -> isize {
solve ( instructions . iter ( ) . map ( | ( _ , b ) | b ) )
}
fn solve < ' a > ( instructions : impl Iterator < Item = & ' a ( Direction , I ) > + Clone ) -> isize {
let n_points : I = instructions . clone ( ) . map ( | ( _ , len ) | len ) . sum ( ) ;
2023-12-18 14:57:40 +01:00
let points : Vec < _ > = instructions
2023-12-18 15:09:09 +01:00
. scan ( PositionND ( [ 0 , 0 ] ) , | pos , & ( dir , len ) | {
2023-12-18 14:57:40 +01:00
let movement = PositionND ( match dir {
Up = > [ len , 0 ] ,
Down = > [ - len , 0 ] ,
Right = > [ 0 , len ] ,
Left = > [ 0 , - len ] ,
} ) ;
* pos + = movement ;
Some ( * pos )
} )
. collect ( ) ;
( 2 * area ( & points ) - n_points + 2 ) / 2 + n_points
2023-12-18 12:35:13 +01:00
}
2023-12-18 14:57:40 +01:00
fn area ( polygon : & [ Pos ] ) -> isize {
2023-12-18 15:09:09 +01:00
polygon . iter ( ) . zip ( polygon . iter ( ) . cycle ( ) . skip ( 1 ) ) . map ( | ( p1 , p2 ) | p1 [ 0 ] * p2 [ 1 ] - p1 [ 1 ] * p2 [ 0 ] ) . sum ::< I > ( ) . abs ( ) > > 1
2023-12-18 12:35:13 +01:00
}
boilerplate! {
TEST_INPUT = = " \
R 6 ( #70 c710 )
D 5 ( #0 dc571 )
L 2 ( #5713 f0 )
D 2 ( #d2c081 )
R 2 ( #59 c680 )
D 2 ( #411 b91 )
L 5 ( #8 ceee2 )
U 2 ( #caa173 )
L 1 ( #1 b58a2 )
U 2 ( #caa171 )
R 2 ( #7807 d2 )
U 3 ( #a77fa3 )
L 2 ( #015232 )
U 2 ( #7 a21e3 ) "
for tests : {
part1 : { TEST_INPUT = > 62 } ,
2023-12-18 15:09:09 +01:00
part2 : { TEST_INPUT = > 952408144115 } ,
2023-12-18 12:35:13 +01:00
} ,
2023-12-18 14:57:40 +01:00
unittests : {
area : {
& [
PositionND ( [ 0 , 0 ] ) ,
PositionND ( [ 0 , 2 ] ) ,
PositionND ( [ 2 , 2 ] ) ,
PositionND ( [ 2 , 0 ] ) ,
] = > 4
}
} ,
2023-12-18 12:35:13 +01:00
bench1 = = 35991 ,
2023-12-18 15:09:09 +01:00
bench2 = = 54058824661845 ,
2023-12-18 12:35:13 +01:00
bench_parse : Vec ::len = > 602 ,
}