extern crate advent_of_code_2018; use advent_of_code_2018::*; use std::error::Error; use std::path::PathBuf; use std::collections::{HashMap, HashSet}; // cargo watch -cs "cargo run --release --bin day_16" struct Instruction { op: Op, a: i32, b: i32, c: i32 } impl Instruction { fn execute(&self, registers: &[i32; 4]) -> [i32; 4] { use Op::*; let mut result_registers = registers.clone(); result_registers[self.c as usize] = match self.op { Addr => registers[self.a as usize] + registers[self.b as usize], Addi => registers[self.a as usize] + self.b, Mulr => registers[self.a as usize] * registers[self.b as usize], Muli => registers[self.a as usize] * self.b, Banr => registers[self.a as usize] & registers[self.b as usize], Bani => registers[self.a as usize] & self.b, Borr => registers[self.a as usize] | registers[self.b as usize], Bori => registers[self.a as usize] | self.b, Setr => registers[self.a as usize], Seti => self.a, Gtir => if self.a > registers[self.b as usize] { 1 } else { 0 }, Gtri => if registers[self.a as usize] > self.b { 1 } else { 0 }, Gtrr => if registers[self.a as usize] > registers[self.b as usize] { 1 } else { 0 }, Eqir => if self.a == registers[self.b as usize] { 1 } else { 0 }, Eqri => if registers[self.a as usize] == self.b { 1 } else { 0 }, Eqrr => if registers[self.a as usize] == registers[self.b as usize] { 1 } else { 0 } }; result_registers } } #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] enum Op { Addr, Addi, Mulr, Muli, Banr, Bani, Borr, Bori, Setr, Seti, Gtir, Gtri, Gtrr, Eqir, Eqri, Eqrr } impl Op { fn all() -> [Op; 16] { use Op::*; [ Addr, Addi, Mulr, Muli, Banr, Bani, Borr, Bori, Setr, Seti, Gtir, Gtri, Gtrr, Eqir, Eqri, Eqrr ] } } struct UnknownInstruction { before: [i32; 4], after: [i32; 4], opcode: i32, a: i32, b: i32, c: i32 } impl UnknownInstruction { fn possible_matches(&self) -> HashSet { Op::all() .iter() .filter(|&&op| { let instruction = Instruction { op: op, a: self.a, b: self.b, c: self.c }; let result = instruction.execute(&self.before); result == self.after }) .cloned() .collect() } } fn main() -> Result<(), Box> { let input_part_1 = read_file(&PathBuf::from("inputs/16_1.txt"))?; let unknown_instructions: Vec = input_part_1.chunks(3) .map(|chunk| { let mut before_iter = chunk[0].trim_matches(|c: char| !c.is_numeric()).split(", ").map(|c| c.parse::().unwrap()); let before = [ before_iter.next().unwrap(), before_iter.next().unwrap(), before_iter.next().unwrap(), before_iter.next().unwrap(), ]; let mut after_iter = chunk[2].trim_matches(|c: char| !c.is_numeric()).split(", ").map(|c| c.parse::().unwrap()); let after = [ after_iter.next().unwrap(), after_iter.next().unwrap(), after_iter.next().unwrap(), after_iter.next().unwrap(), ]; let mut instruction_iter = chunk[1].split_whitespace().map(|c| c.parse::().unwrap()); UnknownInstruction { before, after, opcode: instruction_iter.next().unwrap(), a: instruction_iter.next().unwrap(), b: instruction_iter.next().unwrap(), c: instruction_iter.next().unwrap(), } }) .collect(); let matches_more_then_3 = unknown_instructions.iter() .filter(|unknown| { unknown.possible_matches().len() >= 3 }) .count(); debug!(matches_more_then_3); let mut opcodes: HashMap> = HashMap::new(); for unknown in unknown_instructions { let matches = unknown.possible_matches(); let to_insert = match opcodes.get(&unknown.opcode) { None => matches, Some(existing) => existing.intersection(&matches).cloned().collect() }; opcodes.insert(unknown.opcode, to_insert); } debug!(opcodes); let mut known_opcodes: HashMap = HashMap::new(); while known_opcodes.len() < 16 { let (opcode, op) = { let (opcode, opset) = opcodes.iter().find(|(_,set)| set.len() == 1).unwrap(); let op = opset.iter().next().unwrap().clone(); (opcode.clone(), op) }; known_opcodes.insert(opcode, op); opcodes.iter_mut().for_each(|(_, set)| { set.remove(&op); }); } debug!(known_opcodes); let input_part_2 = read_file(&PathBuf::from("inputs/16_2.txt"))?; let instructions: Vec = input_part_2.iter() .map(|line| { let mut instruction_iter = line.split_whitespace().map(|c| c.parse::().unwrap()); Instruction { op: known_opcodes.get(&instruction_iter.next().unwrap()).unwrap().clone(), a: instruction_iter.next().unwrap(), b: instruction_iter.next().unwrap(), c: instruction_iter.next().unwrap(), } }) .collect(); let mut registers = [0; 4]; for instruction in instructions { registers = instruction.execute(®isters); } debug!(registers); Ok(()) }