Files
aoc2020/src/day14.rs
T
Stephen Waits e56dff5a12 day 14 solutions
Signed-off-by: Stephen Waits <swaits@amazon.com>
2020-12-14 23:06:50 -08:00

142 lines
3.7 KiB
Rust

// ==== day 12
use crate::utils;
use anyhow::Result;
use std::collections::HashMap;
#[derive(Copy, Clone, Debug)]
enum Instruction {
Mask {
exes_mask: u64,
ones_mask: u64,
zeroes_mask: u64,
},
Write {
address: u64,
value: u64,
},
}
fn parse_mask(s: &str) -> Instruction {
let maskstr = &s[s.find(" = ").unwrap() + 3..];
let ones_str = maskstr.replace('X', "0");
let zeroes_str = maskstr
.replace('1', "X")
.replace('0', "1")
.replace('X', "0");
let exes_str = maskstr.replace('1', "0").replace('X', "1");
Instruction::Mask {
exes_mask: u64::from_str_radix(&exes_str, 2).unwrap(),
ones_mask: u64::from_str_radix(&ones_str, 2).unwrap(),
zeroes_mask: u64::from_str_radix(&zeroes_str, 2).unwrap(),
}
}
fn parse_write(s: &str) -> Instruction {
Instruction::Write {
address: s[4..s.find(']').unwrap()].parse().unwrap(),
value: s[s.find(" = ").unwrap() + 3..].parse().unwrap(),
}
}
fn parse(input: &str) -> Vec<Instruction> {
input
.lines()
.map(|l| l.trim())
.map(|l| match &l[0..4] {
"mask" => parse_mask(l),
"mem[" => parse_write(l),
_ => unreachable!("bad input"),
})
.collect()
}
fn simulate1(program: &[Instruction]) -> u64 {
let mut memory: HashMap<u64, u64> = HashMap::new();
let (mut cur_ones, mut cur_zeroes) = (0, 0);
program.iter().for_each(|i| {
match i {
Instruction::Mask {
ones_mask,
zeroes_mask,
..
} => {
cur_ones = *ones_mask;
cur_zeroes = *zeroes_mask;
}
Instruction::Write { address, value } => {
memory.insert(*address, (value | cur_ones) & !cur_zeroes);
}
};
});
memory.values().sum()
}
#[inline(always)]
fn set_bit(n: u64, bit: usize, value: bool) -> u64 {
if value {
n | (1 << bit)
} else {
n & !(1 << bit)
}
}
fn address_masks_from_float_mask(float_mask: u64) -> impl Iterator<Item = u64> {
let possibilities = 2_u64.pow(float_mask.count_ones());
let one_positions: Vec<usize> = (0..36).filter(|i| float_mask & (1 << i) != 0).collect();
(0..possibilities).map(move |i| {
one_positions
.iter()
.enumerate()
.fold(0, |result, (j, pos)| {
set_bit(result, *pos, (i & (1 << j)) != 0)
})
})
}
fn simulate2(program: &[Instruction]) -> u64 {
let mut memory: HashMap<u64, u64> = HashMap::new();
let (mut cur_exes, mut cur_ones, mut cur_zeroes) = (0, 0, 0);
program.iter().for_each(|i| {
match i {
Instruction::Mask {
exes_mask,
ones_mask,
zeroes_mask,
} => {
cur_exes = *exes_mask;
cur_ones = *ones_mask;
cur_zeroes = *zeroes_mask;
}
Instruction::Write { address, value } => {
let base_address = (*address | cur_ones) & !cur_exes;
address_masks_from_float_mask(cur_exes)
.map(|a| a | base_address)
.for_each(|a| {
memory.insert(a, *value);
});
}
};
});
memory.values().sum()
}
// main
pub fn run() -> Result<(u64, u64)> {
let data = utils::read_file("data/input-14.txt")?;
let answers = utils::read_i64s("data/output-14.txt")?;
let parsed = parse(&data);
let p1 = simulate1(&parsed);
let p2 = simulate2(&parsed);
assert_eq!(p1, answers[0] as u64);
assert_eq!(p2, answers[1] as u64);
Ok((p1, p2))
}