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