use std::convert::TryFrom; use std::error::Error; use std::fmt; const DEBUG: bool = false; #[derive(Clone,Debug)] pub enum Instruction { Acc(Wordsize), Jmp(Wordsize), Nop(Wordsize), } #[derive(Debug)] pub enum InstructionError { InvalidOperation, InvalidArgument, Parse(std::num::ParseIntError), } impl fmt::Display for InstructionError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "InstructionError") } } impl Error for InstructionError { } impl TryFrom for Instruction { type Error = InstructionError; fn try_from(string: String) -> Result { Instruction::try_from(string.as_str()) } } impl TryFrom<&str> for Instruction { type Error = InstructionError; fn try_from(string: &str) -> Result { let mut iter = string.split(" "); let (op, arg) = (iter.next().ok_or(InstructionError::InvalidOperation)?, iter.next().ok_or(InstructionError::InvalidArgument)?); let num = arg.parse().map_err(InstructionError::Parse)?; match op { "nop" => Ok(Instruction::Nop(num)), "jmp" => Ok(Instruction::Jmp(num)), "acc" => Ok(Instruction::Acc(num)), _ => Err(InstructionError::InvalidOperation), } } } pub type Wordsize = i128; #[derive(Clone,Debug)] pub struct Registers { pub ip: usize, pub accumulator: Wordsize, } pub struct Intcode { program: Vec, registers: Registers, } impl Intcode { pub fn new() -> Intcode { Intcode { program: vec![], registers: Registers { accumulator: 0, ip: 0, } } } fn op_acc(&mut self, arg: &Wordsize) { self.registers.accumulator += arg; } fn op_jmp(&mut self, arg: &Wordsize) { if *arg >= 0 { self.registers.ip += *arg as usize; } else { self.registers.ip -= (*arg * -1) as usize; } } pub fn load(&mut self, program: &[Instruction]) { if DEBUG { eprintln!("{:?}", program); } self.program = program.into(); } pub fn regdump(&self) -> Registers { self.registers.clone() } pub fn step(&mut self) -> Result<(), IntcodeError>{ let op = match self.program.get(self.registers.ip) { Some(v) => v.clone(), None => return Err(IntcodeError::MemoryAccessViolation), }; if DEBUG { eprintln!("ip: {}, op: {:?}", self.registers.ip, op); } match op { Instruction::Acc(arg) => self.op_acc(&arg), Instruction::Jmp(arg) => self.op_jmp(&arg), Instruction::Nop(_) => {}, } match op { Instruction::Jmp(_) => {}, _ => self.registers.ip += 1, } Ok(()) } } #[derive(Debug)] pub enum IntcodeError { MemoryAccessViolation, } impl fmt::Display for IntcodeError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "IntcodeError") } } impl Error for IntcodeError { }