summaryrefslogtreecommitdiff
path: root/2020/rust/day08/src/intcode/mod.rs
diff options
context:
space:
mode:
Diffstat (limited to '2020/rust/day08/src/intcode/mod.rs')
-rw-r--r--2020/rust/day08/src/intcode/mod.rs134
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 { }