From 6dd5bf55beee6aad144089025e8407c81ee13327 Mon Sep 17 00:00:00 2001 From: "Eric N. Vander Weele" Date: Mon, 4 Mar 2024 10:45:52 -0500 Subject: [PATCH] 2019: Day 5 --- 2019/Makefile | 1 + 2019/input_05.txt | 1 + 2019/src/bin/puzzle_02.rs | 2 +- 2019/src/bin/puzzle_05.rs | 20 +++++ 2019/src/intcode.rs | 153 +++++++++++++++++++++++++++++++++----- 5 files changed, 156 insertions(+), 21 deletions(-) create mode 100644 2019/input_05.txt create mode 100644 2019/src/bin/puzzle_05.rs diff --git a/2019/Makefile b/2019/Makefile index d6a7e34..8312c44 100644 --- a/2019/Makefile +++ b/2019/Makefile @@ -32,6 +32,7 @@ $(outputdir)/puzzle_%: $(srcbindir)/puzzle_%$(ext) $(CARGO) build --profile $(PROFILE) --bin $(basename $(notdir $<)) $(outputdir)/puzzle_02: $(intcode_deps) +$(outputdir)/puzzle_05: $(intcode_deps) .PHONY: lint lint: lint-code lint-format diff --git a/2019/input_05.txt b/2019/input_05.txt new file mode 100644 index 0000000..04bbec4 --- /dev/null +++ b/2019/input_05.txt @@ -0,0 +1 @@ +3,225,1,225,6,6,1100,1,238,225,104,0,1101,72,36,225,1101,87,26,225,2,144,13,224,101,-1872,224,224,4,224,102,8,223,223,1001,224,2,224,1,223,224,223,1102,66,61,225,1102,25,49,224,101,-1225,224,224,4,224,1002,223,8,223,1001,224,5,224,1,223,224,223,1101,35,77,224,101,-112,224,224,4,224,102,8,223,223,1001,224,2,224,1,223,224,223,1002,195,30,224,1001,224,-2550,224,4,224,1002,223,8,223,1001,224,1,224,1,224,223,223,1102,30,44,225,1102,24,21,225,1,170,117,224,101,-46,224,224,4,224,1002,223,8,223,101,5,224,224,1,224,223,223,1102,63,26,225,102,74,114,224,1001,224,-3256,224,4,224,102,8,223,223,1001,224,3,224,1,224,223,223,1101,58,22,225,101,13,17,224,101,-100,224,224,4,224,1002,223,8,223,101,6,224,224,1,224,223,223,1101,85,18,225,1001,44,7,224,101,-68,224,224,4,224,102,8,223,223,1001,224,5,224,1,223,224,223,4,223,99,0,0,0,677,0,0,0,0,0,0,0,0,0,0,0,1105,0,99999,1105,227,247,1105,1,99999,1005,227,99999,1005,0,256,1105,1,99999,1106,227,99999,1106,0,265,1105,1,99999,1006,0,99999,1006,227,274,1105,1,99999,1105,1,280,1105,1,99999,1,225,225,225,1101,294,0,0,105,1,0,1105,1,99999,1106,0,300,1105,1,99999,1,225,225,225,1101,314,0,0,106,0,0,1105,1,99999,7,677,226,224,102,2,223,223,1005,224,329,101,1,223,223,8,677,226,224,1002,223,2,223,1005,224,344,1001,223,1,223,1107,677,677,224,102,2,223,223,1005,224,359,1001,223,1,223,1107,226,677,224,102,2,223,223,1005,224,374,101,1,223,223,7,226,677,224,102,2,223,223,1005,224,389,101,1,223,223,8,226,677,224,1002,223,2,223,1005,224,404,101,1,223,223,1008,226,677,224,1002,223,2,223,1005,224,419,1001,223,1,223,107,677,677,224,102,2,223,223,1005,224,434,101,1,223,223,1108,677,226,224,1002,223,2,223,1006,224,449,101,1,223,223,1108,677,677,224,102,2,223,223,1006,224,464,101,1,223,223,1007,677,226,224,102,2,223,223,1006,224,479,101,1,223,223,1008,226,226,224,102,2,223,223,1006,224,494,101,1,223,223,108,226,226,224,1002,223,2,223,1006,224,509,101,1,223,223,107,226,226,224,102,2,223,223,1006,224,524,101,1,223,223,1107,677,226,224,102,2,223,223,1005,224,539,1001,223,1,223,108,226,677,224,1002,223,2,223,1005,224,554,101,1,223,223,1007,226,226,224,102,2,223,223,1005,224,569,101,1,223,223,8,226,226,224,102,2,223,223,1006,224,584,101,1,223,223,1008,677,677,224,1002,223,2,223,1005,224,599,1001,223,1,223,107,226,677,224,1002,223,2,223,1005,224,614,1001,223,1,223,1108,226,677,224,102,2,223,223,1006,224,629,101,1,223,223,7,677,677,224,1002,223,2,223,1005,224,644,1001,223,1,223,108,677,677,224,102,2,223,223,1005,224,659,101,1,223,223,1007,677,677,224,102,2,223,223,1006,224,674,101,1,223,223,4,223,99,226 diff --git a/2019/src/bin/puzzle_02.rs b/2019/src/bin/puzzle_02.rs index 79b2697..61c405a 100644 --- a/2019/src/bin/puzzle_02.rs +++ b/2019/src/bin/puzzle_02.rs @@ -4,7 +4,7 @@ use std::ops; use aoc2019::intcode; fn run_program(prog: &[i32], addr1_val: i32, addr2_val: i32) -> i32 { - let mut computer = intcode::Computer::new(prog); + let mut computer = intcode::Computer::new(prog, &[]); computer.memory[1] = addr1_val; computer.memory[2] = addr2_val; diff --git a/2019/src/bin/puzzle_05.rs b/2019/src/bin/puzzle_05.rs new file mode 100644 index 0000000..606d248 --- /dev/null +++ b/2019/src/bin/puzzle_05.rs @@ -0,0 +1,20 @@ +use std::io; + +use aoc2019::intcode; + +fn main() { + let diagnostic_program = intcode::parse_program(io::stdin()); + + println!( + "Part 1: {}", + intcode::Computer::new(&diagnostic_program, &[1]) + .run() + .unwrap() + ); + println!( + "Part 2: {}", + intcode::Computer::new(&diagnostic_program, &[5]) + .run() + .unwrap() + ); +} diff --git a/2019/src/intcode.rs b/2019/src/intcode.rs index d71afe9..3485230 100644 --- a/2019/src/intcode.rs +++ b/2019/src/intcode.rs @@ -1,3 +1,4 @@ +use std::collections::VecDeque; use std::io; pub fn parse_program(input: impl io::Read) -> Vec { @@ -9,60 +10,172 @@ pub fn parse_program(input: impl io::Read) -> Vec { .collect() } -const INSTRUCTION_LEN: usize = 4; +enum Parameter { + Position(i32), + Immediate(i32), +} enum Instruction { - Add(usize, usize, usize), - Multiply(usize, usize, usize), + Add(Parameter, Parameter, Parameter), + Multiply(Parameter, Parameter, Parameter), + Input(Parameter), + Output(Parameter), + JumpIfTrue(Parameter, Parameter), + JumpIfFalse(Parameter, Parameter), + LessThan(Parameter, Parameter, Parameter), + Equals(Parameter, Parameter, Parameter), Halt, } pub struct Computer { pub memory: Vec, + input: VecDeque, + output: Option, ip: usize, + modes: i32, } impl Computer { - pub fn new(program: &[i32]) -> Self { + fn opcode(inst: i32) -> i32 { + inst % 100 + } + + fn param_modes(inst: i32) -> i32 { + inst / 100 + } + + pub fn new(program: &[i32], input: &[i32]) -> Self { Self { memory: program.to_vec(), + input: input.iter().copied().collect(), + output: None, ip: 0, + modes: 0, + } + } + + fn read(&mut self) -> i32 { + let val = self.memory[self.ip]; + self.ip += 1; + val + } + + fn next_param_mode(&mut self) -> i32 { + let val = self.modes % 10; + self.modes /= 10; + val + } + + fn create_parameter(&mut self) -> Parameter { + let param_mode = self.next_param_mode(); + match param_mode { + 0 => Parameter::Position(self.read()), + 1 => Parameter::Immediate(self.read()), + _ => unreachable!(), } } - fn fetch_instruction(&self) -> Instruction { - let memory = &self.memory[self.ip..]; - let opcode = memory[0]; + fn fetch_instruction(&mut self) -> Instruction { + let inst = self.read(); + let opcode = Self::opcode(inst); + self.modes = Self::param_modes(inst); match opcode { 1 => Instruction::Add( - usize::try_from(memory[1]).unwrap(), - usize::try_from(memory[2]).unwrap(), - usize::try_from(memory[3]).unwrap(), + self.create_parameter(), + self.create_parameter(), + self.create_parameter(), ), 2 => Instruction::Multiply( - usize::try_from(memory[1]).unwrap(), - usize::try_from(memory[2]).unwrap(), - usize::try_from(memory[3]).unwrap(), + self.create_parameter(), + self.create_parameter(), + self.create_parameter(), + ), + 3 => Instruction::Input(self.create_parameter()), + 4 => Instruction::Output(self.create_parameter()), + 5 => Instruction::JumpIfTrue(self.create_parameter(), self.create_parameter()), + 6 => Instruction::JumpIfFalse(self.create_parameter(), self.create_parameter()), + 7 => Instruction::LessThan( + self.create_parameter(), + self.create_parameter(), + self.create_parameter(), + ), + 8 => Instruction::Equals( + self.create_parameter(), + self.create_parameter(), + self.create_parameter(), ), 99 => Instruction::Halt, _ => unreachable!(), } } - pub fn run(&mut self) { + fn value(&self, param: Parameter) -> i32 { + match param { + Parameter::Position(addr) => self.memory[usize::try_from(addr).unwrap()], + Parameter::Immediate(val) => val, + } + } + + fn write(&mut self, param: Parameter, val: i32) { + let dst = match param { + Parameter::Position(addr) => usize::try_from(addr).unwrap(), + Parameter::Immediate(_) => unreachable!(), + }; + + self.memory[dst] = val; + } + + fn jump(&mut self, new_ip: Parameter) { + self.ip = usize::try_from(self.value(new_ip)).unwrap(); + } + + pub fn run(&mut self) -> Option { loop { let instruction = self.fetch_instruction(); match instruction { - Instruction::Add(addr1, addr2, dst) => { - self.memory[dst] = self.memory[addr1] + self.memory[addr2]; - self.ip += INSTRUCTION_LEN; + Instruction::Add(op1, op2, dst) => { + self.write(dst, self.value(op1) + self.value(op2)); + } + Instruction::Multiply(op1, op2, dst) => { + self.write(dst, self.value(op1) * self.value(op2)); + } + Instruction::Input(dst) => { + let val = self.input.pop_front().unwrap(); + self.write(dst, val); } - Instruction::Multiply(addr1, addr2, dst) => { - self.memory[dst] = self.memory[addr1] * self.memory[addr2]; - self.ip += INSTRUCTION_LEN; + Instruction::Output(val) => { + self.output = Some(self.value(val)); } + Instruction::JumpIfTrue(cond, new_ip) => { + if self.value(cond) != 0 { + self.jump(new_ip); + } + } + Instruction::JumpIfFalse(cond, new_ip) => { + if self.value(cond) == 0 { + self.jump(new_ip); + } + } + Instruction::LessThan(lhs, rhs, dst) => self.write( + dst, + if self.value(lhs) < self.value(rhs) { + 1 + } else { + 0 + }, + ), + Instruction::Equals(lhs, rhs, dst) => self.write( + dst, + if self.value(lhs) == self.value(rhs) { + 1 + } else { + 0 + }, + ), Instruction::Halt => break, } } + + self.output } }