Switch to a resumption-style implementation for machines.

This commit is contained in:
2019-12-23 15:33:32 -08:00
parent e479b8ef62
commit 9acf32d696
5 changed files with 380 additions and 344 deletions

View File

@@ -1,35 +1,18 @@
use crate::endchannel::{Receiver, Sender, channel}; use crate::machine::{Computer, RunResult};
use crate::machine::Computer;
use terminal_graphics::{Colour, Display}; use terminal_graphics::{Colour, Display};
use std::collections::VecDeque;
use std::fmt; use std::fmt;
use std::thread;
pub struct Arcade { pub struct Arcade {
screen: Vec<Tile>, screen: Vec<Tile>,
width: usize, width: usize,
height: usize, height: usize,
pub score: usize, pub score: usize,
joystick_port: Sender<i64>, logic: Computer,
update_port: Receiver<Update>,
ball: (usize, usize), ball: (usize, usize),
paddle: (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)] #[derive(Clone, Copy, Debug, PartialEq)]
enum Tile { enum Tile {
Empty, Empty,
@@ -39,13 +22,6 @@ enum Tile {
Ball, Ball,
} }
enum Update {
Score(usize),
Ball(usize, usize),
Paddle(usize, usize),
Draw(usize, usize, Tile),
}
impl fmt::Display for Tile { impl fmt::Display for Tile {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self { match self {
@@ -84,51 +60,72 @@ impl Tile {
impl Arcade { impl Arcade {
pub fn new(width: usize, height: usize, cheat: bool, logic_file: &str) -> Arcade { pub fn new(width: usize, height: usize, cheat: bool, logic_file: &str) -> Arcade {
let mut logic = Computer::load(logic_file); 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); } if cheat { logic.write(0, 2); }
thread::spawn(move || logic.run(&mut corecv, &mut cosend));
let mut screen = Vec::with_capacity(width * height); let mut screen = Vec::with_capacity(width * height);
screen.resize(width * height, Tile::Empty); 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 { Arcade {
screen, screen,
width, width,
height, height,
joystick_port: mysend, logic,
update_port: uprecv,
score: 0, score: 0,
ball: (0, 0), ball: (0, 0),
paddle: (0, 0), paddle: (0, 0),
} }
} }
pub fn run<F: FnMut(&Arcade)>(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 { fn count_blocks(&self) -> usize {
let mut count = 0; let mut count = 0;
@@ -141,39 +138,6 @@ impl Arcade {
count count
} }
pub fn process_update<F>(&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) { pub fn draw(&self, display: &mut Display) {
write_to_screen(display, 0, &format!("Score: {}", self.score)); write_to_screen(display, 0, &format!("Score: {}", self.score));
for row in 0..self.height { for row in 0..self.height {
@@ -202,13 +166,23 @@ pub enum Move {
Right, Right,
} }
impl Move {
fn encode(&self) -> i64 {
match self {
Move::Left => -1,
Move::Neutral => 0,
Move::Right => 1,
}
}
}
#[test] #[test]
fn day13() { fn day13() {
let mut arcade1 = Arcade::new(38, 21, false, "inputs/day13"); let arcade1 = Arcade::new(38, 21, false, "inputs/day13");
while arcade1.process_update(auto_move) { } let result1 = arcade1.run(|_| {});
assert_eq!(301, arcade1.count_blocks()); assert_eq!(301, result1.count_blocks());
let mut arcade2 = Arcade::new(38, 21, true, "inputs/day13"); let arcade2 = Arcade::new(38, 21, true, "inputs/day13");
while arcade2.process_update(auto_move) { } let result2 = arcade2.run(|_| {});
assert_eq!(14096, arcade2.score); assert_eq!(14096, result2.score);
} }

View File

@@ -1,9 +1,8 @@
use crate::endchannel::{Sender, Receiver, channel}; use std::collections::VecDeque;
use std::fs; use std::fs;
use std::iter::FromIterator; use std::iter::FromIterator;
use std::ops::Range; use std::ops::Range;
use std::str; use std::str;
use std::thread;
const ADD: i64 = 1; const ADD: i64 = 1;
const MULTIPLY: i64 = 2; const MULTIPLY: i64 = 2;
@@ -42,6 +41,13 @@ pub struct Computer {
done: bool done: bool
} }
pub enum RunResult {
Input(Box<dyn FnOnce(i64) -> Computer>),
Output(i64, Computer),
Continue(Computer),
Halted(Computer),
}
impl Computer { impl Computer {
pub fn load(path: &str) -> Computer { pub fn load(path: &str) -> Computer {
let byte_buffer = fs::read(path).unwrap(); let byte_buffer = fs::read(path).unwrap();
@@ -108,7 +114,7 @@ impl Computer {
self.memory[idx] = val; self.memory[idx] = val;
} }
fn step(&mut self, input: &mut Receiver<i64>, output: &mut Sender<i64>) { fn step(mut self) -> RunResult {
let next_instruction = self.read(self.position); let next_instruction = self.read(self.position);
let opcode = next_instruction % 100; let opcode = next_instruction % 100;
let arg1mode = Mode::from((next_instruction / 100) % 10); let arg1mode = Mode::from((next_instruction / 100) % 10);
@@ -123,6 +129,7 @@ impl Computer {
self.write(dest, arg1 + arg2); self.write(dest, arg1 + arg2);
self.position += 4; self.position += 4;
RunResult::Continue(self)
} }
MULTIPLY => { MULTIPLY => {
let arg1 = self.read_arg(arg1mode, self.position + 1); let arg1 = self.read_arg(arg1mode, self.position + 1);
@@ -131,26 +138,20 @@ impl Computer {
self.write(dest, arg1 * arg2); self.write(dest, arg1 * arg2);
self.position += 4; self.position += 4;
RunResult::Continue(self)
} }
INPUT => { INPUT => {
let dest = self.read_dest(arg1mode, self.position + 1) as usize; let dest = self.read_dest(arg1mode, self.position + 1) as usize;
self.position += 2;
match input.recv() { RunResult::Input(Box::new(move |x| {
None => { self.write(dest, x);
output.conclude(); self
self.done = true; }))
}
Some(val) => {
self.write(dest, val);
self.position += 2;
}
}
} }
OUTPUT => { OUTPUT => {
let arg1 = self.read_arg(arg1mode, self.position + 1); let arg1 = self.read_arg(arg1mode, self.position + 1);
output.send(arg1);
self.position += 2; self.position += 2;
RunResult::Output(arg1, self)
} }
JMPIF => { JMPIF => {
let arg1 = self.read_arg(arg1mode, self.position + 1); let arg1 = self.read_arg(arg1mode, self.position + 1);
@@ -161,6 +162,7 @@ impl Computer {
} else { } else {
self.position += 3; self.position += 3;
} }
RunResult::Continue(self)
} }
JMPNIF => { JMPNIF => {
let arg1 = self.read_arg(arg1mode, self.position + 1); let arg1 = self.read_arg(arg1mode, self.position + 1);
@@ -171,6 +173,7 @@ impl Computer {
} else { } else {
self.position += 3; self.position += 3;
} }
RunResult::Continue(self)
} }
LESS_THAN => { LESS_THAN => {
let arg1 = self.read_arg(arg1mode, self.position + 1); 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.write(dest, if arg1 < arg2 { 1 } else { 0 });
self.position += 4; self.position += 4;
RunResult::Continue(self)
} }
EQUALS => { EQUALS => {
let arg1 = self.read_arg(arg1mode, self.position + 1); 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.write(dest, if arg1 == arg2 { 1 } else { 0 });
self.position += 4; self.position += 4;
RunResult::Continue(self)
} }
ADJUST_BASE => { ADJUST_BASE => {
let arg1 = self.read_arg(arg1mode, self.position + 1); let arg1 = self.read_arg(arg1mode, self.position + 1);
self.relative_base += arg1; self.relative_base += arg1;
self.position += 2; self.position += 2;
RunResult::Continue(self)
} }
HALT => { HALT => {
output.conclude();
self.done = true; self.done = true;
RunResult::Halted(self)
} }
/* */ /* */
unknown_pos => unknown_pos =>
@@ -204,29 +210,69 @@ impl Computer {
} }
} }
fn halted(&self) -> bool { pub fn run(mut self) -> RunResult {
self.done loop {
match self.step() {
RunResult::Continue(next) =>
self = next,
result =>
return result,
}
}
} }
pub fn run(&mut self, input: &mut Receiver<i64>, output: &mut Sender<i64>) { pub fn standard_run(mut self, inputs: &[i64]) -> Vec<i64> {
while !self.halted() { let mut idx = 0;
self.step(input, output); 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>) -> i64 { pub fn serialize(&self, inputs: Vec<i64>) -> i64 {
let mut previous_output = vec![0]; let mut previous_output = VecDeque::new();
previous_output.push_back(0);
for input in inputs.iter() { for input in inputs.iter() {
let mut my_machine = self.clone(); let mut my_machine = self.clone().prime(*input);
let ( mysend, mut corecv) = channel(); let mut output = VecDeque::new();
let (mut cosend, myrecv) = channel();
mysend.send(*input); loop {
for i in previous_output.iter() { match my_machine.run() {
mysend.send(*i); 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 = output;
previous_output = myrecv.collect();
} }
assert_eq!(previous_output.len(), 1); assert_eq!(previous_output.len(), 1);
@@ -263,127 +309,143 @@ impl Computer {
(best_score, best_result) (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>) -> i64 { pub fn amplifier(&self, settings: Vec<i64>) -> i64 {
assert_eq!(settings.len(), 5); assert_eq!(settings.len(), 5);
let mut machine_a = self.clone(); let mut machine_a = self.clone().prime(settings[0]);
let mut machine_b = self.clone(); let mut machine_b = self.clone().prime(settings[1]);
let mut machine_c = self.clone(); let mut machine_c = self.clone().prime(settings[2]);
let mut machine_d = self.clone(); let mut machine_d = self.clone().prime(settings[3]);
let mut machine_e = self.clone(); let mut machine_e = self.clone().prime(settings[4]);
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 last_output = 0; let mut last_output = 0;
for output in recv_eh { loop {
last_output = output; let aout = loop { match machine_a.run() {
send_ha.send_ignore_error(output); 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)] #[cfg(test)]
fn run_example(computer: Vec<i64>, inputs: Vec<i64>, targets: Vec<i64>) { fn run_example(computer: Vec<i64>, inputs: &[i64], targets: &[i64]) {
let day5a = Computer{ memory: computer, position: 0, relative_base: 0, done: false }; let day5a = Computer{ memory: computer, position: 0, relative_base: 0, done: false };
run_computer(day5a, inputs, targets); run_computer(day5a, inputs, targets);
} }
#[cfg(test)] #[cfg(test)]
fn run_computer(mut computer: Computer, inputs: Vec<i64>, targets: Vec<i64>) { fn run_computer(computer: Computer, inputs: &[i64], targets: &[i64]) {
let ( mysend, mut corecv) = channel(); let outputs = computer.standard_run(inputs);
let (mut cosend, myrecv) = channel(); assert_eq!(&outputs, &targets);
for i in inputs.iter() {
mysend.send(*i);
}
computer.run(&mut corecv, &mut cosend);
let outputs: Vec<i64> = myrecv.collect();
assert_eq!(targets, outputs);
} }
#[test] #[test]
fn test_examples() { fn test_examples() {
let (mut deadsend, mut deadrecv) = channel(); let example1 = Computer::from_string("1,0,0,0,99");
let mut 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 }; let answer1 = Computer{ memory: vec![2,0,0,0,99], position: 4, relative_base: 0, done: false };
example1.step(&mut deadrecv, &mut deadsend); match example1.step() {
assert_eq!(example1, answer1); 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 }; let answer2 = Computer{ memory: vec![2,3,0,6,99], position: 4, relative_base: 0, done: false };
example2.step(&mut deadrecv, &mut deadsend); match example2.step() {
assert_eq!(example2, answer2); 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 }; let answer3 = Computer{ memory: vec![2,4,4,5,99,9801], position: 4, relative_base: 0, done: false };
example3.step(&mut deadrecv, &mut deadsend); match example3.step() {
assert_eq!(example3, answer3); 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 }; 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); match example4.run() {
assert_eq!(example4, answer4); RunResult::Halted(result) => assert_eq!(answer4, result),
assert!(example4.halted()); _ => 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 }; let answer5 = Computer{ memory: vec![1002,4,3,4,99], position: 4, relative_base: 0, done: true };
example5.run(&mut deadrecv, &mut deadsend); match example5.run() {
assert_eq!(example5, answer5); RunResult::Halted(result) => assert_eq!(answer5, result),
assert!(example5.halted()); _ => 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 }; let answer6 = Computer{ memory: vec![1101,100,-1,4,99], position: 4, relative_base: 0, done: true };
example6.run(&mut deadrecv, &mut deadsend); match example6.run() {
assert_eq!(example6, answer6); RunResult::Halted(result) => assert_eq!(answer6, result),
assert!(example6.halted()); _ => 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 target = vec![0,0,0,0,0,0,0,0,0,7_259_358];
let ( mysend, mut corecv) = channel(); let outputs = day5a.standard_run(&[1]);
let (mut cosend, myrecv) = channel();
mysend.send(1);
day5a.run(&mut corecv, &mut cosend);
let outputs: Vec<i64> = myrecv.collect();
assert_eq!(target, outputs); 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], &[8], &[1]);
run_example(vec![3,9,8,9,10,9,4,9,99,-1,8], vec![9], vec![0]); 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], vec![4], vec![1]); 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], vec![8], vec![0]); 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], vec![9], vec![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], vec![8], vec![1]); 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], vec![9], vec![0]); 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], vec![4], vec![1]); 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], vec![8], vec![0]); 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], vec![9], vec![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, 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, 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], 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, 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, 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], 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, 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, 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], 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 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]); 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); 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], 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], run_example(vec![1102,34915192,34915192,7,4,7,99,0],
vec![], &[],
vec![1219070632396864]); &[1219070632396864]);
run_example(vec![104,1125899906842624,99], 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"), &[1], &[3063082071]);
run_computer(Computer::load("inputs/day9"), vec![2], vec![81348]); run_computer(Computer::load("inputs/day9"), &[2], &[81348]);
} }

View File

@@ -1,17 +1,16 @@
mod arcade; mod arcade;
mod args; mod args;
mod endchannel;
mod fuel; mod fuel;
mod image; mod image;
mod machine; mod machine;
mod orbits; mod orbits;
#[cfg(test)]
mod repair; mod repair;
#[cfg(test)]
mod robot; mod robot;
mod wiremap; mod wiremap;
use crate::arcade::{auto_move, Move};
use crate::args::Command; use crate::args::Command;
use crate::endchannel::channel;
use crate::fuel::calculate_fuel; use crate::fuel::calculate_fuel;
use crate::orbits::Object; use crate::orbits::Object;
use crate::wiremap::WireMap; use crate::wiremap::WireMap;
@@ -32,15 +31,12 @@ fn main() {
println!("TOTAL FUEL: {}", total); println!("TOTAL FUEL: {}", total);
} }
Command::RunComputer(mut initial) => { Command::RunComputer(initial) => {
let (my_sender, mut their_receiver) = channel();
let (mut their_sender, my_receiver) = channel();
println!("Initial Computer:"); println!("Initial Computer:");
initial.show(); initial.show();
println!("Running, with input 5."); println!("Running, with input 5.");
my_sender.send(5); let results = initial.standard_run(&[5]);
initial.run(&mut their_receiver, &mut their_sender); for val in results.iter() {
for val in my_receiver {
println!("Received value: {}", val); println!("Received value: {}", val);
} }
} }
@@ -162,15 +158,15 @@ fn main() {
image.draw(); image.draw();
} }
Command::Arcade(mut arcade) => { Command::Arcade(arcade) => {
let mut screen = Display::new(40, 40); let mut screen = Display::new(40, 40);
screen.clear(); screen.clear();
while arcade.process_update(auto_move) { let result = arcade.run(move |a| {
arcade.draw(&mut screen); a.draw(&mut screen);
screen.print(); screen.print();
} });
println!("Final score: {}", arcade.score); println!("Final score: {}", result.score);
} }
} }
} }

View File

@@ -1,7 +1,5 @@
use crate::endchannel::{Receiver, Sender, channel}; use crate::machine::{Computer, RunResult};
use crate::machine::Computer;
use std::collections::VecDeque; use std::collections::VecDeque;
use std::thread;
#[derive(Clone, Copy, Debug, PartialEq)] #[derive(Clone, Copy, Debug, PartialEq)]
enum Direction { enum Direction {
@@ -20,16 +18,6 @@ impl Direction {
Direction::West => (x - 1, y), Direction::West => (x - 1, y),
} }
} }
fn random() -> Direction {
match rand::random::<u8>() & 0x3 {
0 => Direction::North,
1 => Direction::East,
2 => Direction::South,
3 => Direction::West,
_ => panic!("The world broke")
}
}
} }
const ALL_DIRECTIONS: [Direction; 4] = [Direction::North, const ALL_DIRECTIONS: [Direction; 4] = [Direction::North,
@@ -38,15 +26,6 @@ const ALL_DIRECTIONS: [Direction; 4] = [Direction::North,
Direction::West]; Direction::West];
impl Direction { 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 { fn encode(&self) -> i64 {
match self { match self {
Direction::North => 1, Direction::North => 1,
@@ -67,16 +46,6 @@ impl Path {
Path{ steps: vec![] } 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<Path> { fn extend(&self) -> Vec<Path> {
let mut res = Vec::with_capacity(4); let mut res = Vec::with_capacity(4);
@@ -145,28 +114,32 @@ impl RepairSearch {
} }
fn try_path(&mut self, path: &Path) -> MoveResult { fn try_path(&mut self, path: &Path) -> MoveResult {
let (mut mysend, mut corecv) = channel(); let mut my_computer = self.computer.clone();
let (mut cosend, mut myrecv) = channel();
let my_computer = self.computer.clone();
let mut last_response = MoveResult::Done; let mut last_response = MoveResult::Done;
let mut idx = 0;
thread::spawn(move || my_computer.clone().run(&mut corecv, &mut cosend)); loop {
for step in path.steps.iter() { match my_computer.run() {
mysend.send(step.encode()); RunResult::Continue(next) =>
match myrecv.recv() { my_computer = next,
None => RunResult::Halted(_) =>
return last_response, return last_response,
Some(response) => { RunResult::Output(x, next) => {
last_response = MoveResult::new(response); my_computer = next;
last_response = MoveResult::new(x);
if last_response == MoveResult::HitWall { 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 { fn run_search(&mut self) -> usize {
@@ -201,8 +174,7 @@ enum Tile {
struct Room { struct Room {
layout: Vec<Tile>, layout: Vec<Tile>,
computer_input: Sender<i64>, computer: Computer,
computer_output: Receiver<i64>,
width: usize, width: usize,
height: usize, height: usize,
x: usize, x: usize,
@@ -211,17 +183,13 @@ struct Room {
impl Room { impl Room {
fn new(width: usize, height: usize, f: &str) -> Room { fn new(width: usize, height: usize, f: &str) -> Room {
let (mut mysend, mut corecv) = channel(); let computer = Computer::load(f);
let (mut cosend, mut myrecv) = channel();
let mut my_computer = Computer::load(f);
let mut layout = Vec::with_capacity(width * height); let mut layout = Vec::with_capacity(width * height);
layout.resize(width * height, Tile::Unknown); layout.resize(width * height, Tile::Unknown);
thread::spawn(move || my_computer.run(&mut corecv, &mut cosend));
Room{ Room{
layout, layout,
computer_input: mysend, computer,
computer_output: myrecv,
width, height, width, height,
x: width / 2, x: width / 2,
y: height / 2, y: height / 2,
@@ -248,6 +216,7 @@ impl Room {
res res
} }
/*
fn print(&self) { fn print(&self) {
println!("\n\n\n\n\n\n"); println!("\n\n\n\n\n\n");
for y in 0..self.height { for y in 0..self.height {
@@ -266,6 +235,7 @@ impl Room {
println!(); println!();
} }
} }
*/
fn next_unknown(&self) -> Option<Direction> { fn next_unknown(&self) -> Option<Direction> {
let mut visited = vec![]; let mut visited = vec![];
@@ -292,51 +262,61 @@ impl Room {
None 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); let (tx, ty) = direction.apply(self.x, self.y);
if self.get(tx, ty) == Tile::Wall { if self.get(tx, ty) == Tile::Wall {
return false; return (self, false);
} }
self.computer_input.send(direction.encode()); loop {
match self.computer_output.recv() { match self.computer.run() {
None => false, RunResult::Continue(next) =>
Some(resp) => { self.computer = next,
let response = MoveResult::new(resp); 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 { self.computer = next;
MoveResult::HitWall => { match response {
self.set(tx, ty, Tile::Wall); MoveResult::HitWall => {
false self.set(tx, ty, Tile::Wall);
} return (self, false);
MoveResult::Done => { }
self.set(tx, ty, Tile::Empty); MoveResult::Done => {
self.x = tx; self.set(tx, ty, Tile::Empty);
self.y = ty; self.x = tx;
true self.y = ty;
} return (self, true);
MoveResult::FoundSystem => { }
self.set(tx, ty, Tile::Oxygen); MoveResult::FoundSystem => {
self.x = tx; self.set(tx, ty, Tile::Oxygen);
self.y = ty; self.x = tx;
true self.y = ty;
return (self, true);
}
} }
} }
} }
} }
} }
fn map_room(&mut self) -> usize { fn map_room(mut self) -> (Self, usize) {
let mut steps = 0; let mut steps = 0;
while let Some(next_step) = self.next_unknown() { while let Some(next_step) = self.next_unknown() {
//println!("Steps taken: {} [x {}, y {}, next {:?}]", steps, self.x, self.y, next_step); //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 += 1;
} }
steps (self, steps)
} }
fn has_empty_space(&self) -> bool { fn has_empty_space(&self) -> bool {
@@ -381,8 +361,9 @@ fn day15a() {
#[test] #[test]
fn day15b() { 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!(day15b.next_unknown().is_some());
assert_eq!(2452, day15b.map_room()); let (mut mapped, size) = day15b.map_room();
assert_eq!(346, day15b.spread()); assert_eq!(2452, size);
assert_eq!(346, mapped.spread());
} }

View File

@@ -1,33 +1,26 @@
use crate::endchannel::{Sender, Receiver, channel}; use crate::machine::{Computer, RunResult};
use crate::machine::Computer;
use image::{ImageBuffer, Rgb}; use image::{ImageBuffer, Rgb};
use std::thread;
struct HullGrid { struct HullGrid {
data: ImageBuffer<Rgb<u8>, Vec<u8>>, data: ImageBuffer<Rgb<u8>, Vec<u8>>,
computer: Computer,
robot_x: u32, robot_x: u32,
robot_y: u32, robot_y: u32,
robot_dir: Direction, robot_dir: Direction,
sender: Sender<i64>,
receiver: Receiver<i64>,
} }
impl HullGrid { impl HullGrid {
fn new(width: u32, height: u32, computer_path: &str) -> HullGrid { fn new(width: u32, height: u32, computer_path: &str) -> HullGrid {
let mut init_computer = Computer::load(computer_path); let computer = Computer::load(computer_path);
let ( mysend, mut corecv) = channel();
let (mut cosend, myrecv) = channel();
assert!(width & 1 == 1); assert!(width & 1 == 1);
assert!(height & 1 == 1); assert!(height & 1 == 1);
thread::spawn(move || init_computer.run(&mut corecv, &mut cosend));
HullGrid { HullGrid {
data: ImageBuffer::new(width, height), data: ImageBuffer::new(width, height),
computer,
robot_x: width / 2, robot_x: width / 2,
robot_y: height / 2, robot_y: height / 2,
robot_dir: Direction::Up, robot_dir: Direction::Up,
sender: mysend,
receiver: myrecv,
} }
} }
@@ -53,29 +46,55 @@ impl HullGrid {
} }
} }
fn paint_next(&mut self) -> bool { fn paint_next(mut self, output: Option<&str>) -> Option<Self> {
self.sender.send_ignore_error(if self.is_white() { 1 } else { 0 }); let mut new_color: Option<i64> = None;
match self.receiver.recv() {
None => loop {
false, let color = if self.is_white() { 1 } else { 0 };
Some(new_color) => {
let rotation = self.receiver.recv().expect("Didn't get rotation back"); match self.computer.run() {
if new_color == 0 { self.set_black() } else { self.set_white() } RunResult::Continue(next) =>
self.robot_dir = if rotation == 0 { self.computer = next,
self.robot_dir.rotate_right() RunResult::Halted(next) => {
} else { self.computer = next;
self.robot_dir.rotate_left() if let Some(fname) = output {
}; self.render(fname);
self.step(); }
true 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![]; 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); let cur = (self.robot_x, self.robot_y);
if !points.contains(&cur) { if !points.contains(&cur) {
points.push(cur); points.push(cur);
@@ -86,7 +105,12 @@ impl HullGrid {
} }
fn render(&self, file: &str) { 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] #[test]
fn day11() { fn day11() {
let mut day1a = HullGrid::new(1001, 1001, "inputs/day11"); let day1a = HullGrid::new(1001, 1001, "inputs/day11");
assert_eq!(2373, day1a.paint_hull()); assert_eq!(2373, day1a.paint_hull(None));
let mut day1b = HullGrid::new(1001, 1001, "inputs/day11"); let mut day1b = HullGrid::new(1001, 1001, "inputs/day11");
day1b.set_white(); day1b.set_white();
assert_eq!(249, day1b.paint_hull()); assert_eq!(249, day1b.paint_hull(None));
day1b.render("day1.png");
} }