AoC2020/src/day14.rs

121 lines
2.9 KiB
Rust

use std::io::BufRead;
use std::str::FromStr;
use std::collections::HashMap;
#[derive(Debug)]
struct Mask {
zeros: u64,
ones: u64,
}
impl FromStr for Mask {
type Err = ();
fn from_str(s: &str) -> Result<Self, Self::Err> {
// Mask is like XXXXXXXXXXXXXXXXXXXXXXXXXXXXX1XXXX0X
// Insert ones when char is 1, zero when char is 0, don't do anything if X
// Struct can be used as masked = (number | ones) & zeros
Ok(Mask {
zeros: u64::from_str_radix(&s.replace('X', "1"), 2).unwrap(),
ones: u64::from_str_radix(&s.replace('X', "0"), 2).unwrap(),
})
}
}
impl Mask {
fn id() -> Self {
Mask {
// Mask are 36 bits integers
zeros: u64::from_str_radix(&"1".repeat(36), 2).unwrap(),
ones: u64::from_str_radix(&"0".repeat(36), 2).unwrap(),
}
}
fn apply(&self, value: u64) -> u64 {
(value | self.ones) & self.zeros
}
}
#[derive(Debug)]
enum Instruction {
ChangeMask(Mask),
AssignMemory {
address: usize,
value: u64,
}
}
impl FromStr for Instruction {
type Err = ();
fn from_str(s: &str) -> Result<Self, Self::Err> {
let mut splitted = s.split(" = ");
let instruction = splitted.next().unwrap();
let value = splitted.next().unwrap();
Ok(if instruction == "mask" {
Instruction::ChangeMask(value.parse().unwrap())
} else {
Instruction::AssignMemory {
address: instruction.trim_end_matches(']').trim_start_matches("mem[").parse().unwrap(),
value: value.parse().unwrap()
}
})
}
}
#[derive(Debug)]
struct Program {
instructions: Vec<Instruction>,
memory: HashMap<usize, u64>,
mask: Mask,
}
impl Program {
fn run(&mut self) {
for instruction in self.instructions.drain(..) {
match instruction {
Instruction::ChangeMask(mask) => self.mask = mask,
Instruction::AssignMemory { value, address } => {
self.memory.insert(address, self.mask.apply(value));
}
}
}
}
}
impl Program {
fn build(instructions: Vec<Instruction>) -> Self {
Program {
instructions,
mask: Mask::id(),
memory: HashMap::new(),
}
}
}
pub fn run_part1<F: BufRead> (input: F) -> u64 {
let instructions: Vec<Instruction> = input.lines()
.filter_map(|line| line.unwrap().parse().ok())
.collect();
let mut program = Program::build(instructions);
program.run();
program.memory.values().sum()
}
pub fn part1<F: BufRead> (input: F) {
println!("{}", run_part1(input))
}
#[cfg(test)]
mod test {
use super::*;
#[test]
pub fn test_parse() {
let input = r#"mask = XXXXXXXXXXXXXXXXXXXXXXXXXXXXX1XXXX0X
mem[8] = 11
mem[7] = 101
mem[8] = 0"#.as_bytes();
assert_eq!(run_part1(input), 165);
}
}