From 9acf32d696dbf1d1fdf9cbcdb2691535cff9661a Mon Sep 17 00:00:00 2001 From: Adam Wick Date: Mon, 23 Dec 2019 15:33:32 -0800 Subject: [PATCH] Switch to a resumption-style implementation for machines. --- src/arcade.rs | 168 ++++++++++++---------------- src/machine.rs | 296 ++++++++++++++++++++++++++++++------------------- src/main.rs | 24 ++-- src/repair.rs | 147 +++++++++++------------- src/robot.rs | 89 +++++++++------ 5 files changed, 380 insertions(+), 344 deletions(-) diff --git a/src/arcade.rs b/src/arcade.rs index a1c81b6..418ab0d 100644 --- a/src/arcade.rs +++ b/src/arcade.rs @@ -1,35 +1,18 @@ -use crate::endchannel::{Receiver, Sender, channel}; -use crate::machine::Computer; +use crate::machine::{Computer, RunResult}; use terminal_graphics::{Colour, Display}; +use std::collections::VecDeque; use std::fmt; -use std::thread; pub struct Arcade { screen: Vec, width: usize, height: usize, pub score: usize, - joystick_port: Sender, - update_port: Receiver, + logic: Computer, ball: (usize, usize), paddle: (usize, usize), } -pub fn auto_move(arcade: &Arcade) -> Move { - let (ball_x, _) = arcade.ball; - let (paddle_x, _) = arcade.paddle; - - if paddle_x < ball_x { - return Move::Right; - } - - if paddle_x > ball_x { - return Move::Left; - } - - Move::Neutral -} - #[derive(Clone, Copy, Debug, PartialEq)] enum Tile { Empty, @@ -39,13 +22,6 @@ enum Tile { Ball, } -enum Update { - Score(usize), - Ball(usize, usize), - Paddle(usize, usize), - Draw(usize, usize, Tile), -} - impl fmt::Display for Tile { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { @@ -84,51 +60,72 @@ impl Tile { impl Arcade { pub fn new(width: usize, height: usize, cheat: bool, logic_file: &str) -> Arcade { let mut logic = Computer::load(logic_file); - let ( mysend, mut corecv) = channel(); - let (mut cosend, mut myrecv) = channel(); - let (mut upsend, uprecv) = channel(); if cheat { logic.write(0, 2); } - thread::spawn(move || logic.run(&mut corecv, &mut cosend)); - let mut screen = Vec::with_capacity(width * height); screen.resize(width * height, Tile::Empty); - - thread::spawn(move || { - while let Some(first) = myrecv.recv() { - let second = myrecv.recv().expect("Didn't get second?!"); - let third = myrecv.recv().expect("Didn't get third?!"); - - if first == -1 && second == 0 { - upsend.send_ignore_error(Update::Score(third as usize)); - } else { - let x = first as usize; - let y = second as usize; - let t = Tile::new(third); - upsend.send_ignore_error(Update::Draw(x, y, t)); - if t == Tile::Ball { - upsend.send_ignore_error(Update::Ball(x, y)); - } - if t == Tile::HorizontalPaddle { - upsend.send_ignore_error(Update::Paddle(x, y)); - } - } - } - upsend.conclude(); - }); - Arcade { screen, width, height, - joystick_port: mysend, - update_port: uprecv, + logic, score: 0, ball: (0, 0), paddle: (0, 0), } } + pub fn run(mut self, mut redraw: F) -> Self { + let mut output_buffer = vec![]; + let mut input_buffer = VecDeque::new(); + + loop { + match self.logic.run() { + RunResult::Continue(next) => + self.logic = next, + RunResult::Halted(next) => { + self.logic = next; + return self; + } + RunResult::Output(x, next) => { + self.logic = next; + output_buffer.push(x); + if output_buffer.len() == 3 { + if output_buffer[0] == -1 && output_buffer[1] == 0 { + self.score = output_buffer[2] as usize; + } else { + let x = output_buffer[0] as usize; + let y = output_buffer[1] as usize; + let t = Tile::new(output_buffer[2]); + self.screen[ (y * self.width) + x ] = t; + if t == Tile::Ball { + self.ball = (x, y); + let (paddle_x, _) = self.paddle; + + if paddle_x < x { + input_buffer.push_back(Move::Right); + } else if paddle_x > x { + input_buffer.push_back(Move::Left); + } else { + input_buffer.push_back(Move::Neutral); + } + } + if t == Tile::HorizontalPaddle { + self.paddle = (x, y); + } + } + output_buffer = vec![]; + } + } + RunResult::Input(c) => { + self.logic = c(input_buffer.pop_front().unwrap().encode()); + redraw(&self); + } + } + } + } + + #[cfg(test)] fn count_blocks(&self) -> usize { let mut count = 0; @@ -141,39 +138,6 @@ impl Arcade { count } - pub fn process_update(&mut self, next_move: F) -> bool - where F: Fn(&Arcade) -> Move - { - let next = self.update_port.recv(); - - if let Some(ref update) = next { - match update { - &Update::Score(s) => self.score = s, - &Update::Draw(x, y, t) => self.screen[ (y * self.width) + x ] = t, - &Update::Ball(x, y) => { - self.ball = (x, y); - let next = next_move(&self); - self.paddle_move(next); - } - &Update::Paddle(x, y) => { - self.paddle = (x, y); - // let next = next_move(&self); - // self.paddle_move(next); - } - } - } - - next.is_some() - } - - pub fn paddle_move(&mut self, motion: Move) { - match motion { - Move::Left => self.joystick_port.send_ignore_error(-1), - Move::Neutral => self.joystick_port.send_ignore_error(0), - Move::Right => self.joystick_port.send_ignore_error(1), - } - } - pub fn draw(&self, display: &mut Display) { write_to_screen(display, 0, &format!("Score: {}", self.score)); for row in 0..self.height { @@ -202,13 +166,23 @@ pub enum Move { Right, } +impl Move { + fn encode(&self) -> i64 { + match self { + Move::Left => -1, + Move::Neutral => 0, + Move::Right => 1, + } + } +} + #[test] fn day13() { - let mut arcade1 = Arcade::new(38, 21, false, "inputs/day13"); - while arcade1.process_update(auto_move) { } - assert_eq!(301, arcade1.count_blocks()); + let arcade1 = Arcade::new(38, 21, false, "inputs/day13"); + let result1 = arcade1.run(|_| {}); + assert_eq!(301, result1.count_blocks()); - let mut arcade2 = Arcade::new(38, 21, true, "inputs/day13"); - while arcade2.process_update(auto_move) { } - assert_eq!(14096, arcade2.score); + let arcade2 = Arcade::new(38, 21, true, "inputs/day13"); + let result2 = arcade2.run(|_| {}); + assert_eq!(14096, result2.score); } diff --git a/src/machine.rs b/src/machine.rs index a94394c..db319ae 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -1,9 +1,8 @@ -use crate::endchannel::{Sender, Receiver, channel}; +use std::collections::VecDeque; use std::fs; use std::iter::FromIterator; use std::ops::Range; use std::str; -use std::thread; const ADD: i64 = 1; const MULTIPLY: i64 = 2; @@ -42,6 +41,13 @@ pub struct Computer { done: bool } +pub enum RunResult { + Input(Box Computer>), + Output(i64, Computer), + Continue(Computer), + Halted(Computer), +} + impl Computer { pub fn load(path: &str) -> Computer { let byte_buffer = fs::read(path).unwrap(); @@ -108,7 +114,7 @@ impl Computer { self.memory[idx] = val; } - fn step(&mut self, input: &mut Receiver, output: &mut Sender) { + fn step(mut self) -> RunResult { let next_instruction = self.read(self.position); let opcode = next_instruction % 100; let arg1mode = Mode::from((next_instruction / 100) % 10); @@ -123,6 +129,7 @@ impl Computer { self.write(dest, arg1 + arg2); self.position += 4; + RunResult::Continue(self) } MULTIPLY => { let arg1 = self.read_arg(arg1mode, self.position + 1); @@ -131,26 +138,20 @@ impl Computer { self.write(dest, arg1 * arg2); self.position += 4; + RunResult::Continue(self) } INPUT => { let dest = self.read_dest(arg1mode, self.position + 1) as usize; - - match input.recv() { - None => { - output.conclude(); - self.done = true; - } - Some(val) => { - self.write(dest, val); - self.position += 2; - } - } + self.position += 2; + RunResult::Input(Box::new(move |x| { + self.write(dest, x); + self + })) } OUTPUT => { let arg1 = self.read_arg(arg1mode, self.position + 1); - - output.send(arg1); self.position += 2; + RunResult::Output(arg1, self) } JMPIF => { let arg1 = self.read_arg(arg1mode, self.position + 1); @@ -161,6 +162,7 @@ impl Computer { } else { self.position += 3; } + RunResult::Continue(self) } JMPNIF => { let arg1 = self.read_arg(arg1mode, self.position + 1); @@ -171,6 +173,7 @@ impl Computer { } else { self.position += 3; } + RunResult::Continue(self) } LESS_THAN => { let arg1 = self.read_arg(arg1mode, self.position + 1); @@ -179,6 +182,7 @@ impl Computer { self.write(dest, if arg1 < arg2 { 1 } else { 0 }); self.position += 4; + RunResult::Continue(self) } EQUALS => { let arg1 = self.read_arg(arg1mode, self.position + 1); @@ -187,16 +191,18 @@ impl Computer { self.write(dest, if arg1 == arg2 { 1 } else { 0 }); self.position += 4; + RunResult::Continue(self) } ADJUST_BASE => { let arg1 = self.read_arg(arg1mode, self.position + 1); self.relative_base += arg1; self.position += 2; + RunResult::Continue(self) } HALT => { - output.conclude(); self.done = true; + RunResult::Halted(self) } /* */ unknown_pos => @@ -204,29 +210,69 @@ impl Computer { } } - fn halted(&self) -> bool { - self.done + pub fn run(mut self) -> RunResult { + loop { + match self.step() { + RunResult::Continue(next) => + self = next, + result => + return result, + } + } } - pub fn run(&mut self, input: &mut Receiver, output: &mut Sender) { - while !self.halted() { - self.step(input, output); + pub fn standard_run(mut self, inputs: &[i64]) -> Vec { + let mut idx = 0; + let mut res = vec![]; + + loop { + match self.step() { + RunResult::Continue(next) => + self = next, + RunResult::Halted(_) => + return res, + RunResult::Input(c) if idx < inputs.len() => { + self = c(inputs[idx]); + idx += 1; + } + RunResult::Input(_) => + panic!("Ran out of inputs in standard run."), + RunResult::Output(x, next) => { + res.push(x); + self = next; + } + } } } pub fn serialize(&self, inputs: Vec) -> i64 { - let mut previous_output = vec![0]; + let mut previous_output = VecDeque::new(); + previous_output.push_back(0); for input in inputs.iter() { - let mut my_machine = self.clone(); - let ( mysend, mut corecv) = channel(); - let (mut cosend, myrecv) = channel(); - mysend.send(*input); - for i in previous_output.iter() { - mysend.send(*i); + let mut my_machine = self.clone().prime(*input); + let mut output = VecDeque::new(); + + loop { + match my_machine.run() { + RunResult::Continue(next) => + my_machine = next, + RunResult::Halted(_) => + break, + RunResult::Input(c) => + match previous_output.pop_front() { + None => + panic!("Serialized machine wanted input I didn't have!"), + Some(next_input) => + my_machine = c(next_input), + }, + RunResult::Output(o, next) => { + output.push_back(o); + my_machine = next; + } + } } - my_machine.run(&mut corecv, &mut cosend); - previous_output = myrecv.collect(); + previous_output = output; } assert_eq!(previous_output.len(), 1); @@ -263,127 +309,143 @@ impl Computer { (best_score, best_result) } + pub fn prime(self, input: i64) -> Self { + match self.run() { + RunResult::Input(c) => c(input), + _ => + panic!("Priming failure: machine didn't ask for input first.") + } + } + pub fn amplifier(&self, settings: Vec) -> i64 { assert_eq!(settings.len(), 5); - let mut machine_a = self.clone(); - let mut machine_b = self.clone(); - let mut machine_c = self.clone(); - let mut machine_d = self.clone(); - let mut machine_e = self.clone(); - - let ( send_ha, mut recv_ha) = channel(); send_ha.send(settings[0]); - let (mut send_ab, mut recv_ab) = channel(); send_ab.send(settings[1]); - let (mut send_bc, mut recv_bc) = channel(); send_bc.send(settings[2]); - let (mut send_cd, mut recv_cd) = channel(); send_cd.send(settings[3]); - let (mut send_de, mut recv_de) = channel(); send_de.send(settings[4]); - let (mut send_eh, recv_eh) = channel(); - - thread::spawn(move || { machine_a.run(&mut recv_ha, &mut send_ab) }); - thread::spawn(move || { machine_b.run(&mut recv_ab, &mut send_bc) }); - thread::spawn(move || { machine_c.run(&mut recv_bc, &mut send_cd) }); - thread::spawn(move || { machine_d.run(&mut recv_cd, &mut send_de) }); - thread::spawn(move || { machine_e.run(&mut recv_de, &mut send_eh) }); - - send_ha.send(0); // kick it off - + let mut machine_a = self.clone().prime(settings[0]); + let mut machine_b = self.clone().prime(settings[1]); + let mut machine_c = self.clone().prime(settings[2]); + let mut machine_d = self.clone().prime(settings[3]); + let mut machine_e = self.clone().prime(settings[4]); let mut last_output = 0; - for output in recv_eh { - last_output = output; - send_ha.send_ignore_error(output); + loop { + let aout = loop { match machine_a.run() { + RunResult::Halted(_) => return last_output, + RunResult::Output(o, next) => { machine_a = next; break o; } + RunResult::Input(c) => machine_a = c(last_output), + _ => panic!("Unexpted aout"), + } }; + let bout = loop { match machine_b.run() { + RunResult::Halted(_) => return last_output, + RunResult::Output(o, next) => { machine_b = next; break o; } + RunResult::Input(c) => machine_b = c(aout), + _ => panic!("Unexpted aout"), + } }; + let cout = loop { match machine_c.run() { + RunResult::Halted(_) => return last_output, + RunResult::Output(o, next) => { machine_c = next; break o; } + RunResult::Input(c) => machine_c = c(bout), + _ => panic!("Unexpted aout"), + } }; + let dout = loop { match machine_d.run() { + RunResult::Halted(_) => return last_output, + RunResult::Output(o, next) => { machine_d = next; break o; } + RunResult::Input(c) => machine_d = c(cout), + _ => panic!("Unexpted aout"), + } }; + let eout = loop { match machine_e.run() { + RunResult::Halted(_) => return last_output, + RunResult::Output(o, next) => { machine_e = next; break o; } + RunResult::Input(c) => machine_e = c(dout), + _ => panic!("Unexpted aout"), + } }; + last_output = eout; } - - last_output } } #[cfg(test)] -fn run_example(computer: Vec, inputs: Vec, targets: Vec) { +fn run_example(computer: Vec, inputs: &[i64], targets: &[i64]) { let day5a = Computer{ memory: computer, position: 0, relative_base: 0, done: false }; run_computer(day5a, inputs, targets); } #[cfg(test)] -fn run_computer(mut computer: Computer, inputs: Vec, targets: Vec) { - let ( mysend, mut corecv) = channel(); - let (mut cosend, myrecv) = channel(); - for i in inputs.iter() { - mysend.send(*i); - } - computer.run(&mut corecv, &mut cosend); - let outputs: Vec = myrecv.collect(); - assert_eq!(targets, outputs); +fn run_computer(computer: Computer, inputs: &[i64], targets: &[i64]) { + let outputs = computer.standard_run(inputs); + assert_eq!(&outputs, &targets); } #[test] fn test_examples() { - let (mut deadsend, mut deadrecv) = channel(); - - let mut example1 = Computer::from_string("1,0,0,0,99"); + let example1 = Computer::from_string("1,0,0,0,99"); let answer1 = Computer{ memory: vec![2,0,0,0,99], position: 4, relative_base: 0, done: false }; - example1.step(&mut deadrecv, &mut deadsend); - assert_eq!(example1, answer1); + match example1.step() { + RunResult::Continue(result) => assert_eq!(answer1, result), + _ => assert!(false), + } - let mut example2 = Computer::from_string("2,3,0,3,99"); + let example2 = Computer::from_string("2,3,0,3,99"); let answer2 = Computer{ memory: vec![2,3,0,6,99], position: 4, relative_base: 0, done: false }; - example2.step(&mut deadrecv, &mut deadsend); - assert_eq!(example2, answer2); + match example2.step() { + RunResult::Continue(result) => assert_eq!(answer2, result), + _ => assert!(false), + } - let mut example3 = Computer::from_string("2,4,4,5,99,0"); + let example3 = Computer::from_string("2,4,4,5,99,0"); let answer3 = Computer{ memory: vec![2,4,4,5,99,9801], position: 4, relative_base: 0, done: false }; - example3.step(&mut deadrecv, &mut deadsend); - assert_eq!(example3, answer3); + match example3.step() { + RunResult::Continue(result) => assert_eq!(answer3, result), + _ => assert!(false), + } - let mut example4 = Computer::from_string("1,1,1,4,99,5,6,0,99"); + let example4 = Computer::from_string("1,1,1,4,99,5,6,0,99"); let answer4 = Computer{ memory: vec![30,1,1,4,2,5,6,0,99], position: 8, relative_base: 0, done: true }; - example4.run(&mut deadrecv, &mut deadsend); - assert_eq!(example4, answer4); - assert!(example4.halted()); + match example4.run() { + RunResult::Halted(result) => assert_eq!(answer4, result), + _ => assert!(false), + } - let mut example5 = Computer::from_string("1002,4,3,4,33"); + let example5 = Computer::from_string("1002,4,3,4,33"); let answer5 = Computer{ memory: vec![1002,4,3,4,99], position: 4, relative_base: 0, done: true }; - example5.run(&mut deadrecv, &mut deadsend); - assert_eq!(example5, answer5); - assert!(example5.halted()); + match example5.run() { + RunResult::Halted(result) => assert_eq!(answer5, result), + _ => assert!(false), + } - let mut example6 = Computer::from_string("1101,100,-1,4,0"); + let example6 = Computer::from_string("1101,100,-1,4,0"); let answer6 = Computer{ memory: vec![1101,100,-1,4,99], position: 4, relative_base: 0, done: true }; - example6.run(&mut deadrecv, &mut deadsend); - assert_eq!(example6, answer6); - assert!(example6.halted()); + match example6.run() { + RunResult::Halted(result) => assert_eq!(answer6, result), + _ => assert!(false), + } - let mut day5a = Computer::load("inputs/day5"); + let day5a = Computer::load("inputs/day5"); 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(); + let outputs = day5a.standard_run(&[1]); 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,9,8,9,10,9,4,9,99,-1,8], &[8], &[1]); + run_example(vec![3,9,8,9,10,9,4,9,99,-1,8], &[9], &[0]); + run_example(vec![3,9,7,9,10,9,4,9,99,-1,8], &[4], &[1]); + run_example(vec![3,9,7,9,10,9,4,9,99,-1,8], &[8], &[0]); + run_example(vec![3,9,7,9,10,9,4,9,99,-1,8], &[9], &[0]); + run_example(vec![3,3,1108,-1,8,3,4,3,99], &[8], &[1]); + run_example(vec![3,3,1108,-1,8,3,4,3,99], &[9], &[0]); + run_example(vec![3,3,1107,-1,8,3,4,3,99], &[4], &[1]); + run_example(vec![3,3,1107,-1,8,3,4,3,99], &[8], &[0]); + run_example(vec![3,3,1107,-1,8,3,4,3,99], &[9], &[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]); + &[3], &[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]); + &[8], &[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]); + &[192], &[1001]); let example7a = Computer::from_string("3,15,3,16,1002,16,10,16,1,16,15,15,4,15,99,0,0"); let result7a = example7a.serialize(vec![4,3,2,1,0]); @@ -416,15 +478,15 @@ fn test_examples() { assert_eq!(vec![9,7,8,5,6], example7ft); run_example(vec![109,1,204,-1,1001,100,1,100,1008,100,16,101,1006,101,0,99], - vec![], - vec![109,1,204,-1,1001,100,1,100,1008,100,16,101,1006,101,0,99]); + &[], + &[109,1,204,-1,1001,100,1,100,1008,100,16,101,1006,101,0,99]); run_example(vec![1102,34915192,34915192,7,4,7,99,0], - vec![], - vec![1219070632396864]); + &[], + &[1219070632396864]); run_example(vec![104,1125899906842624,99], - vec![], - vec![1125899906842624]); + &[], + &[1125899906842624]); - run_computer(Computer::load("inputs/day9"), vec![1], vec![3063082071]); - run_computer(Computer::load("inputs/day9"), vec![2], vec![81348]); + run_computer(Computer::load("inputs/day9"), &[1], &[3063082071]); + run_computer(Computer::load("inputs/day9"), &[2], &[81348]); } diff --git a/src/main.rs b/src/main.rs index 01f9302..76841b9 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,17 +1,16 @@ mod arcade; mod args; -mod endchannel; mod fuel; mod image; mod machine; mod orbits; +#[cfg(test)] mod repair; +#[cfg(test)] mod robot; mod wiremap; -use crate::arcade::{auto_move, Move}; use crate::args::Command; -use crate::endchannel::channel; use crate::fuel::calculate_fuel; use crate::orbits::Object; use crate::wiremap::WireMap; @@ -32,15 +31,12 @@ fn main() { println!("TOTAL FUEL: {}", total); } - Command::RunComputer(mut initial) => { - let (my_sender, mut their_receiver) = channel(); - let (mut their_sender, my_receiver) = channel(); + Command::RunComputer(initial) => { println!("Initial Computer:"); initial.show(); println!("Running, with input 5."); - my_sender.send(5); - initial.run(&mut their_receiver, &mut their_sender); - for val in my_receiver { + let results = initial.standard_run(&[5]); + for val in results.iter() { println!("Received value: {}", val); } } @@ -162,15 +158,15 @@ fn main() { image.draw(); } - Command::Arcade(mut arcade) => { + Command::Arcade(arcade) => { let mut screen = Display::new(40, 40); screen.clear(); - while arcade.process_update(auto_move) { - arcade.draw(&mut screen); + let result = arcade.run(move |a| { + a.draw(&mut screen); screen.print(); - } - println!("Final score: {}", arcade.score); + }); + println!("Final score: {}", result.score); } } } diff --git a/src/repair.rs b/src/repair.rs index 26a27f4..ff82766 100644 --- a/src/repair.rs +++ b/src/repair.rs @@ -1,7 +1,5 @@ -use crate::endchannel::{Receiver, Sender, channel}; -use crate::machine::Computer; +use crate::machine::{Computer, RunResult}; use std::collections::VecDeque; -use std::thread; #[derive(Clone, Copy, Debug, PartialEq)] enum Direction { @@ -20,16 +18,6 @@ impl Direction { Direction::West => (x - 1, y), } } - - fn random() -> Direction { - match rand::random::() & 0x3 { - 0 => Direction::North, - 1 => Direction::East, - 2 => Direction::South, - 3 => Direction::West, - _ => panic!("The world broke") - } - } } const ALL_DIRECTIONS: [Direction; 4] = [Direction::North, @@ -38,15 +26,6 @@ const ALL_DIRECTIONS: [Direction; 4] = [Direction::North, Direction::West]; impl Direction { - fn reverse(&self) -> Direction { - match self { - Direction::North => Direction::South, - Direction::East => Direction::West, - Direction::South => Direction::North, - Direction::West => Direction::East, - } - } - fn encode(&self) -> i64 { match self { Direction::North => 1, @@ -67,16 +46,6 @@ impl Path { Path{ steps: vec![] } } - fn reverse(&self) -> Path { - let mut steps = Vec::with_capacity(self.steps.len()); - - for step in self.steps.iter().rev() { - steps.push(step.reverse()); - } - - Path{ steps } - } - fn extend(&self) -> Vec { let mut res = Vec::with_capacity(4); @@ -145,28 +114,32 @@ impl RepairSearch { } fn try_path(&mut self, path: &Path) -> MoveResult { - let (mut mysend, mut corecv) = channel(); - let (mut cosend, mut myrecv) = channel(); - let my_computer = self.computer.clone(); + let mut my_computer = self.computer.clone(); let mut last_response = MoveResult::Done; + let mut idx = 0; - thread::spawn(move || my_computer.clone().run(&mut corecv, &mut cosend)); - for step in path.steps.iter() { - mysend.send(step.encode()); - match myrecv.recv() { - None => + loop { + match my_computer.run() { + RunResult::Continue(next) => + my_computer = next, + RunResult::Halted(_) => return last_response, - Some(response) => { - last_response = MoveResult::new(response); + RunResult::Output(x, next) => { + my_computer = next; + last_response = MoveResult::new(x); if last_response == MoveResult::HitWall { - break + return last_response; } } + RunResult::Input(c) => { + if idx >= path.steps.len() { + return last_response; + } + my_computer = c(path.steps[idx].encode()); + idx += 1; + } } } - mysend.conclude(); - - last_response } fn run_search(&mut self) -> usize { @@ -201,8 +174,7 @@ enum Tile { struct Room { layout: Vec, - computer_input: Sender, - computer_output: Receiver, + computer: Computer, width: usize, height: usize, x: usize, @@ -211,17 +183,13 @@ struct Room { impl Room { fn new(width: usize, height: usize, f: &str) -> Room { - let (mut mysend, mut corecv) = channel(); - let (mut cosend, mut myrecv) = channel(); - let mut my_computer = Computer::load(f); + let computer = Computer::load(f); let mut layout = Vec::with_capacity(width * height); layout.resize(width * height, Tile::Unknown); - thread::spawn(move || my_computer.run(&mut corecv, &mut cosend)); Room{ layout, - computer_input: mysend, - computer_output: myrecv, + computer, width, height, x: width / 2, y: height / 2, @@ -248,6 +216,7 @@ impl Room { res } + /* fn print(&self) { println!("\n\n\n\n\n\n"); for y in 0..self.height { @@ -266,6 +235,7 @@ impl Room { println!(); } } + */ fn next_unknown(&self) -> Option { let mut visited = vec![]; @@ -292,51 +262,61 @@ impl Room { None } - fn step(&mut self, direction: Direction) -> bool { + fn step(mut self, direction: Direction) -> (Self, bool) { let (tx, ty) = direction.apply(self.x, self.y); if self.get(tx, ty) == Tile::Wall { - return false; + return (self, false); } - self.computer_input.send(direction.encode()); - match self.computer_output.recv() { - None => false, - Some(resp) => { - let response = MoveResult::new(resp); + loop { + match self.computer.run() { + RunResult::Continue(next) => + self.computer = next, + RunResult::Halted(next) => { + self.computer = next; + return (self, false); + } + RunResult::Input(c) => + self.computer = c(direction.encode()), + RunResult::Output(resp, next) => { + let response = MoveResult::new(resp); - match response { - MoveResult::HitWall => { - self.set(tx, ty, Tile::Wall); - false - } - MoveResult::Done => { - self.set(tx, ty, Tile::Empty); - self.x = tx; - self.y = ty; - true - } - MoveResult::FoundSystem => { - self.set(tx, ty, Tile::Oxygen); - self.x = tx; - self.y = ty; - true + self.computer = next; + match response { + MoveResult::HitWall => { + self.set(tx, ty, Tile::Wall); + return (self, false); + } + MoveResult::Done => { + self.set(tx, ty, Tile::Empty); + self.x = tx; + self.y = ty; + return (self, true); + } + MoveResult::FoundSystem => { + self.set(tx, ty, Tile::Oxygen); + self.x = tx; + self.y = ty; + return (self, true); + } } } } } } - fn map_room(&mut self) -> usize { + fn map_room(mut self) -> (Self, usize) { let mut steps = 0; while let Some(next_step) = self.next_unknown() { //println!("Steps taken: {} [x {}, y {}, next {:?}]", steps, self.x, self.y, next_step); - self.step(next_step); + let (next, _) = self.step(next_step); + self = next; steps += 1; } - steps + (self, steps) } fn has_empty_space(&self) -> bool { @@ -381,8 +361,9 @@ fn day15a() { #[test] fn day15b() { - let mut day15b = Room::new(50, 50, "inputs/day15"); + let day15b = Room::new(50, 50, "inputs/day15"); assert!(day15b.next_unknown().is_some()); - assert_eq!(2452, day15b.map_room()); - assert_eq!(346, day15b.spread()); + let (mut mapped, size) = day15b.map_room(); + assert_eq!(2452, size); + assert_eq!(346, mapped.spread()); } diff --git a/src/robot.rs b/src/robot.rs index c0cbeb2..2ab7850 100644 --- a/src/robot.rs +++ b/src/robot.rs @@ -1,33 +1,26 @@ -use crate::endchannel::{Sender, Receiver, channel}; -use crate::machine::Computer; +use crate::machine::{Computer, RunResult}; use image::{ImageBuffer, Rgb}; -use std::thread; struct HullGrid { data: ImageBuffer, Vec>, + computer: Computer, robot_x: u32, robot_y: u32, robot_dir: Direction, - sender: Sender, - receiver: Receiver, } impl HullGrid { fn new(width: u32, height: u32, computer_path: &str) -> HullGrid { - let mut init_computer = Computer::load(computer_path); - let ( mysend, mut corecv) = channel(); - let (mut cosend, myrecv) = channel(); + let computer = Computer::load(computer_path); assert!(width & 1 == 1); assert!(height & 1 == 1); - thread::spawn(move || init_computer.run(&mut corecv, &mut cosend)); HullGrid { data: ImageBuffer::new(width, height), + computer, robot_x: width / 2, robot_y: height / 2, robot_dir: Direction::Up, - sender: mysend, - receiver: myrecv, } } @@ -53,29 +46,55 @@ impl HullGrid { } } - fn paint_next(&mut self) -> bool { - self.sender.send_ignore_error(if self.is_white() { 1 } else { 0 }); - match self.receiver.recv() { - None => - false, - Some(new_color) => { - let rotation = self.receiver.recv().expect("Didn't get rotation back"); - if new_color == 0 { self.set_black() } else { self.set_white() } - self.robot_dir = if rotation == 0 { - self.robot_dir.rotate_right() - } else { - self.robot_dir.rotate_left() - }; - self.step(); - true + fn paint_next(mut self, output: Option<&str>) -> Option { + let mut new_color: Option = None; + + loop { + let color = if self.is_white() { 1 } else { 0 }; + + match self.computer.run() { + RunResult::Continue(next) => + self.computer = next, + RunResult::Halted(next) => { + self.computer = next; + if let Some(fname) = output { + self.render(fname); + } + return None; + } + RunResult::Input(c) => + self.computer = c(color), + RunResult::Output(o, next) if new_color.is_none() => { + new_color = Some(o); + self.computer = next; + } + RunResult::Output(rotation, next) => { + self.computer = next; + + if new_color.unwrap() == 0 { + self.set_black() + } else { + self.set_white() + } + + self.robot_dir = if rotation == 0 { + self.robot_dir.rotate_right() + } else { + self.robot_dir.rotate_left() + }; + + self.step(); + return Some(self); + } } } } - fn paint_hull(&mut self) -> usize { + fn paint_hull(mut self, output: Option<&str>) -> usize { let mut points = vec![]; - while self.paint_next() { + while let Some(next) = self.paint_next(output) { + self = next; let cur = (self.robot_x, self.robot_y); if !points.contains(&cur) { points.push(cur); @@ -86,7 +105,12 @@ impl HullGrid { } fn render(&self, file: &str) { - self.data.save(file); + match self.data.save(file) { + Err(e) => + println!("Error saving file: {}", e), + Ok(_) => + {} + } } } @@ -143,10 +167,9 @@ fn rotations_work() { #[test] fn day11() { - let mut day1a = HullGrid::new(1001, 1001, "inputs/day11"); - assert_eq!(2373, day1a.paint_hull()); + let day1a = HullGrid::new(1001, 1001, "inputs/day11"); + assert_eq!(2373, day1a.paint_hull(None)); let mut day1b = HullGrid::new(1001, 1001, "inputs/day11"); day1b.set_white(); - assert_eq!(249, day1b.paint_hull()); - day1b.render("day1.png"); + assert_eq!(249, day1b.paint_hull(None)); } \ No newline at end of file