diff options
Diffstat (limited to '2020/rust/day08/src/intcode/mod.rs')
-rw-r--r-- | 2020/rust/day08/src/intcode/mod.rs | 134 |
1 files changed, 134 insertions, 0 deletions
diff --git a/2020/rust/day08/src/intcode/mod.rs b/2020/rust/day08/src/intcode/mod.rs new file mode 100644 index 0000000..5ec50e3 --- /dev/null +++ b/2020/rust/day08/src/intcode/mod.rs @@ -0,0 +1,134 @@ +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<String> for Instruction { + type Error = InstructionError; + + fn try_from(string: String) -> Result<Self, Self::Error> { + Instruction::try_from(string.as_str()) + } +} + +impl TryFrom<&str> for Instruction { + type Error = InstructionError; + + fn try_from(string: &str) -> Result<Self, Self::Error> { + 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<Instruction>, + 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 { } |