2020: day14: cleanup and comments

This commit is contained in:
Antoine Martin 2020-12-14 14:11:08 +01:00
parent 8017827edc
commit 18ddbd1310

View file

@ -17,7 +17,7 @@ pub fn run() -> aoc::Result<String> {
fn part1(input: &str) -> aoc::Result<u64> { fn part1(input: &str) -> aoc::Result<u64> {
let mut program: Program = input.parse()?; let mut program: Program = input.parse()?;
program.run()?; program.run_part1()?;
Ok(program.memory_sum()) Ok(program.memory_sum())
} }
@ -30,6 +30,7 @@ fn part2(input: &str) -> aoc::Result<u64> {
Ok(program.memory_sum()) Ok(program.memory_sum())
} }
/// Represents the kind of mask we want to apply at a specific offset
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
enum Mask { enum Mask {
Floating, Floating,
@ -37,6 +38,7 @@ enum Mask {
Zero, Zero,
} }
/// An iterator over all possible values produced by applying `masks` on a single value
#[derive(Debug)] #[derive(Debug)]
struct FloatingIterator<'a> { struct FloatingIterator<'a> {
masks: &'a [Mask], masks: &'a [Mask],
@ -48,6 +50,7 @@ struct FloatingIterator<'a> {
impl<'a> FloatingIterator<'a> { impl<'a> FloatingIterator<'a> {
fn new(masks: &'a [Mask], mut n: usize) -> Self { fn new(masks: &'a [Mask], mut n: usize) -> Self {
// apply non-floating masks here, we don't want to process them in every iteration
for (offset, mask) in masks.iter().enumerate() { for (offset, mask) in masks.iter().enumerate() {
if let Mask::One = mask { if let Mask::One = mask {
n |= 1 << offset; n |= 1 << offset;
@ -62,6 +65,7 @@ impl<'a> FloatingIterator<'a> {
} }
} }
/// Returns the offset of the next Floating Mask it finds after offset, if any
fn find_next_floating(masks: &[Mask], offset: usize) -> Option<usize> { fn find_next_floating(masks: &[Mask], offset: usize) -> Option<usize> {
masks masks
.iter() .iter()
@ -105,14 +109,17 @@ impl<'a> Iterator for FloatingIterator<'a> {
let (offset, state) = self.stack.last_mut().unwrap(); let (offset, state) = self.stack.last_mut().unwrap();
match state { match state {
FloatingState::Unapplied => { FloatingState::Unapplied => {
// apply the Zero mask
self.current_value &= !(1 << *offset); self.current_value &= !(1 << *offset);
*state = FloatingState::AppliedZero; *state = FloatingState::AppliedZero;
} }
FloatingState::AppliedZero => { FloatingState::AppliedZero => {
// apply the One mask
self.current_value |= 1 << *offset; self.current_value |= 1 << *offset;
*state = FloatingState::AppliedZeroAndOne; *state = FloatingState::AppliedZeroAndOne;
} }
FloatingState::AppliedZeroAndOne => { FloatingState::AppliedZeroAndOne => {
// we've applied all possibilities for this mask, we can unwind our stack
self.stack.pop(); self.stack.pop();
if self.stack.is_empty() { if self.stack.is_empty() {
@ -125,7 +132,7 @@ impl<'a> Iterator for FloatingIterator<'a> {
} }
} }
// we've applied our current mask transform, now we "recurse" and find the next one // we've applied our current mask transform, now we "recur" and find the next one
match FloatingIterator::find_next_floating(self.masks, *offset + 1) { match FloatingIterator::find_next_floating(self.masks, *offset + 1) {
Some(offset) => self.stack.push((offset, FloatingState::Unapplied)), Some(offset) => self.stack.push((offset, FloatingState::Unapplied)),
None => { None => {
@ -143,7 +150,9 @@ struct BitMask {
} }
impl BitMask { impl BitMask {
/// function used for part 1: 'X' bits just don't do anything /// Function used for part 1: 'X' bits just don't do anything
///
/// This discards Floating masks, returning a single modified value
fn apply_no_floating(&self, mut n: u64) -> u64 { fn apply_no_floating(&self, mut n: u64) -> u64 {
for (offset, mask) in self.masks.iter().enumerate() { for (offset, mask) in self.masks.iter().enumerate() {
match mask { match mask {
@ -156,6 +165,10 @@ impl BitMask {
n n
} }
/// Returns an iterator over all possible values when applying the BitMask
///
/// This takes into account Floating masks, which produce multiple possibilities, hence the need
/// for an iterator
fn apply(&self, n: usize) -> impl Iterator<Item = usize> + '_ { fn apply(&self, n: usize) -> impl Iterator<Item = usize> + '_ {
FloatingIterator::new(&self.masks, n) FloatingIterator::new(&self.masks, n)
} }
@ -239,7 +252,7 @@ struct Program {
} }
impl Program { impl Program {
fn run(&mut self) -> aoc::Result<()> { fn run_part1(&mut self) -> aoc::Result<()> {
for inst in &self.instructions { for inst in &self.instructions {
match inst { match inst {
Instruction::ChangeMask(bitmask) => self.current_mask = Some(bitmask.clone()), Instruction::ChangeMask(bitmask) => self.current_mask = Some(bitmask.clone()),