Skip to content

Instantly share code, notes, and snippets.

@ltriant
Created December 8, 2019 23:45
Show Gist options
  • Save ltriant/2e01fd870fd0e5e41325d8dec4e66f7b to your computer and use it in GitHub Desktop.
Save ltriant/2e01fd870fd0e5e41325d8dec4e66f7b to your computer and use it in GitHub Desktop.
Advent of Code 2019 Day 7
use std::collections::VecDeque;
use itertools::Itertools;
#[derive(PartialEq)]
enum AddressingMode {
Position,
Immediate,
}
impl From<u8> for AddressingMode {
fn from(v: u8) -> Self {
match v {
0 => AddressingMode::Position,
1 => AddressingMode::Immediate,
_ => unreachable!(),
}
}
}
fn digits(num: i64) -> [u8; 4] {
[
((num / 10 % 10) as u8 * 10) + (num % 10) as u8,
(num / 100 % 10) as u8,
(num / 1_000 % 10) as u8,
(num / 10_000 % 10) as u8,
]
}
fn get_operands(mem: &Vec<i64>, pc: usize, n: usize) -> Vec<i64> {
let opcode = digits(mem[pc]);
(1 ..= n)
.map(|i| {
match AddressingMode::from(opcode[i]) {
AddressingMode::Position => mem[mem[pc + i] as usize],
AddressingMode::Immediate => mem[pc + i],
}
} )
.collect::<Vec<_>>()
}
enum InputState {
PhaseSetting,
InputSignal,
}
struct CPU {
mem: Vec<i64>,
pc: usize,
input_state: InputState,
phase_setting: i64,
}
impl CPU {
fn new_cpu(mem: Vec<i64>, phase_setting: i64) -> Self {
Self {
mem: mem,
pc: 0,
input_state: InputState::PhaseSetting,
phase_setting: phase_setting,
}
}
fn run_machine(&mut self, input_signal: i64) -> Option<i64> {
loop {
let original_op = self.mem[self.pc];
let op = digits(original_op);
match op[0] {
1 => {
let operands = get_operands(&self.mem, self.pc, 2);
let dest = self.mem[self.pc + 3] as usize;
self.mem[dest] = operands[0] as i64 + operands[1] as i64;
println!("{:05} ADD {} {} -> {}",
original_op,
operands[0],
operands[1],
dest);
self.pc += 4;
},
2 => {
let operands = get_operands(&self.mem, self.pc, 2);
let dest = self.mem[self.pc + 3] as usize;
self.mem[dest] = operands[0] as i64 * operands[1] as i64;
println!("{:05} MUL {} {} -> {}",
original_op,
operands[0],
operands[1],
dest);
self.pc += 4;
},
3 => {
let operand1 = self.mem[self.pc + 1] as usize;
match self.input_state {
InputState::PhaseSetting => {
self.mem[operand1] = self.phase_setting;
self.input_state = InputState::InputSignal;
},
InputState::InputSignal => {
self.mem[operand1] = input_signal;
},
}
println!("{:05} IN -> {}", original_op, operand1);
self.pc += 2;
},
4 => {
let operand1 = self.mem[self.pc + 1] as usize;
println!("{:05} OUT -> {}", original_op, operand1);
self.pc += 2;
return Some(self.mem[operand1]);
//println!("{}", self.mem[operand1]);
},
5 => {
let operands = get_operands(&self.mem, self.pc, 2);
if operands[0] != 0 {
self.pc = operands[1] as usize;
} else {
self.pc += 3;
}
println!("{:05} JNZ {} -> {}",
original_op,
operands[0],
operands[1]);
},
6 => {
let operands = get_operands(&self.mem, self.pc, 2);
if operands[0] == 0 {
self.pc = operands[1] as usize;
} else {
self.pc += 3;
}
println!("{:05} JZ {} -> {}",
original_op,
operands[0],
operands[1]);
},
7 => {
let operands = get_operands(&self.mem, self.pc, 2);
let dest = self.mem[self.pc + 3] as usize;
if operands[0] < operands[1] {
self.mem[dest] = 1;
} else {
self.mem[dest] = 0;
}
println!("{:05} JL {} {} -> {}",
original_op,
operands[0],
operands[1],
dest);
self.pc += 4;
},
8 => {
let operands = get_operands(&self.mem, self.pc, 2);
let dest = self.mem[self.pc + 3] as usize;
if operands[0] == operands[1] {
self.mem[dest] = 1;
} else {
self.mem[dest] = 0;
}
println!("{:05} JEQ {} {} -> {}",
original_op,
operands[0],
operands[1],
dest);
self.pc += 4;
},
99 => {
println!("{:05} HLT", original_op);
break;
},
_ => {
println!("got opcode: {} -> {}", op[3], self.mem[self.pc]);
break;
},
}
}
return None;
}
}
#[allow(dead_code)]
pub fn part1() {
let mem = include_str!("day07.input")
.lines()
.flat_map(|line| line.split(','))
.map(|c| c.parse::<i64>().unwrap())
.collect::<Vec<_>>();
let max_output = (0 .. 5).permutations(5)
.map(|inputs| {
inputs.iter().fold(0, |input_signal, &phase_setting| {
CPU::new_cpu(mem.clone(), phase_setting as i64)
.run_machine(input_signal)
.unwrap()
} )
} )
.max()
.unwrap();
println!("Part 1 {}", max_output);
}
#[allow(dead_code)]
pub fn part2() {
let mem = include_str!("day07.input")
.lines()
.flat_map(|line| line.split(','))
.map(|c| c.parse::<i64>().unwrap())
.collect::<Vec<_>>();
let max_output = (5 ..= 9).permutations(5)
.map(|inputs| {
let mut amps = (0 .. 5).map(|_| mem.clone())
.zip(inputs.iter())
.map(|(mem, &phase_setting)| CPU::new_cpu(mem, phase_setting))
.collect::<VecDeque<_>>();
let mut input = 0;
while let Some(mut amp) = amps.pop_front() {
if let Some(output) = amp.run_machine(input) {
input = output;
amps.push_back(amp);
}
}
input
} )
.max()
.unwrap();
println!("Part 2 {}", max_output);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment