From 6038959cee487e03337bcd673ba656fb9ba45e7b Mon Sep 17 00:00:00 2001 From: Justin Worthe Date: Mon, 18 Dec 2017 08:25:13 +0200 Subject: Day 18: Just implement this multicore cpu for me quickly... --- src/bin/day_18.rs | 207 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 207 insertions(+) create mode 100644 src/bin/day_18.rs (limited to 'src/bin') diff --git a/src/bin/day_18.rs b/src/bin/day_18.rs new file mode 100644 index 0000000..f763f1f --- /dev/null +++ b/src/bin/day_18.rs @@ -0,0 +1,207 @@ +extern crate advent_of_code_2017; +use advent_of_code_2017::*; + +use std::str::FromStr; +use std::collections::HashMap; +use std::sync::mpsc::*; + +fn main() { + let args = AdventArgs::init(); + + let instructions: Vec = args.input.iter() + .map(|line| line.parse().unwrap()) + .collect(); + + let (sender0, receiver0) = channel(); + let (sender1, receiver1) = channel(); + + let mut program0 = Program::new(0, instructions.clone(), sender0, receiver1, args.part == 1); + + if args.part == 1 { + program0.run(); + let mut answer = 0; + while let Ok(x) = receiver0.try_recv() { + answer = x; + } + + println!("Last sent value: {}", answer); + } else { + let mut program1 = Program::new(1, instructions.clone(), sender1, receiver0, args.part == 1); + + while !(program0.terminated && program1.terminated) && (program0.run() || program1.run()) { + } + + + println!("Program 0 sent {} messages", program0.sent_count); + println!("Program 1 sent {} messages", program1.sent_count); + } + + +} + +struct Program { + instructions: Vec, + registers: HashMap, + pc: i64, + terminated: bool, + sender: Sender, + sent_count: u64, + receiver: Receiver, + part1: bool +} + +impl Program { + fn new(process_id: i64, instructions: Vec, sender: Sender, receiver: Receiver, part1: bool) -> Program { + let mut reg = HashMap::new(); + if !part1 { + reg.insert('p', process_id); + } + Program { + instructions: instructions, + registers: reg, + pc: 0, + terminated: false, + sender: sender, + sent_count: 0, + receiver: receiver, + part1: part1 + } + } + fn run(&mut self) -> bool { + use Instruction::*; + + let mut blocked = false; + let mut did_something = false; + + while !blocked && !self.terminated { + if self.pc < 0 || self.pc as usize >= self.instructions.len() { + self.terminated = true; + } + else { + let ins = self.instructions[self.pc as usize].clone(); + + match ins { + Snd(x) => { + self.sent_count += 1; + self.sender.send(self.get(x)).ok(); + }, + Set(x, y) => { + let y_val = self.get(y); + self.set(x, y_val); + }, + Add(x, y) => { + let x_val = self.get(x); + let y_val = self.get(y); + self.set(x, x_val + y_val); + }, + Mul(x, y) => { + let x_val = self.get(x); + let y_val = self.get(y); + self.set(x, x_val * y_val); + }, + Mod(x, y) => { + let x_val = self.get(x); + let y_val = self.get(y); + self.set(x, x_val % y_val); + }, + Rcv(x) => { + if self.part1 { + blocked = self.get(x) != 0; + } else { + match self.receiver.try_recv() { + Ok(y) => { + self.set(x, y); + }, + Err(_) => { + blocked = true; + return did_something; + } + } + } + }, + Jgz(x, y) => { + if self.get(x) > 0 { + self.pc = self.pc + self.get(y) - 1; + } + }, + } + self.pc += 1; + did_something = true; + } + } + true + } + + fn get(&self, register: Data) -> i64 { + use Data::*; + match register { + Register(c) => self.registers.get(&c).cloned().unwrap_or(0), + Literal(i) => i + } + } + + fn set(&mut self, register: Data, value: i64) { + use Data::*; + match register { + Register(c) => { + self.registers.insert(c, value); + }, + _ => {} + } + } +} + +#[derive(Debug, Clone)] +enum Instruction { + Snd(Data), + Set(Data, Data), + Add(Data, Data), + Mul(Data, Data), + Mod(Data, Data), + Rcv(Data), + Jgz(Data, Data) +} + +impl FromStr for Instruction { + type Err = String; + + fn from_str(s: &str) -> Result { + use Instruction::*; + + let mut str_iter = s.split_whitespace(); + let ins = str_iter.next(); + let x = str_iter.next().map(|x| x.parse::()); + let y = str_iter.next().map(|x| x.parse::()); + + match (ins, x, y) { + (Some("snd"), Some(Ok(x)), _) => Ok(Snd(x)), + (Some("set"), Some(Ok(x)), Some(Ok(y))) => Ok(Set(x, y)), + (Some("add"), Some(Ok(x)), Some(Ok(y))) => Ok(Add(x, y)), + (Some("mul"), Some(Ok(x)), Some(Ok(y))) => Ok(Mul(x, y)), + (Some("mod"), Some(Ok(x)), Some(Ok(y))) => Ok(Mod(x, y)), + (Some("rcv"), Some(Ok(x)), _) => Ok(Rcv(x)), + (Some("jgz"), Some(Ok(x)), Some(Ok(y))) => Ok(Jgz(x, y)), + (_, _, _) => Err(format!("Unknown instruction {}", s)) + } + } +} + +#[derive(Debug, Clone, Copy)] +enum Data { + Literal(i64), + Register(char) +} + +impl FromStr for Data { + type Err = String; + + fn from_str(s: &str) -> Result { + use Data::*; + + match (s.parse(), s.chars().next()) { + (Ok(num), _) => Ok(Literal(num)), + (Err(_), Some(c)) => Ok(Register(c)), + (_, _) => Err(format!("Invalid data {}", s)) + } + } +} -- cgit v1.2.3