| // The Computer Language Benchmarks Game |
| // http://benchmarksgame.alioth.debian.org/ |
| // |
| // contributed by the Rust Project Developers |
| |
| // Copyright (c) 2012-2014 The Rust Project Developers |
| // |
| // All rights reserved. |
| // |
| // Redistribution and use in source and binary forms, with or without |
| // modification, are permitted provided that the following conditions |
| // are met: |
| // |
| // - Redistributions of source code must retain the above copyright |
| // notice, this list of conditions and the following disclaimer. |
| // |
| // - Redistributions in binary form must reproduce the above copyright |
| // notice, this list of conditions and the following disclaimer in |
| // the documentation and/or other materials provided with the |
| // distribution. |
| // |
| // - Neither the name of "The Computer Language Benchmarks Game" nor |
| // the name of "The Computer Language Shootout Benchmarks" nor the |
| // names of its contributors may be used to endorse or promote |
| // products derived from this software without specific prior |
| // written permission. |
| // |
| // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS |
| // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE |
| // COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
| // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
| // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR |
| // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
| // HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, |
| // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
| // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED |
| // OF THE POSSIBILITY OF SUCH DAMAGE. |
| |
| // no-pretty-expanded |
| |
| use self::Color::{Red, Yellow, Blue}; |
| use std::sync::mpsc::{channel, Sender, Receiver}; |
| use std::fmt; |
| use std::thread; |
| |
| fn print_complements() { |
| let all = [Blue, Red, Yellow]; |
| for aa in &all { |
| for bb in &all { |
| println!("{:?} + {:?} -> {:?}", *aa, *bb, transform(*aa, *bb)); |
| } |
| } |
| } |
| |
| #[derive(Copy, Clone)] |
| enum Color { |
| Red, |
| Yellow, |
| Blue, |
| } |
| |
| impl fmt::Debug for Color { |
| fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
| let str = match *self { |
| Red => "red", |
| Yellow => "yellow", |
| Blue => "blue", |
| }; |
| write!(f, "{}", str) |
| } |
| } |
| |
| #[derive(Copy, Clone)] |
| struct CreatureInfo { |
| name: usize, |
| color: Color |
| } |
| |
| fn show_color_list(set: Vec<Color>) -> String { |
| let mut out = String::new(); |
| for col in &set { |
| out.push(' '); |
| out.push_str(&format!("{:?}", col)); |
| } |
| out |
| } |
| |
| fn show_digit(nn: usize) -> &'static str { |
| match nn { |
| 0 => {" zero"} |
| 1 => {" one"} |
| 2 => {" two"} |
| 3 => {" three"} |
| 4 => {" four"} |
| 5 => {" five"} |
| 6 => {" six"} |
| 7 => {" seven"} |
| 8 => {" eight"} |
| 9 => {" nine"} |
| _ => {panic!("expected digits from 0 to 9...")} |
| } |
| } |
| |
| struct Number(usize); |
| impl fmt::Debug for Number { |
| fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
| let mut out = vec![]; |
| let Number(mut num) = *self; |
| if num == 0 { out.push(show_digit(0)) }; |
| |
| while num != 0 { |
| let dig = num % 10; |
| num = num / 10; |
| let s = show_digit(dig); |
| out.push(s); |
| } |
| |
| for s in out.iter().rev() { |
| try!(write!(f, "{}", s)) |
| } |
| Ok(()) |
| } |
| } |
| |
| fn transform(aa: Color, bb: Color) -> Color { |
| match (aa, bb) { |
| (Red, Red ) => { Red } |
| (Red, Yellow) => { Blue } |
| (Red, Blue ) => { Yellow } |
| (Yellow, Red ) => { Blue } |
| (Yellow, Yellow) => { Yellow } |
| (Yellow, Blue ) => { Red } |
| (Blue, Red ) => { Yellow } |
| (Blue, Yellow) => { Red } |
| (Blue, Blue ) => { Blue } |
| } |
| } |
| |
| fn creature( |
| name: usize, |
| mut color: Color, |
| from_rendezvous: Receiver<CreatureInfo>, |
| to_rendezvous: Sender<CreatureInfo>, |
| to_rendezvous_log: Sender<String> |
| ) { |
| let mut creatures_met = 0; |
| let mut evil_clones_met = 0; |
| let mut rendezvous = from_rendezvous.iter(); |
| |
| loop { |
| // ask for a pairing |
| to_rendezvous.send(CreatureInfo {name: name, color: color}).unwrap(); |
| |
| // log and change, or quit |
| match rendezvous.next() { |
| Some(other_creature) => { |
| color = transform(color, other_creature.color); |
| |
| // track some statistics |
| creatures_met += 1; |
| if other_creature.name == name { |
| evil_clones_met += 1; |
| } |
| } |
| None => break |
| } |
| } |
| // log creatures met and evil clones of self |
| let report = format!("{}{:?}", creatures_met, Number(evil_clones_met)); |
| to_rendezvous_log.send(report).unwrap(); |
| } |
| |
| fn rendezvous(nn: usize, set: Vec<Color>) { |
| // these ports will allow us to hear from the creatures |
| let (to_rendezvous, from_creatures) = channel::<CreatureInfo>(); |
| |
| // these channels will be passed to the creatures so they can talk to us |
| let (to_rendezvous_log, from_creatures_log) = channel::<String>(); |
| |
| // these channels will allow us to talk to each creature by 'name'/index |
| let to_creature: Vec<Sender<CreatureInfo>> = |
| set.iter().enumerate().map(|(ii, &col)| { |
| // create each creature as a listener with a port, and |
| // give us a channel to talk to each |
| let to_rendezvous = to_rendezvous.clone(); |
| let to_rendezvous_log = to_rendezvous_log.clone(); |
| let (to_creature, from_rendezvous) = channel(); |
| thread::spawn(move|| { |
| creature(ii, |
| col, |
| from_rendezvous, |
| to_rendezvous, |
| to_rendezvous_log); |
| }); |
| to_creature |
| }).collect(); |
| |
| let mut creatures_met = 0; |
| |
| // set up meetings... |
| for _ in 0..nn { |
| let fst_creature = from_creatures.recv().unwrap(); |
| let snd_creature = from_creatures.recv().unwrap(); |
| |
| creatures_met += 2; |
| |
| to_creature[fst_creature.name].send(snd_creature).unwrap(); |
| to_creature[snd_creature.name].send(fst_creature).unwrap(); |
| } |
| |
| // tell each creature to stop |
| drop(to_creature); |
| |
| // print each color in the set |
| println!("{}", show_color_list(set)); |
| |
| // print each creature's stats |
| drop(to_rendezvous_log); |
| for rep in from_creatures_log.iter() { |
| println!("{}", rep); |
| } |
| |
| // print the total number of creatures met |
| println!("{:?}\n", Number(creatures_met)); |
| } |
| |
| fn main() { |
| let nn = if std::env::var_os("RUST_BENCH").is_some() { |
| 200000 |
| } else { |
| std::env::args() |
| .nth(1) |
| .and_then(|arg| arg.parse().ok()) |
| .unwrap_or(600) |
| }; |
| |
| print_complements(); |
| println!(""); |
| |
| rendezvous(nn, vec!(Blue, Red, Yellow)); |
| |
| rendezvous(nn, |
| vec!(Blue, Red, Yellow, Red, Yellow, Blue, Red, Yellow, Red, Blue)); |
| } |