Add command buffer to intcode computer

This commit is contained in:
kageru 2019-12-13 10:20:29 +01:00
parent 6faab62f5e
commit 2ee1c8779d

View File

@ -3,6 +3,7 @@ pub struct IntComputer {
pub tape: Vec<i64>, pub tape: Vec<i64>,
pub params: Vec<i64>, pub params: Vec<i64>,
relative_base: i64, relative_base: i64,
cmd_buffer: Vec<Operation>,
} }
pub enum IntComputerResult { pub enum IntComputerResult {
@ -26,18 +27,19 @@ impl IntComputer {
tape, tape,
params, params,
relative_base: 0, relative_base: 0,
cmd_buffer: Vec::new(),
} }
} }
pub fn run(&mut self) -> IntComputerResult { pub fn run(&mut self) -> IntComputerResult {
loop { loop {
match self.decode_next() { match self.cmd_buffer.pop().unwrap_or_else(|| self.decode_next()) {
Some(op) => { Operation::Halt {} => return IntComputerResult::Halt,
if let Some(o) = self.execute(op) { op => {
if let Some(o) = self.execute(op.to_owned()) {
return IntComputerResult::Output(o); return IntComputerResult::Output(o);
} }
} }
None => return IntComputerResult::Halt,
} }
} }
} }
@ -73,7 +75,7 @@ impl IntComputer {
value value
} }
fn decode_next(&mut self) -> Option<Operation> { fn decode_next(&mut self) -> Operation {
let next = self.get_next(Mode::Immediate); let next = self.get_next(Mode::Immediate);
let mut full_opcode: Vec<_> = next.to_string().chars().collect(); let mut full_opcode: Vec<_> = next.to_string().chars().collect();
full_opcode.reverse(); full_opcode.reverse();
@ -82,50 +84,50 @@ impl IntComputer {
full_opcode[0], full_opcode[0],
]; ];
match raw_opcode { match raw_opcode {
['0', '1'] => Some(Operation::Add { ['0', '1'] => Operation::Add {
x: self.get_next(get_mode(&full_opcode, ParameterPosition::First)), x: self.get_next(get_mode(&full_opcode, ParameterPosition::First)),
y: self.get_next(get_mode(&full_opcode, ParameterPosition::Second)), y: self.get_next(get_mode(&full_opcode, ParameterPosition::Second)),
addr: self.get_next_address(get_mode(&full_opcode, ParameterPosition::Third)) addr: self.get_next_address(get_mode(&full_opcode, ParameterPosition::Third))
as usize, as usize,
}), },
['0', '2'] => Some(Operation::Multiply { ['0', '2'] => Operation::Multiply {
x: self.get_next(get_mode(&full_opcode, ParameterPosition::First)), x: self.get_next(get_mode(&full_opcode, ParameterPosition::First)),
y: self.get_next(get_mode(&full_opcode, ParameterPosition::Second)), y: self.get_next(get_mode(&full_opcode, ParameterPosition::Second)),
addr: self.get_next_address(get_mode(&full_opcode, ParameterPosition::Third)) addr: self.get_next_address(get_mode(&full_opcode, ParameterPosition::Third))
as usize, as usize,
}), },
['0', '3'] => Some(Operation::Input { ['0', '3'] => Operation::Input {
value: self.params.pop().unwrap(), value: self.params.pop().unwrap(),
addr: self.get_next_address(get_mode(&full_opcode, ParameterPosition::First)) addr: self.get_next_address(get_mode(&full_opcode, ParameterPosition::First))
as usize, as usize,
}), },
['0', '4'] => Some(Operation::Output { ['0', '4'] => Operation::Output {
value: self.get_next(get_mode(&full_opcode, ParameterPosition::First)), value: self.get_next(get_mode(&full_opcode, ParameterPosition::First)),
}), },
['0', '5'] => Some(Operation::JumpIfTrue { ['0', '5'] => Operation::JumpIfTrue {
value: self.get_next(get_mode(&full_opcode, ParameterPosition::First)), value: self.get_next(get_mode(&full_opcode, ParameterPosition::First)),
addr: self.get_next(get_mode(&full_opcode, ParameterPosition::Second)) as usize, addr: self.get_next(get_mode(&full_opcode, ParameterPosition::Second)) as usize,
}), },
['0', '6'] => Some(Operation::JumpIfFalse { ['0', '6'] => Operation::JumpIfFalse {
value: self.get_next(get_mode(&full_opcode, ParameterPosition::First)), value: self.get_next(get_mode(&full_opcode, ParameterPosition::First)),
addr: self.get_next(get_mode(&full_opcode, ParameterPosition::Second)) as usize, addr: self.get_next(get_mode(&full_opcode, ParameterPosition::Second)) as usize,
}), },
['0', '7'] => Some(Operation::LessThan { ['0', '7'] => Operation::LessThan {
first: self.get_next(get_mode(&full_opcode, ParameterPosition::First)), first: self.get_next(get_mode(&full_opcode, ParameterPosition::First)),
second: self.get_next(get_mode(&full_opcode, ParameterPosition::Second)), second: self.get_next(get_mode(&full_opcode, ParameterPosition::Second)),
addr: self.get_next_address(get_mode(&full_opcode, ParameterPosition::Third)) addr: self.get_next_address(get_mode(&full_opcode, ParameterPosition::Third))
as usize, as usize,
}), },
['0', '8'] => Some(Operation::Equals { ['0', '8'] => Operation::Equals {
first: self.get_next(get_mode(&full_opcode, ParameterPosition::First)), first: self.get_next(get_mode(&full_opcode, ParameterPosition::First)),
second: self.get_next(get_mode(&full_opcode, ParameterPosition::Second)), second: self.get_next(get_mode(&full_opcode, ParameterPosition::Second)),
addr: self.get_next_address(get_mode(&full_opcode, ParameterPosition::Third)) addr: self.get_next_address(get_mode(&full_opcode, ParameterPosition::Third))
as usize, as usize,
}), },
['0', '9'] => Some(Operation::AdjustRelativeBase { ['0', '9'] => Operation::AdjustRelativeBase {
value: self.get_next(get_mode(&full_opcode, ParameterPosition::First)), value: self.get_next(get_mode(&full_opcode, ParameterPosition::First)),
}), },
['9', '9'] => None, ['9', '9'] => Operation::Halt {},
_ => unreachable!("Unknown opcode"), _ => unreachable!("Unknown opcode"),
} }
} }
@ -165,6 +167,7 @@ impl IntComputer {
Operation::Output { value } => { Operation::Output { value } => {
return Some(value); return Some(value);
} }
Operation::Halt {} => unreachable!(),
}; };
None None
} }
@ -175,7 +178,7 @@ fn get_mode(raw_opcode: &[char], pos: ParameterPosition) -> Mode {
raw_opcode.get::<usize>(pos.into()).unwrap_or(&'0').into() raw_opcode.get::<usize>(pos.into()).unwrap_or(&'0').into()
} }
#[derive(Debug)] #[derive(Debug, Clone)]
enum Operation { enum Operation {
Add { Add {
x: i64, x: i64,
@ -215,6 +218,7 @@ enum Operation {
AdjustRelativeBase { AdjustRelativeBase {
value: i64, value: i64,
}, },
Halt {},
} }
#[derive(Debug)] #[derive(Debug)]