121 lines
2.9 KiB
Rust
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);
|
|
}
|
|
}
|