AoC2020/src/day14part2.rs

143 lines
3.7 KiB
Rust

use std::io::BufRead;
use std::str::FromStr;
use std::collections::{HashMap, VecDeque};
#[derive(Debug)]
struct Mask {
value: VecDeque<char>
}
impl FromStr for Mask {
type Err = ();
fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(Mask {
value: s.chars().collect()
})
}
}
impl Mask {
fn id() -> Self {
Mask {
value: "0".repeat(36).chars().collect()
}
}
fn apply(&self, value: u64) -> Vec<String> {
let input: VecDeque<_> = format!("{:036b}", value).chars().collect();
let mut res = Vec::new();
self.apply_rec(self.value.clone(), input, Vec::new(), &mut res);
res
}
fn apply_rec(&self, mut mask: VecDeque<char>, mut input: VecDeque<char>, mut output: Vec<char>, acc: &mut Vec<String>) {
match mask.pop_front() {
None => acc.push(output.iter().collect()),
Some('0') => {
output.push(input.pop_front().unwrap());
self.apply_rec(mask, input, output, acc)
},
Some('1') => {
input.pop_front().unwrap();
output.push('1');
self.apply_rec(mask, input, output, acc)
},
Some('X') => {
input.pop_front().unwrap();
let mut output_zero = output.clone();
output_zero.push('0');
self.apply_rec(mask.clone(), input.clone(), output_zero, acc);
output.push('1');
self.apply_rec(mask, input, output, acc);
},
_ => unreachable!()
}
}
}
#[derive(Debug)]
enum Instruction {
ChangeMask(Mask),
AssignMemory {
address: u64,
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<String, 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 } => {
for addr_variant in self.mask.apply(address).drain(..) {
self.memory.insert(addr_variant, value);
}
}
}
}
}
}
impl Program {
fn build(instructions: Vec<Instruction>) -> Self {
Program {
instructions,
mask: Mask::id(),
memory: HashMap::new(),
}
}
}
pub fn run_part2<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 part2<F: BufRead> (input: F) {
println!("{}", run_part2(input))
}
#[cfg(test)]
mod test {
use super::*;
#[test]
pub fn test_parse() {
let input = r#"mask = 000000000000000000000000000000X1001X
mem[42] = 100
mask = 00000000000000000000000000000000X0XX
mem[26] = 1"#.as_bytes();
assert_eq!(run_part2(input), 208);
}
}