From 92d9e9fa100196fd7fdc4cc4f19bf2b4a83a4be4 Mon Sep 17 00:00:00 2001 From: Wesley Moore Date: Sun, 8 Dec 2019 12:23:49 +1100 Subject: [PATCH] Day 7 part 2 --- 2019/src/bin/day5.rs | 4 +- 2019/src/bin/day7.rs | 106 ++++++++++++++++++++++++++++++++-- 2019/src/computer.rs | 132 +++++++++++++++++++++++++++++++------------ 3 files changed, 199 insertions(+), 43 deletions(-) diff --git a/2019/src/bin/day5.rs b/2019/src/bin/day5.rs index 3fd226c..43c8b80 100644 --- a/2019/src/bin/day5.rs +++ b/2019/src/bin/day5.rs @@ -5,11 +5,11 @@ fn main() -> io::Result<()> { let input = fs::read_to_string("input/day5.txt")?; let data = input::read_separated_line(',', &input)?; - let mut computer = computer::Computer::new(data.clone(), vec![1], vec![]); + let mut computer = computer::Computer::new('1', data.clone(), vec![1], vec![]); computer.run(None, None); println!("Part 1: {}", computer.output()); - let mut computer = computer::Computer::new(data.clone(), vec![5], vec![]); + let mut computer = computer::Computer::new('2', data.clone(), vec![5], vec![]); computer.run(None, None); println!("Part 2: {}", computer.output()); diff --git a/2019/src/bin/day7.rs b/2019/src/bin/day7.rs index e84c1a8..588e0c1 100644 --- a/2019/src/bin/day7.rs +++ b/2019/src/bin/day7.rs @@ -1,6 +1,10 @@ use std::{fs, io}; -use advent_of_code::{computer, input}; +use advent_of_code::computer::{ComputeResult, Computer, Output, Pipe}; +use advent_of_code::input; +use std::cell::RefCell; +use std::convert::TryFrom; +use std::rc::Rc; const AMPLIFIERS: usize = 5; @@ -9,7 +13,7 @@ fn main() -> io::Result<()> { let data = input::read_separated_line(',', &source)?; part1(data.clone()); - // part2(data); + part2(data); Ok(()) } @@ -20,12 +24,14 @@ fn part1(data: Vec) { elements[i as usize] = i; } let max = phase_settings(elements) - .iter() + .into_iter() .map(|settings| { let mut output = 0; + let mut name = 'A'; for phase_setting in settings.iter() { let input = vec![output, *phase_setting]; - let mut computer = computer::Computer::new(data.clone(), input, vec![]); + let mut computer = Computer::new(name, data.clone(), input, vec![]); + name = char::try_from(name as u32 + 1).unwrap(); computer.run(None, None); output = computer.output(); } @@ -42,7 +48,68 @@ fn part2(data: Vec) { elements[i as usize - 5] = i; } - // println!("Part 2: {}", max); + let max = phase_settings(elements) + .into_iter() + .map(|settings| run_part2_with_settings(data.clone(), settings)) + .max() + .unwrap(); + + println!("Part 2: {}", max); +} + +fn run_part2_with_settings(data: Vec, settings: [i32; AMPLIFIERS]) -> i32 { + // Construct the amplifiers and the pipes between them + // The first amplifier gets io_pipe as input + // The last amplifier gets io_pipe as output + // otherwise the get a pipe between them + let io_pipe = Rc::new(RefCell::new(Pipe::new(vec![0].into_iter().collect()))); + let mut last_pipe = Rc::clone(&io_pipe); + let mut amplifiers = Vec::with_capacity(AMPLIFIERS); + for i in 0..AMPLIFIERS { + let next_pipe = if i == AMPLIFIERS - 1 { + // This is the last amplifier, its output goes to the input of the first + Rc::clone(&io_pipe) + } else { + Rc::new(RefCell::new(Pipe::new(vec![].into_iter().collect()))) + }; + // Add the phase setting (it's the first thing that's read) + last_pipe.borrow_mut().push_front(settings[i]); + let amp = Computer::new( + char::try_from('A' as u32 + i as u32).unwrap(), + data.clone(), + last_pipe, + Rc::clone(&next_pipe), + ); + amplifiers.push(amp); + last_pipe = next_pipe; + } + + // Now run them + let mut i = 0; + let mut halted = Vec::with_capacity(AMPLIFIERS); + loop { + match amplifiers[i].run(None, None) { + ComputeResult::Halted => { + let amp = amplifiers.remove(i); + println!("{} halted", amp.name()); + halted.push(amp); + if amplifiers.is_empty() { + break; + } + // Don't increment i as we removed an element + i = i % amplifiers.len(); + } + ComputeResult::NeedsInput => { + println!("{} needs input", amplifiers[i].name()); + // continue to next one + i = (i + 1) % amplifiers.len(); + } + } + } + + // Need the last output sent from the last amplifier + dbg!(io_pipe.borrow()); + io_pipe.last_value() } fn phase_settings(mut elements: [i32; AMPLIFIERS]) -> Vec<[i32; AMPLIFIERS]> { @@ -73,7 +140,7 @@ mod tests { #[test] fn test_phase_setting_generation() { - let settings = phase_settings(); + let settings = phase_settings([0, 1, 2, 3, 4]); assert_eq!( &settings[0..6], &[ @@ -86,4 +153,31 @@ mod tests { ] ); } + + #[test] + fn test_part2_example1() { + let input = vec![ + 3, 26, 1001, 26, -4, 26, 3, 27, 1002, 27, 2, 27, 1, 27, 26, 27, 4, 27, 1001, 28, -1, + 28, 1005, 28, 6, 99, 0, 0, 5, + ]; + assert_eq!(run_part2_with_settings(input, [9, 8, 7, 6, 5]), 139629729); + } + + #[test] + fn test_part2_example2() { + let input = vec![ + 3, 52, 1001, 52, -5, 52, 3, 53, 1, 52, 56, 54, 1007, 54, 5, 55, 1005, 55, 26, 1001, 54, + -5, 54, 1105, 1, 12, 1, 53, 54, 53, 1008, 54, 0, 55, 1001, 55, 1, 55, 2, 53, 55, 53, 4, + 53, 1001, 56, -1, 56, 1005, 56, 6, 99, 0, 0, 0, 0, 10, + ]; + assert_eq!(run_part2_with_settings(input, [9, 7, 8, 5, 6]), 18216); + } + + #[test] + fn test_part2_with_part1_example() { + let input = vec![ + 3, 15, 3, 16, 1002, 16, 10, 16, 1, 16, 15, 15, 4, 15, 99, 0, 0, + ]; + assert_eq!(run_part2_with_settings(input, [4, 3, 2, 1, 0]), 43210); + } } diff --git a/2019/src/computer.rs b/2019/src/computer.rs index ff0c911..2a550c5 100644 --- a/2019/src/computer.rs +++ b/2019/src/computer.rs @@ -1,3 +1,7 @@ +use std::cell::RefCell; +use std::collections::VecDeque; +use std::rc::Rc; + type Address = i32; #[derive(Debug, Eq, PartialEq)] @@ -19,7 +23,20 @@ enum Mode { Address, } +#[derive(Debug)] +pub struct Pipe { + queue: VecDeque, + last: Option, +} + +pub enum ComputeResult { + Halted, + NeedsInput, +} + pub struct Computer { + name: char, + ip: i32, memory: Vec, input: I, output: O, @@ -51,6 +68,24 @@ impl Output for Vec { } } +impl Input for Rc> { + fn read(&mut self) -> Option { + dbg!(self.borrow_mut().queue.pop_front()) + } +} + +impl Output for Rc> { + fn write(&mut self, value: i32) { + let mut pipe = self.borrow_mut(); + pipe.last = Some(value); + pipe.queue.push_back(value); + } + + fn last_value(&self) -> i32 { + self.borrow().last.unwrap() + } +} + fn decode(mut instruction: i32) -> Instruction { let opcode = divmod(&mut instruction, 100); @@ -90,15 +125,25 @@ fn decode(mut instruction: i32) -> Instruction { } } -impl Computer where I: Input, O: Output { - pub fn new(memory: Vec, input: I, output: O) -> Self { +impl Computer +where + I: Input, + O: Output, +{ + pub fn new(name: char, memory: Vec, input: I, output: O) -> Self { Computer { + name, + ip: 0, memory, input, output, } } + pub fn name(&self) -> char { + self.name + } + fn read(&self, value: i32, mode: Mode) -> i32 { match mode { Mode::Immediate => self.memory[value as usize], @@ -110,67 +155,74 @@ impl Computer where I: Input, O: Output { self.memory[address as usize] = value; } - pub fn run(&mut self, noun: Option, verb: Option) { + pub fn run(&mut self, noun: Option, verb: Option) -> ComputeResult { + println!("{}: resume ip = {}", self.name, self.ip); if let Some(noun) = noun { self.write(1, noun); } if let Some(verb) = verb { self.write(2, verb); } - let mut ip = 0; // instruction pointer loop { - match decode(self.read(ip, Mode::Immediate)) { + match decode(self.read(self.ip, Mode::Immediate)) { Instruction::Add(mode1, mode2) => { - let result = self.read(ip + 1, mode1) + self.read(ip + 2, mode2); - self.write(self.read(ip + 3, Mode::Immediate), result); - ip += 4; + let result = self.read(self.ip + 1, mode1) + self.read(self.ip + 2, mode2); + self.write(self.read(self.ip + 3, Mode::Immediate), result); + self.ip += 4; } Instruction::Multiply(mode1, mode2) => { - let result = self.read(ip + 1, mode1) * self.read(ip + 2, mode2); - self.write(self.read(ip + 3, Mode::Immediate), result); - ip += 4; - } - Instruction::Input => { - let value = self.input.read().expect("no more input"); - self.write(self.read(ip + 1, Mode::Immediate), value); - ip += 2; + let result = self.read(self.ip + 1, mode1) * self.read(self.ip + 2, mode2); + self.write(self.read(self.ip + 3, Mode::Immediate), result); + self.ip += 4; } + Instruction::Input => match self.input.read() { + Some(value) => { + self.write(self.read(self.ip + 1, Mode::Immediate), value); + self.ip += 2; + } + None => { + // println!("{}: pause ip = {}", self.name, self.ip); + return ComputeResult::NeedsInput; + } + }, Instruction::Output(mode) => { - self.output.write(self.read(ip + 1, mode)); - ip += 2; + let value = self.read(self.ip + 1, mode); + println!("{}: output {}", self.name, value); + self.output.write(value); + self.ip += 2; } Instruction::JumpIfTrue(mode1, mode2) => { - if self.read(ip + 1, mode1) != 0 { - ip = self.read(ip + 2, mode2); + if self.read(self.ip + 1, mode1) != 0 { + self.ip = self.read(self.ip + 2, mode2); } else { - ip += 3; + self.ip += 3; } } Instruction::JumpIfFalse(mode1, mode2) => { - if self.read(ip + 1, mode1) == 0 { - ip = self.read(ip + 2, mode2); + if self.read(self.ip + 1, mode1) == 0 { + self.ip = self.read(self.ip + 2, mode2); } else { - ip += 3; + self.ip += 3; } } Instruction::LessThan(mode1, mode2) => { - if self.read(ip + 1, mode1) < self.read(ip + 2, mode2) { - self.write(self.read(ip + 3, Mode::Immediate), 1); + if self.read(self.ip + 1, mode1) < self.read(self.ip + 2, mode2) { + self.write(self.read(self.ip + 3, Mode::Immediate), 1); } else { - self.write(self.read(ip + 3, Mode::Immediate), 0); + self.write(self.read(self.ip + 3, Mode::Immediate), 0); } - ip += 4; + self.ip += 4; } Instruction::Equals(mode1, mode2) => { - if self.read(ip + 1, mode1) == self.read(ip + 2, mode2) { - self.write(self.read(ip + 3, Mode::Immediate), 1); + if self.read(self.ip + 1, mode1) == self.read(self.ip + 2, mode2) { + self.write(self.read(self.ip + 3, Mode::Immediate), 1); } else { - self.write(self.read(ip + 3, Mode::Immediate), 0); + self.write(self.read(self.ip + 3, Mode::Immediate), 0); } - ip += 4; + self.ip += 4; } - Instruction::Halt => break, + Instruction::Halt => return ComputeResult::Halted, } } } @@ -180,6 +232,16 @@ impl Computer where I: Input, O: Output { } } +impl Pipe { + pub fn new(queue: VecDeque) -> Self { + Pipe { queue, last: None } + } + + pub fn push_front(&mut self, value: i32) { + self.queue.push_front(value); + } +} + fn divmod(value: &mut i32, divisor: i32) -> i32 { let res = *value % divisor; *value /= divisor; @@ -213,8 +275,8 @@ mod tests { #[test] fn test_day2() { let input = fs::read_to_string("input/day2.txt").unwrap(); - let mut data = input::read_separated_line(',', &input).unwrap(); - let mut program = Computer::new(&mut data, vec![]); + let data = input::read_separated_line(',', &input).unwrap(); + let mut program = Computer::new('2', data, vec![], vec![]); // Check that day2 still works wirh run through this implementation program.run(Some(12), Some(2));