2019: day05: part 2
This commit is contained in:
parent
6e1c3c989f
commit
6202a3b1fd
|
@ -5,6 +5,8 @@ const INPUT: &str = include_str!("../input/day05.txt");
|
||||||
|
|
||||||
pub fn run() -> Result<()> {
|
pub fn run() -> Result<()> {
|
||||||
println!("part 1: {}", part1(INPUT)?);
|
println!("part 1: {}", part1(INPUT)?);
|
||||||
|
println!("part 2: {}", part2(INPUT)?);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,6 +19,15 @@ fn part1(input: &str) -> Result<i64> {
|
||||||
.ok_or_else(|| err!("intcode gave no output"))
|
.ok_or_else(|| err!("intcode gave no output"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn part2(input: &str) -> Result<i64> {
|
||||||
|
let mut intcode = Intcode::new(input)?;
|
||||||
|
intcode.add_input(5);
|
||||||
|
intcode.run()?;
|
||||||
|
intcode
|
||||||
|
.get_output()
|
||||||
|
.ok_or_else(|| err!("intcode gave no output"))
|
||||||
|
}
|
||||||
|
|
||||||
enum Parameter {
|
enum Parameter {
|
||||||
Position(usize),
|
Position(usize),
|
||||||
Immediate(i64),
|
Immediate(i64),
|
||||||
|
@ -67,6 +78,10 @@ enum Opcode {
|
||||||
Multiply(Parameter, Parameter, Parameter),
|
Multiply(Parameter, Parameter, Parameter),
|
||||||
Input(Parameter),
|
Input(Parameter),
|
||||||
Output(Parameter),
|
Output(Parameter),
|
||||||
|
JumpTrue(Parameter, Parameter),
|
||||||
|
JumpFalse(Parameter, Parameter),
|
||||||
|
LessThan(Parameter, Parameter, Parameter),
|
||||||
|
Equals(Parameter, Parameter, Parameter),
|
||||||
Halt,
|
Halt,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -138,6 +153,40 @@ impl Intcode {
|
||||||
|
|
||||||
Ok(Opcode::Output(op))
|
Ok(Opcode::Output(op))
|
||||||
}
|
}
|
||||||
|
5 => {
|
||||||
|
let test = Parameter::new(instruction / 100, self.memory.get(self.ip + 1))?;
|
||||||
|
let dst = Parameter::new(instruction / 1000, self.memory.get(self.ip + 2))?;
|
||||||
|
|
||||||
|
Ok(Opcode::JumpTrue(test, dst))
|
||||||
|
}
|
||||||
|
6 => {
|
||||||
|
let test = Parameter::new(instruction / 100, self.memory.get(self.ip + 1))?;
|
||||||
|
let dst = Parameter::new(instruction / 1000, self.memory.get(self.ip + 2))?;
|
||||||
|
|
||||||
|
Ok(Opcode::JumpFalse(test, dst))
|
||||||
|
}
|
||||||
|
7 => {
|
||||||
|
let op1 = Parameter::new(instruction / 100, self.memory.get(self.ip + 1))?;
|
||||||
|
let op2 = Parameter::new(instruction / 1000, self.memory.get(self.ip + 2))?;
|
||||||
|
let dst = Parameter::new(instruction / 10000, self.memory.get(self.ip + 3))?;
|
||||||
|
|
||||||
|
if let Parameter::Immediate(_) = dst {
|
||||||
|
Err(err!("less than: destination parameter can't be immediate"))
|
||||||
|
} else {
|
||||||
|
Ok(Opcode::LessThan(op1, op2, dst))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
8 => {
|
||||||
|
let op1 = Parameter::new(instruction / 100, self.memory.get(self.ip + 1))?;
|
||||||
|
let op2 = Parameter::new(instruction / 1000, self.memory.get(self.ip + 2))?;
|
||||||
|
let dst = Parameter::new(instruction / 10000, self.memory.get(self.ip + 3))?;
|
||||||
|
|
||||||
|
if let Parameter::Immediate(_) = dst {
|
||||||
|
Err(err!("equals: destination parameter can't be immediate"))
|
||||||
|
} else {
|
||||||
|
Ok(Opcode::Equals(op1, op2, dst))
|
||||||
|
}
|
||||||
|
}
|
||||||
99 => Ok(Opcode::Halt),
|
99 => Ok(Opcode::Halt),
|
||||||
_ => Err(err!("unknown opcode: {}", opcode)),
|
_ => Err(err!("unknown opcode: {}", opcode)),
|
||||||
}
|
}
|
||||||
|
@ -193,6 +242,62 @@ impl Intcode {
|
||||||
|
|
||||||
self.ip += 2;
|
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"))?;
|
||||||
|
|
||||||
|
if val != 0 {
|
||||||
|
self.ip = dst as usize;
|
||||||
|
} else {
|
||||||
|
self.ip += 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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"))?;
|
||||||
|
|
||||||
|
if val == 0 {
|
||||||
|
self.ip = dst as usize;
|
||||||
|
} else {
|
||||||
|
self.ip += 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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 res = if val1 < val2 { 1 } else { 0 };
|
||||||
|
dst.set(&mut self.memory, res)?;
|
||||||
|
|
||||||
|
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 res = if val1 == val2 { 1 } else { 0 };
|
||||||
|
dst.set(&mut self.memory, res)?;
|
||||||
|
|
||||||
|
self.ip += 4;
|
||||||
|
}
|
||||||
Opcode::Halt => break Ok(()),
|
Opcode::Halt => break Ok(()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -219,4 +324,9 @@ mod tests {
|
||||||
fn part1_real() {
|
fn part1_real() {
|
||||||
assert_eq!(part1(INPUT).unwrap(), 16225258);
|
assert_eq!(part1(INPUT).unwrap(), 16225258);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn part2_real() {
|
||||||
|
assert_eq!(part2(INPUT).unwrap(), 2808771);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue