aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGravatar alecdwm 2019-12-05 17:54:16 +1000
committerGravatar alecdwm 2019-12-05 17:54:16 +1000
commit0f341778d756d82f22a37cad261953f74712c318 (patch)
tree9ec8476b8c6bfcfe5b1404edbbfed15489b6b742
parent44b9ea085771da52ce1eb3e690d00b721116a509 (diff)
added 2019 day5 part2 solution
-rw-r--r--src/main.rs1
-rw-r--r--src/year_2019/day5.rs102
-rw-r--r--src/year_2019/intcode_computer.rs81
3 files changed, 182 insertions, 2 deletions
diff --git a/src/main.rs b/src/main.rs
index 0ac047a..8b1b3b1 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -28,6 +28,7 @@ fn main() {
puzzle_solutions.insert("2019::day4::part1", advent_of_code::year_2019::day4::part1);
puzzle_solutions.insert("2019::day4::part2", advent_of_code::year_2019::day4::part2);
puzzle_solutions.insert("2019::day5::part1", advent_of_code::year_2019::day5::part1);
+ puzzle_solutions.insert("2019::day5::part2", advent_of_code::year_2019::day5::part2);
let command = match env::args().skip(1).next() {
Some(command) => command,
diff --git a/src/year_2019/day5.rs b/src/year_2019/day5.rs
index 33bd1c9..b74a7cc 100644
--- a/src/year_2019/day5.rs
+++ b/src/year_2019/day5.rs
@@ -57,7 +57,9 @@ pub fn part1() {
let input_tx = computer.create_input();
let output_rx = computer.create_output();
- input_tx.send(1).unwrap();
+ const TEST_SYSTEM_ID: i64 = 1;
+
+ input_tx.send(TEST_SYSTEM_ID).unwrap();
computer.run();
let mut diagnostic_code = 0;
@@ -75,6 +77,61 @@ pub fn part1() {
);
}
+/// The air conditioner comes online! Its cold air feels good for a while, but then the TEST alarms start to go off. Since the air conditioner can't vent its heat anywhere but back into the spacecraft, it's actually making the air inside the ship warmer.
+///
+/// Instead, you'll need to use the TEST to extend the thermal radiators. Fortunately, the diagnostic program (your puzzle input) is already equipped for this. Unfortunately, your Intcode computer is not.
+///
+/// Your computer is only missing a few opcodes:
+///
+/// Opcode 5 is jump-if-true: if the first parameter is non-zero, it sets the instruction pointer to the value from the second parameter. Otherwise, it does nothing.
+/// Opcode 6 is jump-if-false: if the first parameter is zero, it sets the instruction pointer to the value from the second parameter. Otherwise, it does nothing.
+/// Opcode 7 is less than: if the first parameter is less than the second parameter, it stores 1 in the position given by the third parameter. Otherwise, it stores 0.
+/// Opcode 8 is equals: if the first parameter is equal to the second parameter, it stores 1 in the position given by the third parameter. Otherwise, it stores 0.
+///
+/// Like all instructions, these instructions need to support parameter modes as described above.
+///
+/// Normally, after an instruction is finished, the instruction pointer increases by the number of values in that instruction. However, if the instruction modifies the instruction pointer, that value is used and the instruction pointer is not automatically increased.
+///
+/// For example, here are several programs that take one input, compare it to the value 8, and then produce one output:
+///
+/// 3,9,8,9,10,9,4,9,99,-1,8 - Using position mode, consider whether the input is equal to 8; output 1 (if it is) or 0 (if it is not).
+/// 3,9,7,9,10,9,4,9,99,-1,8 - Using position mode, consider whether the input is less than 8; output 1 (if it is) or 0 (if it is not).
+/// 3,3,1108,-1,8,3,4,3,99 - Using immediate mode, consider whether the input is equal to 8; output 1 (if it is) or 0 (if it is not).
+/// 3,3,1107,-1,8,3,4,3,99 - Using immediate mode, consider whether the input is less than 8; output 1 (if it is) or 0 (if it is not).
+///
+/// Here are some jump tests that take an input, then output 0 if the input was zero or 1 if the input was non-zero:
+///
+/// 3,12,6,12,15,1,13,14,13,4,13,99,-1,0,1,9 (using position mode)
+/// 3,3,1105,-1,9,1101,0,0,12,4,12,99,1 (using immediate mode)
+///
+/// Here's a larger example:
+///
+/// 3,21,1008,21,8,20,1005,20,22,107,8,21,20,1006,20,31,
+/// 1106,0,36,98,0,0,1002,21,125,20,4,20,1105,1,46,104,
+/// 999,1105,1,46,1101,1000,1,20,4,20,1105,1,46,98,99
+///
+/// The above example program uses an input instruction to ask for a single number. The program will then output 999 if the input value is below 8, output 1000 if the input value is equal to 8, or output 1001 if the input value is greater than 8.
+///
+/// This time, when the TEST diagnostic program runs its input instruction to get the ID of the system to test, provide it 5, the ID for the ship's thermal radiator controller. This diagnostic test suite only outputs one number, the diagnostic code.
+///
+/// What is the diagnostic code for system ID 5?
+pub fn part2() {
+ let input = crate::common::read_stdin_to_string();
+ let mut computer = IntcodeComputer::from(input.as_str());
+
+ let input_tx = computer.create_input();
+ let output_rx = computer.create_output();
+
+ const TEST_SYSTEM_ID: i64 = 5;
+
+ input_tx.send(TEST_SYSTEM_ID).unwrap();
+ computer.run();
+
+ let diagnostic_code = output_rx.recv().unwrap();
+
+ println!("The diagnostic code for system ID 5: {}", diagnostic_code);
+}
+
#[cfg(test)]
mod tests {
use super::*;
@@ -91,4 +148,47 @@ mod tests {
assert_eq!(output_rx.recv().unwrap(), 42);
}
+
+ #[test]
+ fn test_intcode_computer_part_2_comparison_examples() {
+ let examples = [
+ ("3,9,8,9,10,9,4,9,99,-1,8", 7, 0),
+ ("3,9,8,9,10,9,4,9,99,-1,8", 8, 1),
+ ("3,9,8,9,10,9,4,9,99,-1,8", 9, 0),
+ ("3,9,7,9,10,9,4,9,99,-1,8", 6, 1),
+ ("3,9,7,9,10,9,4,9,99,-1,8", 7, 1),
+ ("3,9,7,9,10,9,4,9,99,-1,8", 8, 0),
+ ("3,9,7,9,10,9,4,9,99,-1,8", 9, 0),
+ ("3,3,1108,-1,8,3,4,3,99", 7, 0),
+ ("3,3,1108,-1,8,3,4,3,99", 8, 1),
+ ("3,3,1108,-1,8,3,4,3,99", 9, 0),
+ ("3,3,1107,-1,8,3,4,3,99", 6, 1),
+ ("3,3,1107,-1,8,3,4,3,99", 7, 1),
+ ("3,3,1107,-1,8,3,4,3,99", 8, 0),
+ ("3,3,1107,-1,8,3,4,3,99", 9, 0),
+ ("3,12,6,12,15,1,13,14,13,4,13,99,-1,0,1,9", -1, 1),
+ ("3,12,6,12,15,1,13,14,13,4,13,99,-1,0,1,9", 0, 0),
+ ("3,12,6,12,15,1,13,14,13,4,13,99,-1,0,1,9", 1, 1),
+ ("3,12,6,12,15,1,13,14,13,4,13,99,-1,0,1,9", 2, 1),
+ ("3,3,1105,-1,9,1101,0,0,12,4,12,99,1", -1, 1),
+ ("3,3,1105,-1,9,1101,0,0,12,4,12,99,1", 0, 0),
+ ("3,3,1105,-1,9,1101,0,0,12,4,12,99,1", 1, 1),
+ ("3,3,1105,-1,9,1101,0,0,12,4,12,99,1", 2, 1),
+ ("3,21,1008,21,8,20,1005,20,22,107,8,21,20,1006,20,31,1106,0,36,98,0,0,1002,21,125,20,4,20,1105,1,46,104,999,1105,1,46,1101,1000,1,20,4,20,1105,1,46,98,99", 7, 999),
+ ("3,21,1008,21,8,20,1005,20,22,107,8,21,20,1006,20,31,1106,0,36,98,0,0,1002,21,125,20,4,20,1105,1,46,104,999,1105,1,46,1101,1000,1,20,4,20,1105,1,46,98,99", 8, 1000),
+ ("3,21,1008,21,8,20,1005,20,22,107,8,21,20,1006,20,31,1106,0,36,98,0,0,1002,21,125,20,4,20,1105,1,46,104,999,1105,1,46,1101,1000,1,20,4,20,1105,1,46,98,99", 9, 1001),
+ ];
+
+ for example in &examples {
+ let mut computer = IntcodeComputer::from(example.0);
+
+ let input_tx = computer.create_input();
+ let output_rx = computer.create_output();
+
+ input_tx.send(example.1).unwrap();
+ computer.run();
+
+ assert_eq!(output_rx.recv().unwrap(), example.2);
+ }
+ }
}
diff --git a/src/year_2019/intcode_computer.rs b/src/year_2019/intcode_computer.rs
index 418e891..79fd711 100644
--- a/src/year_2019/intcode_computer.rs
+++ b/src/year_2019/intcode_computer.rs
@@ -30,6 +30,7 @@ impl IntcodeComputer {
pub fn run(mut self) -> Self {
loop {
let next_instruction = IntcodeInstruction::from(&self);
+ let instruction_pointer_before_instruction = self.instruction_pointer;
let instruction_length = next_instruction.length();
match next_instruction {
@@ -78,10 +79,52 @@ impl IntcodeComputer {
.expect("Failed to send to output");
}
+ IntcodeInstruction::JumpIfTrue(test, jump_to) => {
+ if test.get_value(&self.memory) != 0 {
+ self.instruction_pointer =
+ jump_to.get_value(&self.memory).try_into().unwrap();
+ }
+ }
+
+ IntcodeInstruction::JumpIfFalse(test, jump_to) => {
+ if test.get_value(&self.memory) == 0 {
+ self.instruction_pointer =
+ jump_to.get_value(&self.memory).try_into().unwrap();
+ }
+ }
+
+ IntcodeInstruction::LessThan(one, two, output) => {
+ let one = one.get_value(&self.memory);
+ let two = two.get_value(&self.memory);
+
+ let output_value = if one < two { 1 } else { 0 };
+
+ let output_address = output
+ .get_address()
+ .expect("LessThan 'output' parameter must be an address");
+
+ self.memory.replace(output_address, output_value)
+ }
+
+ IntcodeInstruction::Equals(one, two, output) => {
+ let one = one.get_value(&self.memory);
+ let two = two.get_value(&self.memory);
+
+ let output_value = if one == two { 1 } else { 0 };
+
+ let output_address = output
+ .get_address()
+ .expect("LessThan 'output' parameter must be an address");
+
+ self.memory.replace(output_address, output_value)
+ }
+
IntcodeInstruction::Halt => break,
}
- self.instruction_pointer += instruction_length;
+ if instruction_pointer_before_instruction == self.instruction_pointer {
+ self.instruction_pointer += instruction_length;
+ }
}
self
@@ -124,6 +167,20 @@ enum IntcodeInstruction {
/// Sends a single integer to output from the first parameter
Output(IntcodeParameter),
+ /// If the first parameter is non-zero, sets the instruction pointer to the value of the second parameter.
+ JumpIfTrue(IntcodeParameter, IntcodeParameter),
+
+ /// If the first parameter is zero, sets the instruction pointer to the value of the second parameter.
+ JumpIfFalse(IntcodeParameter, IntcodeParameter),
+
+ /// If the first parameter is less than the second parameter, writes 1 to the third parameter.
+ /// Otherwise, writes 0 to the third parameter.
+ LessThan(IntcodeParameter, IntcodeParameter, IntcodeParameter),
+
+ /// If the first parameter is equal to the second parameter, writes 1 to the third parameter.
+ /// Otherwise, writes 0 to the third parameter.
+ Equals(IntcodeParameter, IntcodeParameter, IntcodeParameter),
+
/// Halts the IntcodeComputer
Halt,
}
@@ -135,6 +192,10 @@ impl IntcodeInstruction {
Self::Multiply(..) => 4,
Self::Input(..) => 2,
Self::Output(..) => 2,
+ Self::JumpIfTrue(..) => 3,
+ Self::JumpIfFalse(..) => 3,
+ Self::LessThan(..) => 4,
+ Self::Equals(..) => 4,
Self::Halt => 1,
}
}
@@ -163,6 +224,24 @@ impl From<&IntcodeComputer> for IntcodeInstruction {
Opcode(4) => {
Self::Output(parser.parse_next(state.memory.get(state.instruction_pointer + 1)))
}
+ Opcode(5) => Self::JumpIfTrue(
+ parser.parse_next(state.memory.get(state.instruction_pointer + 1)),
+ parser.parse_next(state.memory.get(state.instruction_pointer + 2)),
+ ),
+ Opcode(6) => Self::JumpIfFalse(
+ parser.parse_next(state.memory.get(state.instruction_pointer + 1)),
+ parser.parse_next(state.memory.get(state.instruction_pointer + 2)),
+ ),
+ Opcode(7) => Self::LessThan(
+ parser.parse_next(state.memory.get(state.instruction_pointer + 1)),
+ parser.parse_next(state.memory.get(state.instruction_pointer + 2)),
+ parser.parse_writeonly(state.memory.get(state.instruction_pointer + 3)),
+ ),
+ Opcode(8) => Self::Equals(
+ parser.parse_next(state.memory.get(state.instruction_pointer + 1)),
+ parser.parse_next(state.memory.get(state.instruction_pointer + 2)),
+ parser.parse_writeonly(state.memory.get(state.instruction_pointer + 3)),
+ ),
Opcode(99) => Self::Halt,
Opcode(other) => panic!("Invalid Opcode encountered: {}", other),
}