Skip to content

Instantly share code, notes, and snippets.

@gnuvince
Created December 11, 2016 03:29
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save gnuvince/13bdcaaac028e6cce98da4ed3edda569 to your computer and use it in GitHub Desktop.
Save gnuvince/13bdcaaac028e6cce98da4ed3edda569 to your computer and use it in GitHub Desktop.
use std::io;
use std::collections::HashMap;
use std::collections::VecDeque;
#[derive(Debug, PartialEq, Copy, Clone)]
enum Command {
Assign { bot: usize, value: usize },
Give {
src: usize, // from which bot?
dst1: usize, // to which bot/bin?
dst1_type: ActorType, // bot or bin?
dst2: usize, // ditto
dst2_type: ActorType // ditto
}
}
#[derive(Debug, PartialEq, Copy, Clone)]
enum ActorType {
Bot,
OutputBin
}
impl ActorType {
fn from_str(s: &str) -> ActorType {
if s == "bot" {
ActorType::Bot
} else if s == "output" {
ActorType::OutputBin
} else {
panic!("unknown actor type: {}", s)
}
}
}
struct Simulation {
bots: HashMap<usize, Vec<usize>>, // The chips held by a bot
bins: HashMap<usize, Vec<usize>>, // The chips held by a bin
cmds: HashMap<usize, Command>, // The give command for each bot
queue: VecDeque<usize>, // The bots left to be handled
handler: Option<usize> // Which bot handled 17 and 61?
}
impl Simulation {
fn execute(&mut self, c: &Command) {
match *c {
Command::Assign { bot, value } => {
let v = self.bots.entry(bot).or_insert(vec![]);
v.push(value);
if v.len() == 2 {
self.queue.push_back(bot);
}
}
Command::Give
{ src, dst1, dst1_type, dst2, dst2_type } => {
let min = *self.bots.get(&src).unwrap().iter().min().unwrap();
let max = *self.bots.get(&src).unwrap().iter().max().unwrap();
if min == 17 && max == 61 {
self.handler = Some(src);
}
self.give(dst1, dst1_type, min);
self.give(dst2, dst2_type, max);
let v = self.bots.entry(src).or_insert(vec![]);
v.clear();
}
}
}
fn give(&mut self, dst: usize, ty: ActorType, val: usize) {
match ty {
ActorType::Bot => {
let v = self.bots.entry(dst).or_insert(vec![]);
v.push(val);
if v.len() == 2 {
self.queue.push_back(dst);
}
}
ActorType::OutputBin => {
let v = self.bins.entry(dst).or_insert(vec![]);
v.push(val);
}
}
}
fn simulate(&mut self) {
while let Some(bot) = self.queue.pop_front() {
let cmd = *self.cmds.get(&bot).unwrap();
self.execute(&cmd);
}
}
}
fn parse(line: &str) -> Command {
let words: Vec<&str> = line.split_whitespace().collect();
if words[0] == "value" {
let value = words[1].parse::<usize>().expect("usize");
let bot = words[5].parse::<usize>().expect("usize");
return Command::Assign { bot: bot, value: value };
} else if words[0] == "bot" {
let src = words[1].parse::<usize>().expect("usize");
let dst1 = words[6].parse::<usize>().expect("usize");
let dst1_type = ActorType::from_str(words[5]);
let dst2 = words[11].parse::<usize>().expect("usize");
let dst2_type = ActorType::from_str(words[10]);
return Command::Give {
src: src,
dst1: dst1,
dst1_type: dst1_type,
dst2: dst2,
dst2_type: dst2_type
};
} else {
panic!("unrecognized command: {:?}", line)
}
}
fn solve_b(sim: &Simulation) -> usize {
sim.bins.get(&0).unwrap()[0] *
sim.bins.get(&1).unwrap()[0] *
sim.bins.get(&2).unwrap()[0]
}
#[cfg(not(test))]
fn main() {
let stdin = io::stdin();
let mut buf = String::new();
let mut sim = Simulation {
bots: HashMap::new(),
bins: HashMap::new(),
cmds: HashMap::new(),
queue: VecDeque::new(),
handler: None
};
while stdin.read_line(&mut buf).unwrap() > 0 {
let cmd = parse(&buf);
match cmd {
Command::Assign { .. } => {
sim.execute(&cmd);
}
Command::Give { src, .. } => {
sim.cmds.insert(src, cmd);
}
}
buf.clear();
}
sim.simulate();
println!("A: {:?}", sim.handler);
println!("B: {}", solve_b(&sim));
}
#[cfg(test)]
mod test {
#[test]
fn test_parse() {
use super::{parse, Command, ActorType};
let x = parse("bot 127 gives low to output 1 and high to bot 180");
let targ = Command::Give {
src: 127, dst1: 1, dst2: 180,
dst1_type: ActorType::OutputBin,
dst2_type: ActorType::Bot
};
assert_eq!(x, targ);
let x = parse("bot 127 gives low to bot 1 and high to bot 180");
let targ = Command::Give {
src: 127, dst1: 1, dst2: 180,
dst1_type: ActorType::Bot,
dst2_type: ActorType::Bot
};
assert_eq!(x, targ);
let x = parse("value 123 goes to bot 999");
let targ = Command::Assign { bot: 999, value: 123 };
assert_eq!(x, targ);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment