2021-12-03 07:01:36 +01:00
#![ feature(test) ]
extern crate test ;
use aoc2021 ::common ::* ;
2021-12-03 14:41:02 +01:00
const DAY : usize = 3 ;
2021-12-03 12:00:58 +01:00
type Parsed = Vec < usize > ;
2021-12-03 07:01:36 +01:00
fn parse_input ( raw : & str ) -> Parsed {
2021-12-03 12:00:58 +01:00
raw . lines ( ) . map ( | line | usize ::from_str_radix ( line , 2 ) . unwrap ( ) ) . collect ( )
2021-12-03 07:01:36 +01:00
}
2021-12-03 12:00:58 +01:00
fn bit_at ( x : usize , n : usize ) -> bool {
( x > > n ) & 1 ! = 0
2021-12-03 07:01:36 +01:00
}
2021-12-03 12:00:58 +01:00
fn most_common ( parsed : & Parsed , bits : usize ) -> usize {
( 0 .. bits ) . rev ( ) . map ( | n | most_common_at ( parsed , n ) ) . fold ( 0 , | acc , b | ( acc | ( b as usize ) ) < < 1 ) > > 1
}
fn most_common_at ( parsed : & Parsed , n : usize ) -> bool {
parsed . iter ( ) . filter ( | & & x | bit_at ( x , n ) ) . count ( ) * 2 > = parsed . len ( )
}
2021-12-03 14:41:02 +01:00
fn invert ( n : usize , bits : usize ) -> usize {
! n & ( ( 1 < < bits ) - 1 )
2021-12-03 12:00:58 +01:00
}
fn part1 ( parsed : & Parsed , bits : usize ) -> usize {
let gamma = most_common ( parsed , bits ) ;
2021-12-03 14:41:02 +01:00
let epsilon = invert ( gamma , bits ) ;
2021-12-03 07:01:36 +01:00
gamma * epsilon
}
2021-12-03 12:00:58 +01:00
fn part2 ( parsed : & Parsed , bits : usize ) -> usize {
2021-12-03 07:01:36 +01:00
let mut matching_gamma = parsed . clone ( ) ;
let mut matching_epsilon = parsed . clone ( ) ;
2021-12-03 12:00:58 +01:00
for i in ( 0 .. bits ) . rev ( ) {
let gamma = most_common_at ( & matching_gamma , i ) ;
let epsilon = ! most_common_at ( & matching_epsilon , i ) ;
2021-12-03 14:41:02 +01:00
// TODO: Find out why retain is significantly slower than filter().collect()
2021-12-03 20:27:57 +01:00
// Update: Let’s see what the maintainers say: https://github.com/rust-lang/rust/issues/91497
2021-12-03 18:02:18 +01:00
// matching_gamma.retain(|&n| bit_at(n, i) == gamma);
matching_gamma = matching_gamma . into_iter ( ) . filter ( | & n | bit_at ( n , i ) = = gamma ) . collect ( ) ;
2021-12-03 07:01:36 +01:00
if matching_epsilon . len ( ) > 1 {
2021-12-03 18:02:18 +01:00
// matching_epsilon.retain(|&n| bit_at(n, i) == epsilon);
matching_epsilon = matching_epsilon . into_iter ( ) . filter ( | & n | bit_at ( n , i ) = = epsilon ) . collect ( ) ;
2021-12-03 07:01:36 +01:00
}
}
2021-12-03 12:00:58 +01:00
debug_assert_eq! ( matching_gamma . len ( ) , 1 ) ;
debug_assert_eq! ( matching_epsilon . len ( ) , 1 ) ;
matching_gamma [ 0 ] * matching_epsilon [ 0 ]
2021-12-03 07:01:36 +01:00
}
fn main ( ) {
2021-12-03 14:41:02 +01:00
let raw = read_file ( DAY ) ;
let input = parse_input ( & raw ) ;
let line_length = raw . find ( '\n' ) . unwrap ( ) ;
println! ( " Part 1: {} " , part1 ( & input , line_length ) ) ;
println! ( " Part 2: {} " , part2 ( & input , line_length ) ) ;
2021-12-03 07:01:36 +01:00
}
#[ cfg(test) ]
mod tests {
use super ::* ;
use aoc2021 ::* ;
const TEST_INPUT : & str = " 00100
11110
10110
10111
10101
01111
00111
11100
10000
11001
00010
01010 " ;
2021-12-03 12:00:58 +01:00
#[ test ]
fn most_common_test ( ) {
let parsed = parse_input ( TEST_INPUT ) ;
assert_eq! ( most_common ( & parsed , 5 ) , 0b10110 )
}
#[ test ]
fn invert_test ( ) {
let gamma = 0b10110 ;
2021-12-03 14:41:02 +01:00
assert_eq! ( invert ( gamma , 4 ) , 0b01001 ) ;
2021-12-03 12:00:58 +01:00
}
#[ test ]
fn most_common_at_test ( ) {
let parsed = parse_input ( TEST_INPUT ) ;
assert_eq! ( most_common_at ( & parsed , 4 ) , true ) ;
}
#[ test ]
fn bit_at_test ( ) {
assert_eq! ( bit_at ( 0b111 , 0 ) , true ) ;
assert_eq! ( bit_at ( 0b111 , 1 ) , true ) ;
assert_eq! ( bit_at ( 0b111 , 2 ) , true ) ;
assert_eq! ( bit_at ( 0b111 , 3 ) , false ) ;
assert_eq! ( bit_at ( 0b101 , 1 ) , false ) ;
assert_eq! ( bit_at ( 0b11101 , 3 ) , true ) ;
}
test! ( part1 ( 5 ) = = 198 ) ;
test! ( part2 ( 5 ) = = 230 ) ;
bench! ( part1 ( 12 ) = = 3549854 ) ;
bench! ( part2 ( 12 ) = = 3765399 ) ;
2021-12-03 17:05:53 +01:00
bench_input! ( Vec ::len = > 1000 ) ;
2021-12-03 07:01:36 +01:00
}