advent-of-code/2019/src/computer.rs

317 lines
9.5 KiB
Rust
Raw Normal View History

2019-12-08 01:23:49 +00:00
use std::cell::RefCell;
use std::collections::VecDeque;
2019-12-09 05:54:32 +00:00
use std::convert::TryFrom;
2019-12-08 01:23:49 +00:00
use std::rc::Rc;
2019-12-09 05:54:32 +00:00
type Address = i64;
2019-12-07 02:45:54 +00:00
#[derive(Debug, Eq, PartialEq)]
enum Instruction {
2019-12-09 05:54:32 +00:00
Add(Mode, Mode, Mode),
Multiply(Mode, Mode, Mode),
Input(Mode),
2019-12-07 02:45:54 +00:00
Output(Mode),
2019-12-07 03:44:38 +00:00
JumpIfTrue(Mode, Mode),
JumpIfFalse(Mode, Mode),
2019-12-09 05:54:32 +00:00
LessThan(Mode, Mode, Mode),
Equals(Mode, Mode, Mode),
AdjustRelativeBase(Mode),
2019-12-07 02:45:54 +00:00
Halt,
}
2019-12-09 05:54:32 +00:00
#[derive(Debug, Eq, PartialEq, Copy, Clone)]
2019-12-07 02:45:54 +00:00
enum Mode {
Immediate,
Address,
2019-12-09 05:54:32 +00:00
Relative,
2019-12-07 02:45:54 +00:00
}
2019-12-08 01:23:49 +00:00
#[derive(Debug)]
pub struct Pipe {
2019-12-09 05:54:32 +00:00
queue: VecDeque<i64>,
last: Option<i64>,
2019-12-08 01:23:49 +00:00
}
pub enum ComputeResult {
Halted,
NeedsInput,
}
pub struct Computer<I: Input, O: Output> {
2019-12-08 01:23:49 +00:00
name: char,
2019-12-09 05:54:32 +00:00
ip: i64,
memory: Vec<i64>,
input: I,
output: O,
2019-12-09 05:54:32 +00:00
relative_base: i64,
}
pub trait Input {
2019-12-09 05:54:32 +00:00
fn read(&mut self) -> Option<i64>;
}
pub trait Output {
2019-12-09 05:54:32 +00:00
fn write(&mut self, value: i64);
2019-12-09 05:54:32 +00:00
fn last_value(&self) -> i64;
}
2019-12-09 05:54:32 +00:00
impl Input for Vec<i64> {
fn read(&mut self) -> Option<i64> {
self.pop()
}
}
2019-12-09 05:54:32 +00:00
impl Output for Vec<i64> {
fn write(&mut self, value: i64) {
self.push(value)
}
2019-12-09 05:54:32 +00:00
fn last_value(&self) -> i64 {
*self.last().unwrap()
}
2019-12-07 02:45:54 +00:00
}
2019-12-08 01:23:49 +00:00
impl Input for Rc<RefCell<Pipe>> {
2019-12-09 05:54:32 +00:00
fn read(&mut self) -> Option<i64> {
2019-12-08 01:23:49 +00:00
dbg!(self.borrow_mut().queue.pop_front())
}
}
impl Output for Rc<RefCell<Pipe>> {
2019-12-09 05:54:32 +00:00
fn write(&mut self, value: i64) {
2019-12-08 01:23:49 +00:00
let mut pipe = self.borrow_mut();
pipe.last = Some(value);
pipe.queue.push_back(value);
}
2019-12-09 05:54:32 +00:00
fn last_value(&self) -> i64 {
2019-12-08 01:23:49 +00:00
self.borrow().last.unwrap()
}
}
2019-12-09 05:54:32 +00:00
fn decode(mut instruction: i64) -> Instruction {
2019-12-07 02:45:54 +00:00
let opcode = divmod(&mut instruction, 100);
match opcode {
1 => {
// let mode3 = divmod(&mut instruction, 10);
// Parameters that an instruction writes to will never be in immediate mode.
Instruction::Add(
Mode::from(divmod(&mut instruction, 10)),
Mode::from(divmod(&mut instruction, 10)),
2019-12-09 05:54:32 +00:00
Mode::from(divmod(&mut instruction, 10)),
2019-12-07 02:45:54 +00:00
)
}
2 => Instruction::Multiply(
Mode::from(divmod(&mut instruction, 10)),
Mode::from(divmod(&mut instruction, 10)),
2019-12-09 05:54:32 +00:00
Mode::from(divmod(&mut instruction, 10)),
2019-12-07 02:45:54 +00:00
),
2019-12-09 05:54:32 +00:00
3 => Instruction::Input(Mode::from(divmod(&mut instruction, 10))),
2019-12-07 02:45:54 +00:00
4 => Instruction::Output(Mode::from(divmod(&mut instruction, 10))),
2019-12-07 03:44:38 +00:00
5 => Instruction::JumpIfTrue(
Mode::from(divmod(&mut instruction, 10)),
Mode::from(divmod(&mut instruction, 10)),
),
6 => Instruction::JumpIfFalse(
Mode::from(divmod(&mut instruction, 10)),
Mode::from(divmod(&mut instruction, 10)),
),
7 => Instruction::LessThan(
Mode::from(divmod(&mut instruction, 10)),
Mode::from(divmod(&mut instruction, 10)),
2019-12-09 05:54:32 +00:00
Mode::from(divmod(&mut instruction, 10)),
2019-12-07 03:44:38 +00:00
),
8 => Instruction::Equals(
Mode::from(divmod(&mut instruction, 10)),
Mode::from(divmod(&mut instruction, 10)),
2019-12-09 05:54:32 +00:00
Mode::from(divmod(&mut instruction, 10)),
2019-12-07 03:44:38 +00:00
),
2019-12-09 05:54:32 +00:00
9 => Instruction::AdjustRelativeBase(Mode::from(divmod(&mut instruction, 10))),
2019-12-07 02:45:54 +00:00
99 => Instruction::Halt,
_ => panic!("Invalid opcode: {}", opcode),
}
}
2019-12-08 01:23:49 +00:00
impl<I, O> Computer<I, O>
where
I: Input,
O: Output,
{
2019-12-09 05:54:32 +00:00
pub fn new(name: char, mut memory: Vec<i64>, input: I, output: O) -> Self {
// HACK
let mut buffer = vec![0; 64 * 1024 * 1024];
memory.append(&mut buffer);
Computer {
2019-12-08 01:23:49 +00:00
name,
ip: 0,
memory,
input,
output,
2019-12-09 05:54:32 +00:00
relative_base: 0,
}
2019-12-07 02:45:54 +00:00
}
2019-12-08 01:23:49 +00:00
pub fn name(&self) -> char {
self.name
}
2019-12-09 05:54:32 +00:00
fn read(&self, value: i64, mode: Mode) -> i64 {
2019-12-07 02:45:54 +00:00
match mode {
Mode::Immediate => self.memory[value as usize],
Mode::Address => self.memory[self.memory[value as usize] as usize],
2019-12-09 05:54:32 +00:00
// The address a relative mode parameter refers to is itself plus the current relative base.
Mode::Relative => {
self.memory
[usize::try_from(self.relative_base + self.memory[value as usize]).unwrap()]
}
2019-12-07 02:45:54 +00:00
}
}
2019-12-09 05:54:32 +00:00
fn write(&mut self, address: Address, value: i64, mode: Mode) {
match mode {
Mode::Immediate => panic!("attempt to write with immediate mode"),
Mode::Address => self.memory[address as usize] = value,
Mode::Relative => {
self.memory[usize::try_from(self.relative_base + address).unwrap()] = value
}
}
2019-12-07 02:45:54 +00:00
}
2019-12-09 05:54:32 +00:00
pub fn run(&mut self, noun: Option<i64>, verb: Option<i64>) -> ComputeResult {
2019-12-08 01:23:49 +00:00
println!("{}: resume ip = {}", self.name, self.ip);
if let Some(noun) = noun {
2019-12-09 05:54:32 +00:00
self.write(1, noun, Mode::Address);
}
if let Some(verb) = verb {
2019-12-09 05:54:32 +00:00
self.write(2, verb, Mode::Address);
}
2019-12-07 02:45:54 +00:00
loop {
2019-12-08 01:23:49 +00:00
match decode(self.read(self.ip, Mode::Immediate)) {
2019-12-09 05:54:32 +00:00
Instruction::Add(mode1, mode2, write_mode) => {
2019-12-08 01:23:49 +00:00
let result = self.read(self.ip + 1, mode1) + self.read(self.ip + 2, mode2);
2019-12-09 05:54:32 +00:00
self.write(self.read(self.ip + 3, Mode::Immediate), result, write_mode);
2019-12-08 01:23:49 +00:00
self.ip += 4;
2019-12-07 02:45:54 +00:00
}
2019-12-09 05:54:32 +00:00
Instruction::Multiply(mode1, mode2, write_mode) => {
2019-12-08 01:23:49 +00:00
let result = self.read(self.ip + 1, mode1) * self.read(self.ip + 2, mode2);
2019-12-09 05:54:32 +00:00
self.write(self.read(self.ip + 3, Mode::Immediate), result, write_mode);
2019-12-08 01:23:49 +00:00
self.ip += 4;
2019-12-07 02:45:54 +00:00
}
2019-12-09 05:54:32 +00:00
Instruction::Input(write_mode) => match self.input.read() {
2019-12-08 01:23:49 +00:00
Some(value) => {
2019-12-09 05:54:32 +00:00
self.write(self.read(self.ip + 1, Mode::Immediate), value, write_mode);
2019-12-08 01:23:49 +00:00
self.ip += 2;
}
None => {
// println!("{}: pause ip = {}", self.name, self.ip);
return ComputeResult::NeedsInput;
}
},
2019-12-07 02:45:54 +00:00
Instruction::Output(mode) => {
2019-12-08 01:23:49 +00:00
let value = self.read(self.ip + 1, mode);
println!("{}: output {}", self.name, value);
self.output.write(value);
self.ip += 2;
2019-12-07 02:45:54 +00:00
}
2019-12-07 03:44:38 +00:00
Instruction::JumpIfTrue(mode1, mode2) => {
2019-12-08 01:23:49 +00:00
if self.read(self.ip + 1, mode1) != 0 {
self.ip = self.read(self.ip + 2, mode2);
2019-12-07 03:44:38 +00:00
} else {
2019-12-08 01:23:49 +00:00
self.ip += 3;
2019-12-07 03:44:38 +00:00
}
}
Instruction::JumpIfFalse(mode1, mode2) => {
2019-12-08 01:23:49 +00:00
if self.read(self.ip + 1, mode1) == 0 {
self.ip = self.read(self.ip + 2, mode2);
2019-12-07 03:44:38 +00:00
} else {
2019-12-08 01:23:49 +00:00
self.ip += 3;
2019-12-07 03:44:38 +00:00
}
}
2019-12-09 05:54:32 +00:00
Instruction::LessThan(mode1, mode2, write_mode) => {
2019-12-08 01:23:49 +00:00
if self.read(self.ip + 1, mode1) < self.read(self.ip + 2, mode2) {
2019-12-09 05:54:32 +00:00
self.write(self.read(self.ip + 3, Mode::Immediate), 1, write_mode);
2019-12-07 03:44:38 +00:00
} else {
2019-12-09 05:54:32 +00:00
self.write(self.read(self.ip + 3, Mode::Immediate), 0, write_mode);
2019-12-07 03:44:38 +00:00
}
2019-12-08 01:23:49 +00:00
self.ip += 4;
2019-12-07 03:44:38 +00:00
}
2019-12-09 05:54:32 +00:00
Instruction::Equals(mode1, mode2, write_mode) => {
2019-12-08 01:23:49 +00:00
if self.read(self.ip + 1, mode1) == self.read(self.ip + 2, mode2) {
2019-12-09 05:54:32 +00:00
self.write(self.read(self.ip + 3, Mode::Immediate), 1, write_mode);
2019-12-07 03:44:38 +00:00
} else {
2019-12-09 05:54:32 +00:00
self.write(self.read(self.ip + 3, Mode::Immediate), 0, write_mode);
2019-12-07 03:44:38 +00:00
}
2019-12-08 01:23:49 +00:00
self.ip += 4;
2019-12-07 03:44:38 +00:00
}
2019-12-09 05:54:32 +00:00
Instruction::AdjustRelativeBase(mode) => {
let base = self.read(self.ip + 1, mode);
self.relative_base += base;
self.relative_base;
self.ip += 2;
}
2019-12-08 01:23:49 +00:00
Instruction::Halt => return ComputeResult::Halted,
2019-12-07 02:45:54 +00:00
}
}
}
2019-12-09 05:54:32 +00:00
pub fn output(&self) -> i64 {
self.output.last_value()
}
2019-12-07 02:45:54 +00:00
}
2019-12-08 01:23:49 +00:00
impl Pipe {
2019-12-09 05:54:32 +00:00
pub fn new(queue: VecDeque<i64>) -> Self {
2019-12-08 01:23:49 +00:00
Pipe { queue, last: None }
}
2019-12-09 05:54:32 +00:00
pub fn push_front(&mut self, value: i64) {
2019-12-08 01:23:49 +00:00
self.queue.push_front(value);
}
}
2019-12-09 05:54:32 +00:00
fn divmod(value: &mut i64, divisor: i64) -> i64 {
2019-12-07 02:45:54 +00:00
let res = *value % divisor;
*value /= divisor;
res
}
2019-12-09 05:54:32 +00:00
impl From<i64> for Mode {
fn from(mode: i64) -> Self {
2019-12-07 02:45:54 +00:00
match mode {
0 => Mode::Address,
1 => Mode::Immediate,
2019-12-09 05:54:32 +00:00
2 => Mode::Relative,
2019-12-07 02:45:54 +00:00
_ => unreachable!(),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::input;
use std::fs;
#[test]
fn test_decode() {
assert_eq!(
decode(1002),
2019-12-09 05:54:32 +00:00
Instruction::Multiply(Mode::Address, Mode::Immediate, Mode::Address)
2019-12-07 02:45:54 +00:00
)
}
#[test]
2019-12-07 02:45:54 +00:00
fn test_day2() {
let input = fs::read_to_string("input/day2.txt").unwrap();
2019-12-08 01:23:49 +00:00
let data = input::read_separated_line(',', &input).unwrap();
let mut program = Computer::new('2', data, vec![], vec![]);
2019-12-07 02:45:54 +00:00
// Check that day2 still works wirh run through this implementation
program.run(Some(12), Some(2));
assert_eq!(program.read(0, Mode::Immediate), 4138658);
2019-12-07 02:45:54 +00:00
}
}