mirror of
https://github.com/wezm/advent-of-code.git
synced 2024-12-18 10:19:55 +00:00
Day 7 part 2
This commit is contained in:
parent
5965959a05
commit
92d9e9fa10
3 changed files with 199 additions and 43 deletions
|
@ -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());
|
||||
|
||||
|
|
|
@ -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<i32>) {
|
|||
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<i32>) {
|
|||
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]> {
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<i32>,
|
||||
last: Option<i32>,
|
||||
}
|
||||
|
||||
pub enum ComputeResult {
|
||||
Halted,
|
||||
NeedsInput,
|
||||
}
|
||||
|
||||
pub struct Computer<I: Input, O: Output> {
|
||||
name: char,
|
||||
ip: i32,
|
||||
memory: Vec<i32>,
|
||||
input: I,
|
||||
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 {
|
||||
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 {
|
||||
pub fn new(memory: Vec<i32>, input: I, output: O) -> Self {
|
||||
impl<I, O> Computer<I, O>
|
||||
where
|
||||
I: Input,
|
||||
O: Output,
|
||||
{
|
||||
pub fn new(name: char, memory: Vec<i32>, 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<I, O> Computer<I, O> where I: Input, O: Output {
|
|||
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 {
|
||||
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<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 {
|
||||
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));
|
||||
|
|
Loading…
Reference in a new issue