Day 7 part 2

This commit is contained in:
Wesley Moore 2019-12-08 12:23:49 +11:00
parent 5965959a05
commit 92d9e9fa10
No known key found for this signature in database
GPG key ID: BF67766C0BC2D0EE
3 changed files with 199 additions and 43 deletions

View file

@ -5,11 +5,11 @@ fn main() -> io::Result<()> {
let input = fs::read_to_string("input/day5.txt")?; let input = fs::read_to_string("input/day5.txt")?;
let data = input::read_separated_line(',', &input)?; 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); computer.run(None, None);
println!("Part 1: {}", computer.output()); 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); computer.run(None, None);
println!("Part 2: {}", computer.output()); println!("Part 2: {}", computer.output());

View file

@ -1,6 +1,10 @@
use std::{fs, io}; 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; const AMPLIFIERS: usize = 5;
@ -9,7 +13,7 @@ fn main() -> io::Result<()> {
let data = input::read_separated_line(',', &source)?; let data = input::read_separated_line(',', &source)?;
part1(data.clone()); part1(data.clone());
// part2(data); part2(data);
Ok(()) Ok(())
} }
@ -20,12 +24,14 @@ fn part1(data: Vec<i32>) {
elements[i as usize] = i; elements[i as usize] = i;
} }
let max = phase_settings(elements) let max = phase_settings(elements)
.iter() .into_iter()
.map(|settings| { .map(|settings| {
let mut output = 0; let mut output = 0;
let mut name = 'A';
for phase_setting in settings.iter() { for phase_setting in settings.iter() {
let input = vec![output, *phase_setting]; 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); computer.run(None, None);
output = computer.output(); output = computer.output();
} }
@ -42,7 +48,68 @@ fn part2(data: Vec<i32>) {
elements[i as usize - 5] = i; 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<i32>, 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]> { fn phase_settings(mut elements: [i32; AMPLIFIERS]) -> Vec<[i32; AMPLIFIERS]> {
@ -73,7 +140,7 @@ mod tests {
#[test] #[test]
fn test_phase_setting_generation() { fn test_phase_setting_generation() {
let settings = phase_settings(); let settings = phase_settings([0, 1, 2, 3, 4]);
assert_eq!( assert_eq!(
&settings[0..6], &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);
}
} }

View file

@ -1,3 +1,7 @@
use std::cell::RefCell;
use std::collections::VecDeque;
use std::rc::Rc;
type Address = i32; type Address = i32;
#[derive(Debug, Eq, PartialEq)] #[derive(Debug, Eq, PartialEq)]
@ -19,7 +23,20 @@ enum Mode {
Address, Address,
} }
#[derive(Debug)]
pub struct Pipe {
queue: VecDeque<i32>,
last: Option<i32>,
}
pub enum ComputeResult {
Halted,
NeedsInput,
}
pub struct Computer<I: Input, O: Output> { pub struct Computer<I: Input, O: Output> {
name: char,
ip: i32,
memory: Vec<i32>, memory: Vec<i32>,
input: I, input: I,
output: O, output: O,
@ -51,6 +68,24 @@ impl Output for Vec<i32> {
} }
} }
impl Input for Rc<RefCell<Pipe>> {
fn read(&mut self) -> Option<i32> {
dbg!(self.borrow_mut().queue.pop_front())
}
}
impl Output for Rc<RefCell<Pipe>> {
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 { fn decode(mut instruction: i32) -> Instruction {
let opcode = divmod(&mut instruction, 100); let opcode = divmod(&mut instruction, 100);
@ -90,15 +125,25 @@ fn decode(mut instruction: i32) -> Instruction {
} }
} }
impl<I, O> Computer<I, O> where I: Input, O: Output { impl<I, O> Computer<I, O>
pub fn new(memory: Vec<i32>, input: I, output: O) -> Self { where
I: Input,
O: Output,
{
pub fn new(name: char, memory: Vec<i32>, input: I, output: O) -> Self {
Computer { Computer {
name,
ip: 0,
memory, memory,
input, input,
output, output,
} }
} }
pub fn name(&self) -> char {
self.name
}
fn read(&self, value: i32, mode: Mode) -> i32 { fn read(&self, value: i32, mode: Mode) -> i32 {
match mode { match mode {
Mode::Immediate => self.memory[value as usize], Mode::Immediate => self.memory[value as usize],
@ -110,67 +155,74 @@ impl<I, O> Computer<I, O> where I: Input, O: Output {
self.memory[address as usize] = value; self.memory[address as usize] = value;
} }
pub fn run(&mut self, noun: Option<i32>, verb: Option<i32>) { pub fn run(&mut self, noun: Option<i32>, verb: Option<i32>) -> ComputeResult {
println!("{}: resume ip = {}", self.name, self.ip);
if let Some(noun) = noun { if let Some(noun) = noun {
self.write(1, noun); self.write(1, noun);
} }
if let Some(verb) = verb { if let Some(verb) = verb {
self.write(2, verb); self.write(2, verb);
} }
let mut ip = 0; // instruction pointer
loop { loop {
match decode(self.read(ip, Mode::Immediate)) { match decode(self.read(self.ip, Mode::Immediate)) {
Instruction::Add(mode1, mode2) => { Instruction::Add(mode1, mode2) => {
let result = self.read(ip + 1, mode1) + self.read(ip + 2, mode2); let result = self.read(self.ip + 1, mode1) + self.read(self.ip + 2, mode2);
self.write(self.read(ip + 3, Mode::Immediate), result); self.write(self.read(self.ip + 3, Mode::Immediate), result);
ip += 4; self.ip += 4;
} }
Instruction::Multiply(mode1, mode2) => { Instruction::Multiply(mode1, mode2) => {
let result = self.read(ip + 1, mode1) * self.read(ip + 2, mode2); let result = self.read(self.ip + 1, mode1) * self.read(self.ip + 2, mode2);
self.write(self.read(ip + 3, Mode::Immediate), result); self.write(self.read(self.ip + 3, Mode::Immediate), result);
ip += 4; self.ip += 4;
} }
Instruction::Input => { Instruction::Input => match self.input.read() {
let value = self.input.read().expect("no more input"); Some(value) => {
self.write(self.read(ip + 1, Mode::Immediate), value); self.write(self.read(self.ip + 1, Mode::Immediate), value);
ip += 2; self.ip += 2;
} }
None => {
// println!("{}: pause ip = {}", self.name, self.ip);
return ComputeResult::NeedsInput;
}
},
Instruction::Output(mode) => { Instruction::Output(mode) => {
self.output.write(self.read(ip + 1, mode)); let value = self.read(self.ip + 1, mode);
ip += 2; println!("{}: output {}", self.name, value);
self.output.write(value);
self.ip += 2;
} }
Instruction::JumpIfTrue(mode1, mode2) => { Instruction::JumpIfTrue(mode1, mode2) => {
if self.read(ip + 1, mode1) != 0 { if self.read(self.ip + 1, mode1) != 0 {
ip = self.read(ip + 2, mode2); self.ip = self.read(self.ip + 2, mode2);
} else { } else {
ip += 3; self.ip += 3;
} }
} }
Instruction::JumpIfFalse(mode1, mode2) => { Instruction::JumpIfFalse(mode1, mode2) => {
if self.read(ip + 1, mode1) == 0 { if self.read(self.ip + 1, mode1) == 0 {
ip = self.read(ip + 2, mode2); self.ip = self.read(self.ip + 2, mode2);
} else { } else {
ip += 3; self.ip += 3;
} }
} }
Instruction::LessThan(mode1, mode2) => { Instruction::LessThan(mode1, mode2) => {
if self.read(ip + 1, mode1) < self.read(ip + 2, mode2) { if self.read(self.ip + 1, mode1) < self.read(self.ip + 2, mode2) {
self.write(self.read(ip + 3, Mode::Immediate), 1); self.write(self.read(self.ip + 3, Mode::Immediate), 1);
} else { } 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) => { Instruction::Equals(mode1, mode2) => {
if self.read(ip + 1, mode1) == self.read(ip + 2, mode2) { if self.read(self.ip + 1, mode1) == self.read(self.ip + 2, mode2) {
self.write(self.read(ip + 3, Mode::Immediate), 1); self.write(self.read(self.ip + 3, Mode::Immediate), 1);
} else { } 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<I, O> Computer<I, O> where I: Input, O: Output {
} }
} }
impl Pipe {
pub fn new(queue: VecDeque<i32>) -> 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 { fn divmod(value: &mut i32, divisor: i32) -> i32 {
let res = *value % divisor; let res = *value % divisor;
*value /= divisor; *value /= divisor;
@ -213,8 +275,8 @@ mod tests {
#[test] #[test]
fn test_day2() { fn test_day2() {
let input = fs::read_to_string("input/day2.txt").unwrap(); let input = fs::read_to_string("input/day2.txt").unwrap();
let mut data = input::read_separated_line(',', &input).unwrap(); let data = input::read_separated_line(',', &input).unwrap();
let mut program = Computer::new(&mut data, vec![]); let mut program = Computer::new('2', data, vec![], vec![]);
// Check that day2 still works wirh run through this implementation // Check that day2 still works wirh run through this implementation
program.run(Some(12), Some(2)); program.run(Some(12), Some(2));