Switch to a resumption-style implementation for machines.
This commit is contained in:
168
src/arcade.rs
168
src/arcade.rs
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
294
src/machine.rs
294
src/machine.rs
@@ -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;
|
||||||
|
|
||||||
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 => {
|
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 = myrecv.collect();
|
}
|
||||||
|
previous_output = output;
|
||||||
}
|
}
|
||||||
|
|
||||||
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]);
|
||||||
}
|
}
|
||||||
|
|||||||
24
src/main.rs
24
src/main.rs
@@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
121
src/repair.rs
121
src/repair.rs
@@ -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,29 +114,33 @@ 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 {
|
||||||
let mut horizon = Path::new().extend();
|
let mut horizon = Path::new().extend();
|
||||||
@@ -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,
|
||||||
|
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);
|
let response = MoveResult::new(resp);
|
||||||
|
|
||||||
|
self.computer = next;
|
||||||
match response {
|
match response {
|
||||||
MoveResult::HitWall => {
|
MoveResult::HitWall => {
|
||||||
self.set(tx, ty, Tile::Wall);
|
self.set(tx, ty, Tile::Wall);
|
||||||
false
|
return (self, false);
|
||||||
}
|
}
|
||||||
MoveResult::Done => {
|
MoveResult::Done => {
|
||||||
self.set(tx, ty, Tile::Empty);
|
self.set(tx, ty, Tile::Empty);
|
||||||
self.x = tx;
|
self.x = tx;
|
||||||
self.y = ty;
|
self.y = ty;
|
||||||
true
|
return (self, true);
|
||||||
}
|
}
|
||||||
MoveResult::FoundSystem => {
|
MoveResult::FoundSystem => {
|
||||||
self.set(tx, ty, Tile::Oxygen);
|
self.set(tx, ty, Tile::Oxygen);
|
||||||
self.x = tx;
|
self.x = tx;
|
||||||
self.y = ty;
|
self.y = ty;
|
||||||
true
|
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());
|
||||||
}
|
}
|
||||||
|
|||||||
77
src/robot.rs
77
src/robot.rs
@@ -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.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 = if rotation == 0 {
|
||||||
self.robot_dir.rotate_right()
|
self.robot_dir.rotate_right()
|
||||||
} else {
|
} else {
|
||||||
self.robot_dir.rotate_left()
|
self.robot_dir.rotate_left()
|
||||||
};
|
};
|
||||||
|
|
||||||
self.step();
|
self.step();
|
||||||
true
|
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");
|
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user