diff --git a/2019/07/src/main.rs b/2019/07/src/main.rs index eca11bb..2444c2b 100644 --- a/2019/07/src/main.rs +++ b/2019/07/src/main.rs @@ -1,6 +1,7 @@ use itertools::Itertools; use std::io; use std::io::BufRead; +use std::ops::Range; #[derive(Debug)] enum Operation { @@ -25,6 +26,12 @@ enum ParameterPosition { Second, } +struct Machine { + pos: i64, + tape: Vec, + params: Vec, +} + impl Into for ParameterPosition { fn into(self) -> usize { match self { @@ -58,45 +65,46 @@ fn get_mode(raw_opcode: &[char], pos: ParameterPosition) -> Mode { raw_opcode.get::(pos.into()).unwrap_or(&'0').into() } -fn next_operation(input: &[i64], pos: &mut i64, inputs: &mut Vec) -> Option { - let next = get_next(input, pos, Mode::Immediate); +#[rustfmt::skip] +fn next_operation(machine: &mut Machine) -> Option { + let next = get_next(&machine.tape, &mut machine.pos, Mode::Immediate); let mut raw_opcode: Vec<_> = next.to_string().chars().collect(); raw_opcode.reverse(); match raw_opcode[0] { '1' => Some(Operation::Add { - x: get_next(input, pos, get_mode(&raw_opcode, ParameterPosition::First)), - y: get_next(input, pos, get_mode(&raw_opcode, ParameterPosition::Second)), - addr: get_next(input, pos, Mode::Immediate) as usize, + x: get_next(&machine.tape, &mut machine.pos, get_mode(&raw_opcode, ParameterPosition::First)), + y: get_next(&machine.tape, &mut machine.pos, get_mode(&raw_opcode, ParameterPosition::Second)), + addr: get_next(&machine.tape, &mut machine.pos, Mode::Immediate) as usize, }), '2' => Some(Operation::Multiply { - x: get_next(input, pos, get_mode(&raw_opcode, ParameterPosition::First)), - y: get_next(input, pos, get_mode(&raw_opcode, ParameterPosition::Second)), - addr: get_next(input, pos, Mode::Immediate) as usize, + x: get_next(&machine.tape, &mut machine.pos, get_mode(&raw_opcode, ParameterPosition::First)), + y: get_next(&machine.tape, &mut machine.pos, get_mode(&raw_opcode, ParameterPosition::Second)), + addr: get_next(&machine.tape, &mut machine.pos, Mode::Immediate) as usize, }), '3' => Some(Operation::Input { - value: inputs.pop().unwrap(), - addr: get_next(input, pos, Mode::Immediate) as usize, + value: machine.params.pop().unwrap(), + addr: get_next(&machine.tape, &mut machine.pos, Mode::Immediate) as usize, }), '4' => Some(Operation::Output { - value: get_next(input, pos, get_mode(&raw_opcode, ParameterPosition::First)), + value: get_next(&machine.tape, &mut machine.pos, get_mode(&raw_opcode, ParameterPosition::First)), }), '5' => Some(Operation::JumpIfTrue { - value: get_next(input, pos, get_mode(&raw_opcode, ParameterPosition::First)), - addr: get_next(input, pos, get_mode(&raw_opcode, ParameterPosition::Second)), + value: get_next(&machine.tape, &mut machine.pos, get_mode(&raw_opcode, ParameterPosition::First)), + addr: get_next(&machine.tape, &mut machine.pos, get_mode(&raw_opcode, ParameterPosition::Second)), }), '6' => Some(Operation::JumpIfFalse { - value: get_next(input, pos, get_mode(&raw_opcode, ParameterPosition::First)), - addr: get_next(input, pos, get_mode(&raw_opcode, ParameterPosition::Second)), + value: get_next(&machine.tape, &mut machine.pos, get_mode(&raw_opcode, ParameterPosition::First)), + addr: get_next(&machine.tape, &mut machine.pos, get_mode(&raw_opcode, ParameterPosition::Second)), }), '7' => Some(Operation::LessThan { - first: get_next(input, pos, get_mode(&raw_opcode, ParameterPosition::First)), - second: get_next(input, pos, get_mode(&raw_opcode, ParameterPosition::Second)), - addr: get_next(input, pos, Mode::Immediate), + first: get_next(&machine.tape, &mut machine.pos, get_mode(&raw_opcode, ParameterPosition::First)), + second: get_next(&machine.tape, &mut machine.pos, get_mode(&raw_opcode, ParameterPosition::Second)), + addr: get_next(&machine.tape, &mut machine.pos, Mode::Immediate), }), '8' => Some(Operation::Equals { - first: get_next(input, pos, get_mode(&raw_opcode, ParameterPosition::First)), - second: get_next(input, pos, get_mode(&raw_opcode, ParameterPosition::Second)), - addr: get_next(input, pos, Mode::Immediate), + first: get_next(&machine.tape, &mut machine.pos, get_mode(&raw_opcode, ParameterPosition::First)), + second: get_next(&machine.tape, &mut machine.pos, get_mode(&raw_opcode, ParameterPosition::Second)), + addr: get_next(&machine.tape, &mut machine.pos, Mode::Immediate), }), '9' => None, _ => unreachable!(), @@ -149,6 +157,46 @@ fn execute(op: Operation, input: &mut Vec, pos: &mut i64) -> Option { } } +fn find_max(range: Range, input: &Vec) -> i64 { + range + .permutations(5) + .map(|amps| { + let mut last_output = 0; + let mut machines: Vec<_> = amps + .into_iter() + .map(|amp| Machine { + tape: input.clone(), + pos: 0, + params: vec![amp], + }) + .collect(); + for state in (0..5).cycle() { + let mut machine = machines.get_mut(state).unwrap(); + machine.params.insert(0, last_output); + match execute_machine(&mut machine) { + Err(output) => last_output = output, + Ok(_) => break, + } + } + last_output + }) + .max() + .unwrap() +} + +fn execute_machine(machine: &mut Machine) -> Result { + loop { + match next_operation(machine) { + Some(op) => { + if let Some(o) = execute(op, &mut machine.tape, &mut machine.pos) { + return Err(o); + } + } + None => return Ok(machine.params.pop().unwrap()), + } + } +} + pub fn main() { let input: Vec = io::stdin() .lock() @@ -160,60 +208,6 @@ pub fn main() { .map(|n| n.parse().unwrap()) .collect(); - let p1: i64 = (0..5) - .permutations(5) - .map(|amps| { - let mut last_output = 0; - for amp in amps { - let mut pos = 0; - let mut tape = input.clone(); - let mut params = vec![last_output, amp]; - match execute_machine(&mut tape, &mut pos, &mut params) { - Ok(o) => last_output = o, - Err(o) => last_output = o, - } - } - last_output - }) - .max() - .unwrap(); - println!("Part 1: {}", p1); - - let p2: i64 = (5..10) - .permutations(5) - .map(|amps| { - let mut last_output = 0; - let mut inputs: Vec<_> = amps.into_iter().map(move |amp| vec![amp]).collect(); - let mut positions = vec![0, 0, 0, 0, 0]; - let mut states: Vec<_> = (0..5).map(|_| input.clone()).collect(); - for state in (0..5).cycle() { - let mut part1_input = states.get_mut(state).unwrap(); - let mut pos = positions.get_mut(state).unwrap(); - let mut params = inputs.get_mut(state).unwrap(); - params.insert(0, last_output); - match execute_machine(&mut part1_input, &mut pos, &mut params) { - Err(output) => last_output = output, - Ok(_) => break, - } - } - last_output - }) - .max() - .unwrap(); - println!("Part 2: {}", p2); -} - -fn execute_machine(tape: &mut Vec, pos: &mut i64, params: &mut Vec) -> Result { - loop { - match next_operation(tape, pos, params) { - Some(op) => { - if let Some(o) = execute(op, tape, pos) { - return Err(o); - } - } - None => { - return Ok((params.pop().unwrap())); - } - } - } + println!("Part 1: {}", find_max(0..5, &input)); + println!("Part 2: {}", find_max(5..10, &input)); }