2021-04-29 19:14:28 +02:00
#![ feature(test, destructuring_assignment, bool_to_option) ]
#![ allow(clippy::ptr_arg) ]
2020-12-14 10:45:37 +01:00
extern crate test ;
2020-12-14 19:58:13 +01:00
use std ::collections ::HashMap ;
2020-12-14 10:45:37 +01:00
use aoc2020 ::common ::* ;
enum Command < ' a > {
BitMask ( & ' a str ) ,
MemSet { addr : usize , val : usize } ,
}
2020-12-14 16:09:10 +01:00
#[ derive(Debug, Clone, Copy, PartialEq) ]
enum BitState {
One ,
Zero ,
Floating ,
}
2020-12-14 10:45:37 +01:00
type Parsed < ' a > = Vec < Command < ' a > > ;
fn read_input ( ) -> String {
read_file ( 14 )
}
2021-04-29 19:14:28 +02:00
fn parse_input ( raw : & '_ str ) -> Parsed < '_ > {
2020-12-14 10:45:37 +01:00
raw . lines ( )
. map ( | l | {
if let Some ( l ) = l . strip_prefix ( " mask = " ) {
Command ::BitMask ( l )
} else if let Some ( ( addr , val ) ) = l . strip_prefix ( " mem[ " ) . and_then ( | l | l . split_once ( " ] = " ) ) {
Command ::MemSet {
addr : addr . parse ( ) . unwrap ( ) ,
val : val . parse ( ) . unwrap ( ) ,
}
} else {
unreachable! ( )
}
} )
. collect ( )
}
fn calc_bitmask < F : FnMut ( & ( usize , u8 ) ) -> bool > ( b : & str , f : F ) -> usize {
b . bytes ( ) . rev ( ) . enumerate ( ) . filter ( f ) . fold ( 0 , | acc , ( n , _ ) | acc | 1 < < n )
}
2020-12-14 16:09:10 +01:00
fn calc_bitmask_p2 ( b : & str ) -> Vec < BitState > {
b . bytes ( )
. map ( | b | match b {
b '0' = > BitState ::Zero ,
b '1' = > BitState ::One ,
b 'X' = > BitState ::Floating ,
_ = > unreachable! ( ) ,
} )
. collect ( )
}
fn calc_bitmasks_p1 ( b : & str ) -> ( usize , usize ) {
2020-12-14 10:45:37 +01:00
( calc_bitmask ( b , | ( _ , b ) | * b = = b '1' ) , calc_bitmask ( b , | ( _ , b ) | * b ! = b '0' ) )
}
2021-04-29 19:14:28 +02:00
fn part1 ( parsed : & Parsed < '_ > ) -> usize {
2020-12-14 10:45:37 +01:00
let ( mut ones , mut zeros ) = ( 0 , 0 ) ;
let mut mem = HashMap ::new ( ) ;
for command in parsed {
match command {
2020-12-14 16:09:10 +01:00
Command ::BitMask ( bm ) = > ( ones , zeros ) = calc_bitmasks_p1 ( bm ) ,
2020-12-14 10:45:37 +01:00
Command ::MemSet { addr , val } = > {
mem . insert ( addr , ( val & zeros ) | ones ) ;
}
}
}
mem . values ( ) . sum ( )
}
2021-04-29 19:14:28 +02:00
fn states_to_number ( bits : & [ BitState ] ) -> usize {
2020-12-14 18:59:36 +01:00
bits . iter ( )
. rev ( )
. enumerate ( )
. filter ( | ( _ , & b ) | b = = BitState ::One )
. fold ( 0 , | acc , ( n , _ ) | acc | 1 < < n )
}
2020-12-14 19:58:13 +01:00
fn get_variations ( input : Vec < BitState > ) -> Vec < usize > {
2020-12-14 18:59:36 +01:00
match input . iter ( ) . position ( | & b | b = = BitState ::Floating ) {
Some ( i ) = > {
let mut ret = vec! [ ] ;
for & new in & [ BitState ::One , BitState ::Zero ] {
let mut changed = input . clone ( ) ;
changed [ i ] = new ;
2020-12-14 19:58:13 +01:00
ret . append ( & mut get_variations ( changed ) ) ;
2020-12-14 18:59:36 +01:00
}
ret
}
2020-12-14 19:58:13 +01:00
None = > vec! [ states_to_number ( & input ) ] ,
2020-12-14 18:59:36 +01:00
}
}
2021-04-29 19:14:28 +02:00
fn part2 ( parsed : & Parsed < '_ > ) -> usize {
2020-12-14 18:59:36 +01:00
let mut mask = vec! [ ] ;
2020-12-14 19:58:13 +01:00
parsed
. iter ( )
. map ( | cmd | match cmd {
2020-12-14 16:09:10 +01:00
Command ::BitMask ( bm ) = > {
2020-12-14 18:59:36 +01:00
mask = calc_bitmask_p2 ( bm ) ;
2020-12-14 19:58:13 +01:00
( vec! [ ] , 0 )
2020-12-14 16:09:10 +01:00
}
Command ::MemSet { addr , val } = > {
2020-12-14 18:59:36 +01:00
let masked = format! ( " {:036b} " , addr )
2020-12-14 16:09:10 +01:00
. bytes ( )
2020-12-14 18:59:36 +01:00
. zip ( mask . iter ( ) )
. map ( | b | match b {
2020-12-14 16:09:10 +01:00
( _ , BitState ::Floating ) = > BitState ::Floating ,
2020-12-14 18:59:36 +01:00
( _ , BitState ::One ) = > BitState ::One ,
( n , BitState ::Zero ) = > {
if n = = b '0' {
BitState ::Zero
} else {
BitState ::One
}
}
2020-12-14 16:09:10 +01:00
} )
2020-12-14 18:59:36 +01:00
. collect ( ) ;
2020-12-14 19:58:13 +01:00
( get_variations ( masked ) , * val )
2020-12-14 16:09:10 +01:00
}
2020-12-14 19:58:13 +01:00
} )
. flat_map ( | ( addrs , val ) | addrs . into_iter ( ) . map ( move | a | ( a , val ) ) )
. collect ::< HashMap < _ , _ > > ( )
. values ( )
. sum ( )
2020-12-14 10:45:37 +01:00
}
fn main ( ) {
let raw = read_input ( ) ;
let input = parse_input ( & raw ) ;
println! ( " Part 1: {} " , part1 ( & input ) ) ;
println! ( " Part 2: {} " , part2 ( & input ) ) ;
}
#[ cfg(test) ]
mod tests {
use super ::* ;
use aoc2020 ::* ;
use paste ::paste ;
use test ::black_box ;
const TEST_INPUT : & str = " mask = XXXXXXXXXXXXXXXXXXXXXXXXXXXXX1XXXX0X
mem [ 8 ] = 11
mem [ 7 ] = 101
mem [ 8 ] = 0 " ;
2020-12-14 16:09:10 +01:00
const INPUT_PART_2 : & str = " mask = 000000000000000000000000000000X1001X
mem [ 42 ] = 100
mask = 00000000000000000000000000000000 X0XX
mem [ 26 ] = 1 " ;
#[ test ]
fn test_part2 ( ) {
let parsed = parse_input ( INPUT_PART_2 ) ;
assert_eq! ( part2 ( & parsed ) , 208 ) ;
}
2020-12-14 18:59:36 +01:00
#[ test ]
fn test_states_to_number ( ) {
let states = vec! [ BitState ::One , BitState ::Zero , BitState ::One , BitState ::Zero ] ;
assert_eq! ( states_to_number ( & states ) , 10 ) ;
}
2020-12-14 10:45:37 +01:00
test! ( part1 ( ) = = 165 ) ;
bench! ( part1 ( ) = = 18630548206046 ) ;
2020-12-14 18:59:36 +01:00
bench! ( part2 ( ) = = 4254673508445 ) ;
2020-12-14 16:09:10 +01:00
bench_input! ( len = = 577 ) ;
2020-12-14 10:45:37 +01:00
}