2022-12-14 22:42:56 +01:00
#![ feature(test, array_windows) ]
extern crate test ;
use aoc2022 ::{ boilerplate , common ::* } ;
use std ::iter ::repeat ;
const DAY : usize = 14 ;
const X_OFFSET : usize = 300 ;
const SAND_SOURCE : ( usize , usize ) = ( 500 - X_OFFSET , 0 ) ;
const CAVE_HEIGHT : usize = 200 ;
const CAVE_WIDTH : usize = CAVE_HEIGHT * 2 ;
2022-12-14 23:24:16 +01:00
type Cave = [ [ bool ; CAVE_HEIGHT ] ; CAVE_WIDTH ] ;
2022-12-14 22:42:56 +01:00
type Parsed = ( Cave , usize ) ;
fn parse_input ( raw : & str ) -> Parsed {
2022-12-14 23:24:16 +01:00
let mut cave = [ [ false ; CAVE_HEIGHT ] ; CAVE_WIDTH ] ;
2022-12-14 22:42:56 +01:00
let mut max_y = 0 ;
2022-12-14 23:46:52 +01:00
let mut segments : Vec < ( usize , usize ) > = Vec ::with_capacity ( 10 ) ;
2022-12-14 22:42:56 +01:00
for line in raw . lines ( ) {
2022-12-14 23:46:52 +01:00
segments
. extend ( line . split ( " -> " ) . map ( | s | s . split_once ( ',' ) . unwrap ( ) ) . map ( | ( x , y ) | ( parse_num ::< usize > ( x ) - X_OFFSET , parse_num ( y ) ) ) ) ;
2022-12-14 22:42:56 +01:00
for & [ ( x1 , y1 ) , ( x2 , y2 ) ] in segments . array_windows ( ) {
for ( x , y ) in ( ( x1 . min ( x2 ) ) ..= ( x1 . max ( x2 ) ) ) . flat_map ( | x | repeat ( x ) . zip ( ( y1 . min ( y2 ) ) ..= ( y1 . max ( y2 ) ) ) ) {
2022-12-14 23:24:16 +01:00
cave [ x ] [ y ] = true ;
2022-12-14 22:42:56 +01:00
}
}
2022-12-14 23:46:52 +01:00
max_y = max_y . max ( segments . drain ( .. ) . map ( | ( _ , y ) | y ) . max ( ) . unwrap ( ) ) ;
2022-12-14 22:42:56 +01:00
}
( cave , max_y )
}
fn simulate ( ( x , y ) : ( usize , usize ) , cave : & Cave ) -> Option < ( usize , usize ) > {
if y > = CAVE_HEIGHT - 1 {
None
2022-12-14 23:24:16 +01:00
} else if ! cave [ x ] [ y + 1 ] {
2022-12-14 22:42:56 +01:00
simulate ( ( x , y + 1 ) , cave )
2022-12-14 23:24:16 +01:00
} else if ! cave [ x - 1 ] [ y + 1 ] {
2022-12-14 22:42:56 +01:00
simulate ( ( x - 1 , y + 1 ) , cave )
2022-12-14 23:24:16 +01:00
} else if ! cave [ x + 1 ] [ y + 1 ] {
2022-12-14 22:42:56 +01:00
simulate ( ( x + 1 , y + 1 ) , cave )
} else {
Some ( ( x , y ) )
}
}
2022-12-14 23:40:29 +01:00
// abusing scan here to simulate a stateful for-loop with a counter
2022-12-14 22:42:56 +01:00
fn part1 ( ( cave , _ ) : & Parsed ) -> usize {
2022-12-14 23:40:29 +01:00
repeat ( ( ) ) . scan ( cave . to_owned ( ) , | cave , _ | simulate ( SAND_SOURCE , & cave ) . map ( | ( x , y ) | cave [ x ] [ y ] = true ) ) . count ( )
2022-12-14 22:42:56 +01:00
}
fn part2 ( ( cave , max_y ) : & Parsed ) -> usize {
let mut cave = cave . to_owned ( ) ;
2022-12-14 23:24:16 +01:00
cave . iter_mut ( ) . for_each ( | row | row [ max_y + 2 ] = true ) ;
2022-12-14 23:40:29 +01:00
1 + repeat ( ( ) )
. scan ( cave , | cave , _ | simulate ( SAND_SOURCE , & cave ) . map ( | ( x , y ) | cave [ x ] [ y ] = true ) . filter ( | _ | ! cave [ SAND_SOURCE . 0 ] [ SAND_SOURCE . 1 ] ) )
. count ( )
2022-12-14 22:42:56 +01:00
}
boilerplate! {
TEST_INPUT = = " 498,4 -> 498,6 -> 496,6
503 , 4 -> 502 , 4 -> 502 , 9 -> 494 , 9 " ,
tests : {
part1 : { TEST_INPUT = > 24 } ,
part2 : { TEST_INPUT = > 93 } ,
} ,
bench1 = = 674 ,
bench2 = = 24958 ,
bench_parse : | ( _ , y ) : & Parsed | * y = > 161 ,
}