diff --git a/src/endchannel.rs b/src/endchannel.rs new file mode 100644 index 0000000..0f3ef71 --- /dev/null +++ b/src/endchannel.rs @@ -0,0 +1,54 @@ +use std::sync::mpsc; + +pub struct Sender { + underlying: mpsc::Sender>, + done: bool +} + +impl Sender { + pub fn send(&self, t: T) { + if self.done { + panic!("Sending on previously-closed channel."); + } + self.underlying.send(Some(t)).expect("Channel mysteriously closed on send."); + } + + pub fn conclude(&mut self) { + self.underlying.send(None).expect("Failed to close channel."); + self.done = true; + } +} + +pub struct Receiver { + underlying: mpsc::Receiver>, + done: bool +} + +impl Receiver { + pub fn recv(&mut self) -> Option { + if self.done { + return None; + } + + match self.underlying.recv() { + Err(e) => panic!("Channel mysteriously closed on recv: {}", e), + Ok(None) => { self.done = true; None }, + Ok(Some(x)) => Some(x), + } + } +} + +impl Iterator for Receiver { + type Item = T; + + fn next(&mut self) -> Option { + self.recv() + } +} + +pub fn channel() -> (Sender, Receiver) { + let (undersend, underrecv) = mpsc::channel(); + let sender = Sender{ underlying: undersend, done: false }; + let receiver = Receiver{ underlying: underrecv, done: false }; + (sender, receiver) +} diff --git a/src/machine.rs b/src/machine.rs index 77a97f0..cc0767e 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -1,12 +1,16 @@ +use crate::endchannel::{Sender, Receiver}; use std::fs; use std::iter::FromIterator; use std::str; -use std::sync::mpsc::{Sender, Receiver}; const ADD: i64 = 1; const MULTIPLY: i64 = 2; const INPUT: i64 = 3; const OUTPUT: i64 = 4; +const JMPIF: i64 = 5; +const JMPNIF: i64 = 6; +const LESS_THAN: i64 = 7; +const EQUALS: i64 = 8; const HALT: i64 = 99; const MODE_POSITION: i64 = 0; @@ -15,7 +19,8 @@ const MODE_IMMEDIATE: i64 = 1; #[derive(Clone, Debug, PartialEq)] pub struct Computer { memory: Vec, - position: usize + position: usize, + done: bool } impl Computer { @@ -36,7 +41,7 @@ impl Computer { memory.push(next); } - Computer{ memory, position } + Computer{ memory, position, done: false } } pub fn show(&self) { @@ -62,7 +67,7 @@ impl Computer { self.memory[idx] = val; } - fn step(&mut self, input: &Receiver, output: &Sender) { + fn step(&mut self, input: &mut Receiver, output: &mut Sender) { let next_instruction = self.read(self.position); let opcode = next_instruction % 100; let arg1mode = (next_instruction / 100) % 10; @@ -88,16 +93,53 @@ impl Computer { } INPUT => { let dest = self.read(self.position + 1) as usize; - let val = input.recv().expect("Failed to read input value from channel."); + let val = input.recv().expect("Failed to get input!"); self.write(dest, val); self.position += 2; } OUTPUT => { let arg1 = self.read_arg(arg1mode, self.position + 1); - output.send(arg1).expect("Send failed."); + output.send(arg1); self.position += 2; } - HALT => {} + JMPIF => { + let arg1 = self.read_arg(arg1mode, self.position + 1); + let arg2 = self.read_arg(arg2mode, self.position + 2); + if arg1 != 0 { + self.position = arg2 as usize; + } else { + self.position += 3; + } + } + JMPNIF => { + let arg1 = self.read_arg(arg1mode, self.position + 1); + let arg2 = self.read_arg(arg2mode, self.position + 2); + if arg1 == 0 { + self.position = arg2 as usize; + } else { + self.position += 3; + } + } + LESS_THAN => { + let arg1 = self.read_arg(arg1mode, self.position + 1); + let arg2 = self.read_arg(arg2mode, self.position + 2); + let dest = self.read(self.position + 3) as usize; + + self.write(dest, if arg1 < arg2 { 1 } else { 0 }); + self.position += 4; + } + EQUALS => { + let arg1 = self.read_arg(arg1mode, self.position + 1); + let arg2 = self.read_arg(arg2mode, self.position + 2); + let dest = self.read(self.position + 3) as usize; + + self.write(dest, if arg1 == arg2 { 1 } else { 0 }); + self.position += 4; + } + HALT => { + output.conclude(); + self.done = true; + } /* */ unknown_pos => panic!("Unknown instruction {}", unknown_pos) @@ -105,10 +147,10 @@ impl Computer { } fn halted(&self) -> bool { - self.read(self.position) == HALT + self.done } - pub fn run(&mut self, input: &Receiver, output: &Sender) { + pub fn run(&mut self, input: &mut Receiver, output: &mut Sender) { while !self.halted() { self.step(input, output); } @@ -116,43 +158,87 @@ impl Computer { } #[cfg(test)] -use std::sync::mpsc::channel; +use crate::endchannel::channel; + +#[cfg(test)] +fn run_example(computer: Vec, inputs: Vec, targets: Vec) { + let mut day5a = Computer{ memory: computer, position: 0, done: false }; + let ( mysend, mut corecv) = channel(); + let (mut cosend, myrecv) = channel(); + for i in inputs.iter() { + mysend.send(*i); + } + day5a.run(&mut corecv, &mut cosend); + let outputs: Vec = myrecv.collect(); + assert_eq!(targets, outputs); +} #[test] fn test_examples() { - let (deadsend, deadrecv) = channel(); + let (mut deadsend, mut deadrecv) = channel(); - let mut example1 = Computer{ memory: vec![1,0,0,0,99], position: 0 }; - let answer1 = Computer{ memory: vec![2,0,0,0,99], position: 4 }; - example1.step(&deadrecv, &deadsend); + let mut example1 = Computer{ memory: vec![1,0,0,0,99], position: 0, done: false }; + let answer1 = Computer{ memory: vec![2,0,0,0,99], position: 4, done: false }; + example1.step(&mut deadrecv, &mut deadsend); assert_eq!(example1, answer1); - assert!(example1.halted()); - let mut example2 = Computer{ memory: vec![2,3,0,3,99], position: 0 }; - let answer2 = Computer{ memory: vec![2,3,0,6,99], position: 4 }; - example2.step(&deadrecv, &deadsend); + let mut example2 = Computer{ memory: vec![2,3,0,3,99], position: 0, done: false }; + let answer2 = Computer{ memory: vec![2,3,0,6,99], position: 4, done: false }; + example2.step(&mut deadrecv, &mut deadsend); assert_eq!(example2, answer2); - assert!(example2.halted()); - let mut example3 = Computer{ memory: vec![2,4,4,5,99,0], position: 0 }; - let answer3 = Computer{ memory: vec![2,4,4,5,99,9801], position: 4 }; - example3.step(&deadrecv, &deadsend); + let mut example3 = Computer{ memory: vec![2,4,4,5,99,0], position: 0, done: false }; + let answer3 = Computer{ memory: vec![2,4,4,5,99,9801], position: 4, done: false }; + example3.step(&mut deadrecv, &mut deadsend); assert_eq!(example3, answer3); - assert!(example3.halted()); - let mut example4 = Computer{ memory: vec![1,1,1,4,99,5,6,0,99], position: 0 }; - let answer4 = Computer{ memory: vec![30,1,1,4,2,5,6,0,99], position: 8 }; - example4.run(&deadrecv, &deadsend); + let mut example4 = Computer{ memory: vec![1,1,1,4,99,5,6,0,99], position: 0, done: false }; + let answer4 = Computer{ memory: vec![30,1,1,4,2,5,6,0,99], position: 8, done: true }; + example4.run(&mut deadrecv, &mut deadsend); assert_eq!(example4, answer4); assert!(example4.halted()); - let mut example5 = Computer{ memory: vec![1002,4,3,4,33], position: 0 }; - let answer5 = Computer{ memory: vec![1002,4,3,4,99], position: 4 }; - example5.run(&deadrecv, &deadsend); + let mut example5 = Computer{ memory: vec![1002,4,3,4,33], position: 0, done: false }; + let answer5 = Computer{ memory: vec![1002,4,3,4,99], position: 4, done: true }; + example5.run(&mut deadrecv, &mut deadsend); assert_eq!(example5, answer5); + assert!(example5.halted()); let mut example6 = Computer::from_string("1101,100,-1,4,0", 0); - let answer6 = Computer{ memory: vec![1101,100,-1,4,99], position: 4 }; - example6.run(&deadrecv, &deadsend); + let answer6 = Computer{ memory: vec![1101,100,-1,4,99], position: 4, done: true }; + example6.run(&mut deadrecv, &mut deadsend); assert_eq!(example6, answer6); -} \ No newline at end of file + assert!(example6.halted()); + + let mut day5a = Computer::load("inputs/day5", 0); + let target = vec![0,0,0,0,0,0,0,0,0,7_259_358]; + let ( mysend, mut corecv) = channel(); + let (mut cosend, myrecv) = channel(); + mysend.send(1); + day5a.run(&mut corecv, &mut cosend); + let outputs: Vec = myrecv.collect(); + assert_eq!(target, outputs); + + run_example(vec![3,9,8,9,10,9,4,9,99,-1,8], vec![8], vec![1]); + run_example(vec![3,9,8,9,10,9,4,9,99,-1,8], vec![9], vec![0]); + run_example(vec![3,9,7,9,10,9,4,9,99,-1,8], vec![4], vec![1]); + run_example(vec![3,9,7,9,10,9,4,9,99,-1,8], vec![8], vec![0]); + run_example(vec![3,9,7,9,10,9,4,9,99,-1,8], vec![9], vec![0]); + run_example(vec![3,3,1108,-1,8,3,4,3,99], vec![8], vec![1]); + run_example(vec![3,3,1108,-1,8,3,4,3,99], vec![9], vec![0]); + run_example(vec![3,3,1107,-1,8,3,4,3,99], vec![4], vec![1]); + run_example(vec![3,3,1107,-1,8,3,4,3,99], vec![8], vec![0]); + run_example(vec![3,3,1107,-1,8,3,4,3,99], vec![9], vec![0]); + run_example(vec![3,21,1008,21,8,20,1005,20,22,107,8,21,20,1006,20,31, + 1106,0,36,98,0,0,1002,21,125,20,4,20,1105,1,46,104, + 999,1105,1,46,1101,1000,1,20,4,20,1105,1,46,98,99], + vec![3], vec![999]); + run_example(vec![3,21,1008,21,8,20,1005,20,22,107,8,21,20,1006,20,31, + 1106,0,36,98,0,0,1002,21,125,20,4,20,1105,1,46,104, + 999,1105,1,46,1101,1000,1,20,4,20,1105,1,46,98,99], + vec![8], vec![1000]); + run_example(vec![3,21,1008,21,8,20,1005,20,22,107,8,21,20,1006,20,31, + 1106,0,36,98,0,0,1002,21,125,20,4,20,1105,1,46,104, + 999,1105,1,46,1101,1000,1,20,4,20,1105,1,46,98,99], + vec![192], vec![1001]); +} diff --git a/src/main.rs b/src/main.rs index 65cb104..5e66af0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,13 +1,14 @@ mod args; +mod endchannel; mod fuel; mod machine; mod wiremap; use crate::args::Command; +use crate::endchannel::channel; use crate::fuel::calculate_fuel; use crate::wiremap::WireMap; use std::cmp::{max,min}; -use std::sync::mpsc::channel; fn main() { match Command::get() { @@ -24,14 +25,14 @@ fn main() { } Command::RunComputer(mut initial) => { - let (my_sender, their_receiver) = channel(); - let (their_sender, my_receiver) = channel(); + let (my_sender, mut their_receiver) = channel(); + let (mut their_sender, my_receiver) = channel(); println!("Initial Computer:"); initial.show(); - println!("Running, with input 1."); - my_sender.send(1).expect("Initial send failed"); - initial.run(&their_receiver, &their_sender); - for val in my_receiver.iter() { + println!("Running, with input 5."); + my_sender.send(5); + initial.run(&mut their_receiver, &mut their_sender); + for val in my_receiver { println!("Received value: {}", val); } }