advent_of_code/2015/day07-some_assembly_required/src/lib.rs

87 lines
3.1 KiB
Rust

use std::collections::HashMap;
#[derive(Clone)]
pub enum Instruction {
And(String, String),
Or(String, String),
Not(String),
Lshift(String, u8),
Rshift(String, u8),
Equal(String),
}
impl Instruction {
fn parse(line: &str) -> (String, Instruction) {
let components: Vec<&str> = line.split(' ').collect();
match components[1] {
"->" => (components[2].to_string(), Instruction::Equal(components[0].to_string())),
"AND" => (components[4].to_string(), Instruction::And(components[0].to_string(), components[2].to_string())),
"OR" => (components[4].to_string(), Instruction::Or(components[0].to_string(), components[2].to_string())),
"LSHIFT" => (components[4].to_string(), Instruction::Lshift(components[0].to_string(), components[2].parse().unwrap())),
"RSHIFT" => (components[4].to_string(), Instruction::Rshift(components[0].to_string(), components[2].parse().unwrap())),
_ => (components[3].to_string(), Instruction::Not(components[1].to_string())),
}
}
}
pub fn eval_for(wire: String, circuit: &mut HashMap<String, Instruction>) -> u16 {
if let Ok(num) = wire.parse::<u16>() {
return num;
}
let instruction = Instruction::clone(circuit.get(&wire).unwrap_or_else(|| panic!("Wire not found: {wire}")));
let result = match instruction {
Instruction::Equal(val) => eval_for(val, circuit),
Instruction::Not(val) => !(eval_for(val, circuit)),
Instruction::And(l, r) => (eval_for(l, circuit)) & (eval_for(r, circuit)),
Instruction::Or(l, r) => (eval_for(l, circuit)) | (eval_for(r, circuit)),
Instruction::Lshift(val, bits) => eval_for(val, circuit) << bits,
Instruction::Rshift(val, bits) => eval_for(val, circuit) >> bits,
};
circuit.insert(wire, Instruction::Equal(result.to_string()));
result
}
pub fn assemble(input: &str) -> HashMap<String, Instruction> {
input.lines()
.map(Instruction::parse)
.collect()
}
#[cfg(test)]
mod tests {
use super::*;
use std::fs::read_to_string;
fn read_file(name: &str) -> String {
read_to_string(name).expect(&format!("Unable to read file: {}", name)[..])
}
#[test]
fn test_sample() {
let sample_input = read_file("tests/sample_input");
let mut circuit = assemble(&sample_input);
let expected = [
("d", 72),
("e", 507),
("f", 492),
("g", 114),
("h", 65412),
("i", 65079),
("x", 123),
("y", 456),
];
for (wire, output) in expected {
assert_eq!(eval_for(wire.to_string(), &mut circuit), output);
}
}
#[test]
fn test_challenge() {
let challenge_input = read_file("tests/challenge_input");
let mut circuit = assemble(&challenge_input);
let first_a = eval_for(String::from("a"), &mut circuit.clone());
assert_eq!(first_a, 46065);
circuit.insert(String::from("b"), Instruction::Equal(first_a.to_string()));
assert_eq!(eval_for(String::from("a"), &mut circuit), 14134);
}
}