2021-12-17 12:32:46 +01:00
#![ feature(core_intrinsics) ]
2021-12-17 12:01:43 +01:00
#![ feature(test) ]
extern crate test ;
2021-12-17 12:32:46 +01:00
use std ::{ intrinsics ::unlikely , ops ::RangeInclusive } ;
2021-12-17 12:01:43 +01:00
type TargetArea = ( RangeInclusive < isize > , RangeInclusive < isize > ) ;
type Probe = ( ( isize , isize ) , ( isize , isize ) ) ;
#[ derive(Debug, PartialEq) ]
enum ProbeStatus {
Hit ,
Miss ,
NoLongerReachable ,
}
2021-12-17 14:06:31 +01:00
#[ inline ]
2021-12-17 13:26:10 +01:00
fn calc_status ( ( ( xvel , _ ) , ( x , y ) ) : & Probe , ( xtarget , ytarget ) : & TargetArea ) -> ProbeStatus {
2021-12-17 12:01:43 +01:00
if xtarget . contains ( x ) & & ytarget . contains ( y ) {
ProbeStatus ::Hit
2021-12-17 13:26:10 +01:00
} else if y < ytarget . start ( ) | | x > xtarget . end ( ) | | ( xvel = = & 0 & & ! xtarget . contains ( x ) ) {
2021-12-17 12:01:43 +01:00
ProbeStatus ::NoLongerReachable
} else {
ProbeStatus ::Miss
}
}
2021-12-17 14:06:31 +01:00
#[ inline ]
fn step ( ( ( xvel , yvel ) , ( x , y ) ) : & Probe ) -> Probe {
2021-12-17 12:01:43 +01:00
( ( xvel - xvel . signum ( ) , yvel - 1 ) , ( x + xvel , y + yvel ) )
}
2021-12-17 13:26:10 +01:00
fn parse_input ( ) -> TargetArea {
( 34 ..= 67 , - 215 ..= - 186 )
}
2021-12-17 14:06:31 +01:00
fn part1 ( hits : & [ ( ( isize , isize ) , isize ) ] ) -> isize {
2021-12-17 12:32:46 +01:00
* hits . iter ( ) . map ( | ( _ , y ) | y ) . max ( ) . unwrap ( )
2021-12-17 12:01:43 +01:00
}
2021-12-17 12:32:46 +01:00
fn find_hits ( target : & TargetArea ) -> Vec < ( ( isize , isize ) , isize ) > {
2021-12-17 12:51:01 +01:00
( 1 ..= * target . 0. end ( ) )
. flat_map ( move | x | ( * target . 1. start ( ) .. 250 ) . map ( move | y | ( x , y ) ) )
2021-12-17 14:06:31 +01:00
. filter_map ( | start | {
let mut probe = ( start , ( 0 , 0 ) ) ;
2021-12-17 12:32:46 +01:00
let mut y_high = 0 ;
2021-12-17 12:01:43 +01:00
loop {
2021-12-17 14:06:31 +01:00
probe = step ( & probe ) ;
2021-12-17 12:32:46 +01:00
if unlikely ( probe . 0 . 1 = = 0 ) {
y_high = probe . 1 . 1 ;
}
2021-12-17 12:01:43 +01:00
match calc_status ( & probe , target ) {
2021-12-17 14:06:31 +01:00
ProbeStatus ::Hit = > return Some ( ( start , y_high ) ) ,
2021-12-17 13:26:10 +01:00
ProbeStatus ::Miss = > continue ,
2021-12-17 12:32:46 +01:00
ProbeStatus ::NoLongerReachable = > return None ,
2021-12-17 12:01:43 +01:00
}
}
2021-12-17 12:32:46 +01:00
} )
. collect ( )
2021-12-17 12:01:43 +01:00
}
fn main ( ) {
let target = parse_input ( ) ;
let hits = find_hits ( & target ) ;
2021-12-17 12:32:46 +01:00
println! ( " Part 1: {} " , part1 ( & hits ) ) ;
println! ( " Part 2: {} " , hits . len ( ) ) ;
2021-12-17 12:01:43 +01:00
}
#[ cfg(test) ]
mod tests {
use super ::* ;
use aoc2021 ::* ;
#[ test ]
fn part1_test ( ) {
let input = ( 20 ..= 30 , - 10 ..= - 5 ) ;
let hits = find_hits ( & input ) ;
2021-12-17 12:32:46 +01:00
assert_eq! ( part1 ( & hits ) , 45 ) ;
2021-12-17 12:01:43 +01:00
}
#[ test ]
fn part2_test ( ) {
let input = ( 20 ..= 30 , - 10 ..= - 5 ) ;
let hits = find_hits ( & input ) ;
2021-12-17 12:32:46 +01:00
assert_eq! ( hits . len ( ) , 112 ) ;
2021-12-17 12:01:43 +01:00
}
#[ bench ]
fn bench_find_hits ( b : & mut test ::Bencher ) {
let input = parse_input ( ) ;
b . iter ( | | assert_eq! ( find_hits ( & input ) . len ( ) , 2040 ) )
}
#[ bench ]
fn bench_part1 ( b : & mut test ::Bencher ) {
let input = parse_input ( ) ;
let hits = find_hits ( & input ) ;
2021-12-17 12:32:46 +01:00
b . iter ( | | assert_eq! ( part1 ( & hits ) , 23005 ) )
2021-12-17 12:01:43 +01:00
}
}