2019: day05: refactor intcode

This commit is contained in:
Antoine Martin 2019-12-07 17:22:52 +01:00
parent 7eca1339d7
commit 5246fce2ef

View file

@ -56,10 +56,13 @@ impl Parameter {
}
}
fn get(&self, memory: &[i64]) -> Option<i64> {
fn get(&self, memory: &[i64]) -> Result<i64> {
match self {
Parameter::Position(address) => memory.get(*address).copied(),
Parameter::Immediate(value) => Some(*value),
Parameter::Position(address) => match memory.get(*address) {
Some(val) => Ok(*val),
None => Err(err!("read out of bounds at address {}", address)),
},
Parameter::Immediate(value) => Ok(*value),
}
}
@ -120,13 +123,14 @@ impl Intcode {
let instruction = self.memory[self.ip];
let opcode = instruction % 100;
let mode1 = instruction / 100;
let mode2 = instruction / 1000;
let mode3 = instruction / 10000;
match opcode {
1 => {
let op1 = Parameter::new(instruction / 100, self.memory.get(self.ip + 1).copied())?;
let op2 =
Parameter::new(instruction / 1000, self.memory.get(self.ip + 2).copied())?;
let dst =
Parameter::new(instruction / 10000, self.memory.get(self.ip + 3).copied())?;
let op1 = Parameter::new(mode1, self.memory.get(self.ip + 1).copied())?;
let op2 = Parameter::new(mode2, self.memory.get(self.ip + 2).copied())?;
let dst = Parameter::new(mode3, self.memory.get(self.ip + 3).copied())?;
if let Parameter::Immediate(_) = dst {
Err(err!("add: destination parameter can't be immediate"))
@ -135,11 +139,9 @@ impl Intcode {
}
}
2 => {
let op1 = Parameter::new(instruction / 100, self.memory.get(self.ip + 1).copied())?;
let op2 =
Parameter::new(instruction / 1000, self.memory.get(self.ip + 2).copied())?;
let dst =
Parameter::new(instruction / 10000, self.memory.get(self.ip + 3).copied())?;
let op1 = Parameter::new(mode1, self.memory.get(self.ip + 1).copied())?;
let op2 = Parameter::new(mode2, self.memory.get(self.ip + 2).copied())?;
let dst = Parameter::new(mode3, self.memory.get(self.ip + 3).copied())?;
if let Parameter::Immediate(_) = dst {
Err(err!("multiply: destination parameter can't be immediate"))
@ -148,7 +150,7 @@ impl Intcode {
}
}
3 => {
let dst = Parameter::new(instruction / 100, self.memory.get(self.ip + 1).copied())?;
let dst = Parameter::new(mode1, self.memory.get(self.ip + 1).copied())?;
if let Parameter::Immediate(_) = dst {
Err(err!("input: destination parameter can't be immediate"))
@ -157,32 +159,26 @@ impl Intcode {
}
}
4 => {
let op = Parameter::new(instruction / 100, self.memory.get(self.ip + 1).copied())?;
let op = Parameter::new(mode1, self.memory.get(self.ip + 1).copied())?;
Ok(Opcode::Output(op))
}
5 => {
let test =
Parameter::new(instruction / 100, self.memory.get(self.ip + 1).copied())?;
let dst =
Parameter::new(instruction / 1000, self.memory.get(self.ip + 2).copied())?;
let test = Parameter::new(mode1, self.memory.get(self.ip + 1).copied())?;
let dst = Parameter::new(mode2, self.memory.get(self.ip + 2).copied())?;
Ok(Opcode::JumpTrue(test, dst))
}
6 => {
let test =
Parameter::new(instruction / 100, self.memory.get(self.ip + 1).copied())?;
let dst =
Parameter::new(instruction / 1000, self.memory.get(self.ip + 2).copied())?;
let test = Parameter::new(mode1, self.memory.get(self.ip + 1).copied())?;
let dst = Parameter::new(mode2, self.memory.get(self.ip + 2).copied())?;
Ok(Opcode::JumpFalse(test, dst))
}
7 => {
let op1 = Parameter::new(instruction / 100, self.memory.get(self.ip + 1).copied())?;
let op2 =
Parameter::new(instruction / 1000, self.memory.get(self.ip + 2).copied())?;
let dst =
Parameter::new(instruction / 10000, self.memory.get(self.ip + 3).copied())?;
let op1 = Parameter::new(mode1, self.memory.get(self.ip + 1).copied())?;
let op2 = Parameter::new(mode2, self.memory.get(self.ip + 2).copied())?;
let dst = Parameter::new(mode3, self.memory.get(self.ip + 3).copied())?;
if let Parameter::Immediate(_) = dst {
Err(err!("less than: destination parameter can't be immediate"))
@ -191,11 +187,9 @@ impl Intcode {
}
}
8 => {
let op1 = Parameter::new(instruction / 100, self.memory.get(self.ip + 1).copied())?;
let op2 =
Parameter::new(instruction / 1000, self.memory.get(self.ip + 2).copied())?;
let dst =
Parameter::new(instruction / 10000, self.memory.get(self.ip + 3).copied())?;
let op1 = Parameter::new(mode1, self.memory.get(self.ip + 1).copied())?;
let op2 = Parameter::new(mode2, self.memory.get(self.ip + 2).copied())?;
let dst = Parameter::new(mode3, self.memory.get(self.ip + 3).copied())?;
if let Parameter::Immediate(_) = dst {
Err(err!("equals: destination parameter can't be immediate"))
@ -218,24 +212,16 @@ impl Intcode {
match opcode {
Opcode::Add(op1, op2, dst) => {
let val1 = op1
.get(&self.memory)
.ok_or_else(|| err!("add: op1 out of bounds"))?;
let val2 = op2
.get(&self.memory)
.ok_or_else(|| err!("add: op1 out of bounds"))?;
let val1 = op1.get(&self.memory)?;
let val2 = op2.get(&self.memory)?;
dst.set(&mut self.memory, val1 + val2)?;
self.ip += 4;
}
Opcode::Multiply(op1, op2, dst) => {
let val1 = op1
.get(&self.memory)
.ok_or_else(|| err!("add: op1 out of bounds"))?;
let val2 = op2
.get(&self.memory)
.ok_or_else(|| err!("add: op1 out of bounds"))?;
let val1 = op1.get(&self.memory)?;
let val2 = op2.get(&self.memory)?;
dst.set(&mut self.memory, val1 * val2)?;
@ -251,21 +237,17 @@ impl Intcode {
self.ip += 2;
}
Opcode::Output(op) => {
let val = op
.get(&self.memory)
.ok_or_else(|| err!("output: op out of bounds"))?;
let val = op.get(&self.memory)?;
self.output.push(val);
self.ip += 2;
}
Opcode::JumpTrue(test, dst) => {
let val = test
.get(&self.memory)
.ok_or_else(|| err!("jump true: op out of bounds"))?;
let dst = dst
.get(&self.memory)
.filter(|dst| *dst >= 0)
.ok_or_else(|| err!("jump true: op out of bounds"))?;
let val = test.get(&self.memory)?;
let dst = dst.get(&self.memory)?;
if dst < 0 {
return Err(err!("dst must be a valid address: {}", dst));
}
if val != 0 {
self.ip = dst as usize;
@ -274,13 +256,11 @@ impl Intcode {
}
}
Opcode::JumpFalse(test, dst) => {
let val = test
.get(&self.memory)
.ok_or_else(|| err!("jump false: op out of bounds"))?;
let dst = dst
.get(&self.memory)
.filter(|dst| *dst >= 0)
.ok_or_else(|| err!("jump false: op out of bounds"))?;
let val = test.get(&self.memory)?;
let dst = dst.get(&self.memory)?;
if dst < 0 {
return Err(err!("dst must be a valid address: {}", dst));
}
if val == 0 {
self.ip = dst as usize;
@ -289,12 +269,8 @@ impl Intcode {
}
}
Opcode::LessThan(op1, op2, dst) => {
let val1 = op1
.get(&self.memory)
.ok_or_else(|| err!("less than: op1 out of bounds"))?;
let val2 = op2
.get(&self.memory)
.ok_or_else(|| err!("less than: op1 out of bounds"))?;
let val1 = op1.get(&self.memory)?;
let val2 = op2.get(&self.memory)?;
let res = if val1 < val2 { 1 } else { 0 };
dst.set(&mut self.memory, res)?;
@ -302,12 +278,8 @@ impl Intcode {
self.ip += 4;
}
Opcode::Equals(op1, op2, dst) => {
let val1 = op1
.get(&self.memory)
.ok_or_else(|| err!("equals: op1 out of bounds"))?;
let val2 = op2
.get(&self.memory)
.ok_or_else(|| err!("equals: op1 out of bounds"))?;
let val1 = op1.get(&self.memory)?;
let val2 = op2.get(&self.memory)?;
let res = if val1 == val2 { 1 } else { 0 };
dst.set(&mut self.memory, res)?;