2023-12-13 09:30:03 +01:00
#![ feature(test, try_blocks) ]
extern crate test ;
use aoc2023 ::{ boilerplate , common ::* } ;
const DAY : usize = 13 ;
2023-12-13 12:08:26 +01:00
type Parsed = Vec < Vec < I > > ;
type I = u32 ;
2023-12-13 09:30:03 +01:00
fn parse_input ( raw : & str ) -> Parsed {
2023-12-13 12:08:26 +01:00
raw . split ( " \n \n " )
. map ( | block | block . lines ( ) . map ( | l | l . bytes ( ) . map ( | b | b = = b '#' ) . fold ( 0 , | acc , n | ( acc < < 1 ) | n as I ) ) . collect ( ) )
. collect ( )
2023-12-13 09:30:03 +01:00
}
2023-12-13 12:30:51 +01:00
fn find_reflection < const DEVIATIONS : u32 > ( block : & [ I ] ) -> Option < usize > {
2023-12-13 09:30:03 +01:00
' outer : for i in 0 .. block . len ( ) - 1 {
let mut offset = 0 ;
2023-12-13 12:30:51 +01:00
let mut deviations = DEVIATIONS ;
2023-12-13 09:30:03 +01:00
loop {
2023-12-13 12:40:23 +01:00
match try { ( block . get ( i . checked_sub ( offset ) ? ) ? ^ block . get ( i + 1 + offset ) ? ) . count_ones ( ) } {
2023-12-13 12:30:51 +01:00
None if deviations = = 0 = > return Some ( i + 1 ) ,
Some ( 0 ) = > offset + = 1 ,
2023-12-13 12:40:23 +01:00
Some ( diff ) if diff < = deviations = > {
offset + = 1 ;
deviations - = diff ;
2023-12-13 12:30:51 +01:00
}
2023-12-13 10:28:05 +01:00
_ = > continue 'outer ,
2023-12-13 09:30:03 +01:00
}
}
}
None
}
2023-12-13 12:08:26 +01:00
fn transpose ( orig : & [ I ] ) -> Vec < I > {
let max = orig . iter ( ) . max ( ) . unwrap ( ) ;
let len = ( I ::BITS - max . leading_zeros ( ) ) as usize ;
let mut out = vec! [ 0 ; len ] ;
for j in 0 .. len {
for ( i , & value ) in orig . iter ( ) . enumerate ( ) {
2023-12-13 12:40:23 +01:00
let src_bit = value & ( 1 < < j ) ;
let dst_position = orig . len ( ) - 1 - i ;
out [ len - 1 - j ] | = ( ( src_bit ! = 0 ) as I ) < < dst_position ;
2023-12-13 09:30:03 +01:00
}
}
out
}
2023-12-13 12:40:23 +01:00
fn solve < const DEV : u32 > ( blocks : & Parsed ) -> usize {
2023-12-13 12:30:51 +01:00
blocks
. iter ( )
2023-12-13 12:40:23 +01:00
. map ( | block | find_reflection ::< DEV > ( block ) . map ( | n | n * 100 ) . or_else ( | | find_reflection ::< DEV > ( & transpose ( block ) ) ) . unwrap ( ) )
2023-12-13 12:30:51 +01:00
. sum ( )
}
2023-12-13 12:40:23 +01:00
fn part1 ( blocks : & Parsed ) -> usize {
solve ::< 0 > ( blocks )
}
2023-12-13 10:28:05 +01:00
fn part2 ( blocks : & Parsed ) -> usize {
2023-12-13 12:40:23 +01:00
solve ::< 1 > ( blocks )
2023-12-13 09:30:03 +01:00
}
boilerplate! {
TEST_INPUT_HORIZONTAL = = " \
#.. . ##.. #
#.. .. #.. #
.. ##.. ###
#####. ##.
#####. ##.
.. ##.. ###
#.. .. #.. #" ,
TEST_INPUT_VERTICAL = = " \
#. ##.. ##.
.. #. ##. #.
##.. .. .. #
##.. .. .. #
.. #. ##. #.
.. ##.. ##.
2023-12-13 12:30:51 +01:00
#. #. ##. #. " ,
TEST_INPUT_475 = = " \
#.. ##.. ..
. #. ##.. ..
##.. .. ##.
#. #. #. ##.
. ####. ##.
###.. #.. #
#. #. #. ##.
. #. #. ####
.. #. #. ##.
. ##.. ####
#####. ##.
. #. #. ####
. #.. . ####
. #. #. ####
. #. #. ####
#####. ##.
. ##.. ####"
2023-12-13 09:30:03 +01:00
for tests : {
part1 : {
TEST_INPUT_HORIZONTAL = > 400 ,
TEST_INPUT_VERTICAL = > 5 ,
2023-12-13 12:30:51 +01:00
TEST_INPUT_475 = > 7 ,
2023-12-13 09:30:03 +01:00
} ,
2023-12-13 10:28:05 +01:00
part2 : {
TEST_INPUT_HORIZONTAL = > 100 ,
TEST_INPUT_VERTICAL = > 300 ,
2023-12-13 12:30:51 +01:00
TEST_INPUT_475 = > 1300 ,
2023-12-13 10:28:05 +01:00
} ,
2023-12-13 09:30:03 +01:00
} ,
2023-12-13 12:08:26 +01:00
unittests : {
transpose : {
& [
0b100 ,
0b010 ,
] = > TRANSPOSE_42 ,
& [
0b101 ,
0b010 ,
] = > TRANSPOSE_52 ,
} ,
} ,
2023-12-13 09:30:03 +01:00
bench1 = = 37561 ,
2023-12-13 10:28:05 +01:00
bench2 = = 31108 ,
2023-12-13 09:30:03 +01:00
bench_parse : Vec ::len = > 100 ,
}
2023-12-13 12:08:26 +01:00
#[ cfg(test) ]
const TRANSPOSE_52 : & [ I ] = & [ 0b10 , 0b01 , 0b10 ] ;
#[ cfg(test) ]
const TRANSPOSE_42 : & [ I ] = & [ 0b10 , 0b01 , 0b00 ] ;