Created
December 11, 2016 03:29
-
-
Save gnuvince/13bdcaaac028e6cce98da4ed3edda569 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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