<commit_before>#![feature(plugin)]

extern crate "rustc-serialize" as rustc_serialize;
extern crate docopt;
#[plugin] #[no_link] extern crate docopt_macros;

use std::collections::HashSet;

docopt!(Config derive Debug, "
Usage: env-control <string> [-a PATH | -p PATH | -r PATH]...

Options:
    -a, --append PATH   Append this path to the variable
    -p, --prepend PATH  Prepend this path to the variable
    -r, --remove PATH   Remove this path from the variable
    <string>            The PATH-like string to manipulate
", flag_remove: HashSet<String>);

fn main() {
    let cfg: Config = Config::docopt().decode().unwrap_or_else(|e| e.exit());
    let to_append    = cfg.flag_append;
    let to_prepend   = cfg.flag_prepend;
    let to_remove    = cfg.flag_remove;
    let current_path = cfg.arg_string;

    let mut combined_paths = to_prepend.into_iter()
        .chain(current_path.split(':').map(|slice| slice.to_string()))
        .chain(to_append.into_iter());

    let mut printed_paths: HashSet<String> = HashSet::new();

    loop {
        match combined_paths.next() {
            Some(ref first_path) if first_path.trim().is_empty()   => continue,
            Some(ref first_path) if to_remove.contains(first_path) => continue,

            Some(first_path) => {
                print!("{}", first_path);
                printed_paths.insert(first_path);
                break;
            },

            None => return,
        }
    }

    for path in combined_paths {
        if path.trim().is_empty() || printed_paths.contains(&path) || to_remove.contains(&path) {
            continue
        }

        print!(":{}", path);
        printed_paths.insert(path);
    }

    print!("\n");
}
<commit_msg>Create an 'exec' command<commit_after>#![feature(plugin, io, core, env)]

extern crate "rustc-serialize" as rustc_serialize;
extern crate docopt;
#[plugin] #[no_link] extern crate docopt_macros;

use std::collections::HashSet;
use std::old_io::{process, IoError, stdio};
use std::old_io::process::StdioContainer;
use std::env;

docopt!(Config derive Debug Clone, "
Usage: env-control <var-name> [-a PATH | -p PATH | -r PATH]...
       env-control exec <var-name> [-a PATH | -p PATH | -r PATH]... <cmd> [<cmd-args>]...

Options:
    -a, --append PATH   Append this path to the variable
    -p, --prepend PATH  Prepend this path to the variable
    -r, --remove PATH   Remove this path from the variable
    <var-name>          The PATH-like environment variable to manipulate
", flag_remove: HashSet<String>);

struct Changes {
    to_remove: HashSet<String>,
    to_append: Vec<String>,
    to_prepend: Vec<String>,
}

fn main() {
    let cfg: Config = Config::docopt().decode().unwrap_or_else(|e| e.exit());

    let current_path = match env::var_string(&cfg.arg_var_name[]) {
        Ok(string) => string,
        Err(_)     => "".to_string(),
    };

    let changes = Changes {
        to_remove: cfg.flag_remove,
        to_append: cfg.flag_append,
        to_prepend: cfg.flag_prepend,
    };

    if cfg.cmd_exec {
        let mut buffer = Vec::with_capacity(current_path.len());
        process_paths(&mut buffer, changes, &current_path[]).unwrap();

        process::Command::new(&cfg.arg_cmd[])
            .args(&cfg.arg_cmd_args[])
            .env(cfg.arg_var_name, buffer)
            .stdin(StdioContainer::InheritFd(0))
            .stdout(StdioContainer::InheritFd(1))
            .stderr(StdioContainer::InheritFd(2))
            .spawn()
            .unwrap();
    } else {
        let mut stdout = stdio::stdout();
        process_paths(&mut stdout, changes, &current_path[]).unwrap();
        write!(&mut stdout, "\n").unwrap();
    }
}

fn process_paths<W>(writer: &mut W, changes: Changes, current_path: &str) -> Result<(), IoError> where W: Writer {
    let Changes { to_append, to_prepend, to_remove } = changes;

    let mut combined_paths = to_prepend.into_iter()
        .chain(current_path.split(':').map(|slice| slice.to_string()))
        .chain(to_append.into_iter())
        .filter(move |path| {
            !(path.trim().is_empty() || to_remove.contains(path))
        });

    let mut printed_paths: HashSet<String> = HashSet::new();

    if let Some(first_path) = combined_paths.next() {
        try!(write!(writer, "{}", first_path));
        printed_paths.insert(first_path);
    } else {
        return Ok(());
    }

    for path in combined_paths {
        if printed_paths.contains(&path) {
            continue
        }

        try!(write!(writer, ":{}", path));
        printed_paths.insert(path);
    }

    Ok(())
}
<|endoftext|>


<commit_before>mod error;

// My IP address providers
mod myip;

// DNS providers
mod dns;

// Configuration
mod config;

#[macro_use]
extern crate clap;

#[macro_use]
extern crate log;
extern crate env_logger;

extern crate xmlrpc;
extern crate rustc_serialize;
extern crate regex;
extern crate ip;
extern crate hyper;

use clap::{Arg, App};
use std::env;

use config::Config;
use dns::*;
use error::Result;
use myip::*;
use std::process;

fn main() {
    let config = build_config();

    match main_with_errors(&config) {
        Ok(_) => info!("Process ends with success"),
        Err(err) => {
            error!("Process failed with result: {}", err);
            process::exit(-1);
        }
    }
}

fn build_config() -> Config {
    let matches = App::new("gdu")
        .version(&crate_version!()[..])
        .author("Damien Lecan <dev@dlecan.com>")
        .about("Gandi DNS updater, useful to reflect your dynamic IP address to your Gandi DNS zone file.\nIP address is read from stdin.")
        .args_from_usage(
            "-a --apikey=[apikey] 'Your API key provided by Gandi'
            -d --domain=[domain] 'The domain name whose active zonefile will be updated, e.g. \"domain.com\"'
            -n --dry-run 'Dry run, don't really update Gandi zone file'
            -f --force 'Force new zonefile creation even if IP address isn\'t modified'
            -r --record-name=[record_name] 'Name of the A record to update or create (without domain)'
            [verbose]... -v 'Verbose mode'")
        .arg(Arg::with_name("ip_provider")
            .help("IP address provider name to use to get IP address.")
            .short("i")
            .long("ip-provider")
            .takes_value(true)
            .multiple(false))
        .get_matches();

    // Init logging to DEBUG only if user requires it
    match matches.occurrences_of("verbose") {
        0 => env::set_var("RUST_LOG", "INFO"),
        1 => {
            println!("Verbose mode");
            env::set_var("RUST_LOG", "DEBUG");
        }
        2 | _=> {
            println!("More verbose mode");
            env::set_var("RUST_LOG", "TRACE");
        }
    }
    env_logger::init().unwrap();

    let apikey = matches.value_of("apikey").unwrap();
    debug!("Using apikey: {}", apikey);

    let domain = matches.value_of("domain").unwrap();
    debug!("Using domain: {}", domain);

    let record_name = matches.value_of("record_name").unwrap();
    debug!("Using record name: {}", record_name);

    let dry_run = matches.is_present("dry-run");
    debug!("Dry run: {}", dry_run);

    let force = matches.is_present("force");
    debug!("Force: {}", force);

    let ip_provider = value_t_or_exit!(matches.value_of("ip_provider"), IpProvider);
    debug!("IP address provider: {:?}", ip_provider);

    Config {
        apikey: apikey.to_owned(),
        domain: domain.to_owned(),
        record_name: record_name.to_owned(),
        force: force,
        ip_provider: ip_provider,
    }
}

fn main_with_errors(config: &Config) -> Result<()> {

    let ip_provider = IpAddressProvider::from_config(config);

    let expected_ip_addr = try!(ip_provider.get_my_ip_addr());

    debug!("Found IP address: {}", expected_ip_addr);

    // Force Gandi DNS provider for now
    let mut dns_provider = dns::GandiDNSProvider::new(&config.apikey);

    try!(dns_provider.init(&config.domain));

    match expected_ip_addr {
        ip::IpAddr::V6(_)
            if !dns_provider.handle_ipv6_addr() => panic!("You cannot use IP v6 addresses with the selected DNS provider"),
        _ => (),
    }

    let maybe_checked = try!(dns_provider.is_record_already_declared(&config.record_name));

    match maybe_checked {
        Some(ip_addr) => {
            debug!("Record already declared, with IP address: {}", &ip_addr);

            if !config.force && (&ip_addr == &expected_ip_addr) {
                debug!("IP address not modified, no record to update");
                Ok(())
            } else {
                debug!("Update record '{}' with IP address '{}'", &config.record_name, &expected_ip_addr);
                Ok(try!(dns_provider.update_record(&config.record_name, &expected_ip_addr)))
            }
        }
        None => Ok(try!(dns_provider.create_record(&config.record_name, &expected_ip_addr)))
    }
}
<commit_msg>Log IP address found should be always visible (so INFO log level)<commit_after>mod error;

// My IP address providers
mod myip;

// DNS providers
mod dns;

// Configuration
mod config;

#[macro_use]
extern crate clap;

#[macro_use]
extern crate log;
extern crate env_logger;

extern crate xmlrpc;
extern crate rustc_serialize;
extern crate regex;
extern crate ip;
extern crate hyper;

use clap::{Arg, App};
use std::env;

use config::Config;
use dns::*;
use error::Result;
use myip::*;
use std::process;

fn main() {
    let config = build_config();

    match main_with_errors(&config) {
        Ok(_) => info!("Process ends with success"),
        Err(err) => {
            error!("Process failed with result: {}", err);
            process::exit(-1);
        }
    }
}

fn build_config() -> Config {
    let matches = App::new("gdu")
        .version(&crate_version!()[..])
        .author("Damien Lecan <dev@dlecan.com>")
        .about("Gandi DNS updater, useful to reflect your dynamic IP address to your Gandi DNS zone file.\nIP address is read from stdin.")
        .args_from_usage(
            "-a --apikey=[apikey] 'Your API key provided by Gandi'
            -d --domain=[domain] 'The domain name whose active zonefile will be updated, e.g. \"domain.com\"'
            -n --dry-run 'Dry run, don't really update Gandi zone file'
            -f --force 'Force new zonefile creation even if IP address isn\'t modified'
            -r --record-name=[record_name] 'Name of the A record to update or create (without domain)'
            [verbose]... -v 'Verbose mode'")
        .arg(Arg::with_name("ip_provider")
            .help("IP address provider name to use to get IP address.")
            .short("i")
            .long("ip-provider")
            .takes_value(true)
            .multiple(false))
        .get_matches();

    // Init logging to DEBUG only if user requires it
    match matches.occurrences_of("verbose") {
        0 => env::set_var("RUST_LOG", "INFO"),
        1 => {
            println!("Verbose mode");
            env::set_var("RUST_LOG", "DEBUG");
        }
        2 | _=> {
            println!("More verbose mode");
            env::set_var("RUST_LOG", "TRACE");
        }
    }
    env_logger::init().unwrap();

    let apikey = matches.value_of("apikey").unwrap();
    debug!("Using apikey: {}", apikey);

    let domain = matches.value_of("domain").unwrap();
    debug!("Using domain: {}", domain);

    let record_name = matches.value_of("record_name").unwrap();
    debug!("Using record name: {}", record_name);

    let dry_run = matches.is_present("dry-run");
    debug!("Dry run: {}", dry_run);

    let force = matches.is_present("force");
    debug!("Force: {}", force);

    let ip_provider = value_t_or_exit!(matches.value_of("ip_provider"), IpProvider);
    debug!("IP address provider: {:?}", ip_provider);

    Config {
        apikey: apikey.to_owned(),
        domain: domain.to_owned(),
        record_name: record_name.to_owned(),
        force: force,
        ip_provider: ip_provider,
    }
}

fn main_with_errors(config: &Config) -> Result<()> {

    let ip_provider = IpAddressProvider::from_config(config);

    let my_ip = try!(ip_provider.get_my_ip_addr());

    info!("My IP address: {}", my_ip);

    // Force Gandi DNS provider for now
    let mut dns_provider = dns::GandiDNSProvider::new(&config.apikey);

    try!(dns_provider.init(&config.domain));

    match my_ip {
        ip::IpAddr::V6(_)
            if !dns_provider.handle_ipv6_addr() => panic!("You cannot use IP v6 addresses with the selected DNS provider"),
        _ => (),
    }

    let maybe_checked = try!(dns_provider.is_record_already_declared(&config.record_name));

    match maybe_checked {
        Some(ip_addr) => {
            debug!("Record already declared, with IP address: {}", &ip_addr);

            if !config.force && (&ip_addr == &my_ip) {
                debug!("IP address not modified, no record to update");
                Ok(())
            } else {
                debug!("Update record '{}' with IP address '{}'", &config.record_name, &my_ip);
                Ok(try!(dns_provider.update_record(&config.record_name, &my_ip)))
            }
        }
        None => Ok(try!(dns_provider.create_record(&config.record_name, &my_ip)))
    }
}
<|endoftext|>


<commit_before>extern crate arguments;
extern crate temporary;

use std::collections::HashMap;
use std::fmt::Display;

const USAGE: &'static str = "
Usage: cite [options]

Options:
    --bib <FILE>       A bibliography file.
    --ref <NAME>       A reference name.

    --help             Display this message.
";

macro_rules! ok(
    ($result:expr) => (match $result {
        Ok(result) => result,
        Err(error) => raise!(error),
    });
);

macro_rules! raise(
    ($error:expr) => (return Err(Box::new($error)));
    ($($arg:tt)*) => (raise!(format!($($arg)*)));
);

pub type Error = Box<Display>;
pub type Result<T> = std::result::Result<T, Error>;

fn main() {
    start().unwrap_or_else(|error| fail(error));
}

fn start() -> Result<()> {
    let arguments = match arguments::parse(std::env::args()) {
        Ok(arguments) => arguments,
        Err(error) => raise!(error),
    };

    if arguments.get::<bool>("help").unwrap_or(false) {
        help();
    }

    let mut map = HashMap::new();
    map.insert("<bibliography>", "Bibliography!");
    map.insert("<citation>", "Citation!");

    println!("{}", replace(LATEX_TEMPLATE.trim(), &map));

    Ok(())
}

fn help() -> ! {
    println!("{}", USAGE.trim());
    std::process::exit(0);
}

fn fail(error: Error) -> ! {
    use std::io::{stderr, Write};
    let message = format!("Error: {}.\n{}", &*error, USAGE);
    stderr().write_all(message.as_bytes()).unwrap();
    std::process::exit(1);
}

fn replace(text: &str, map: &HashMap<&str, &str>) -> String {
    let mut text = text.to_string();
    for (key, value) in map {
        text = text.replace(key, value);
    }
    text
}

const LATEX_TEMPLATE: &'static str = r#"
\documentclass[journal]{IEEEtran}
\pagestyle{empty}
\renewcommand{\refname}{}

\begin{filecontents}{bibliography.bib}
<bibliography>
\end{filecontents}

\begin{document}
\nocite{<citation>}
\bibliography{IEEEabrv,bibliography.bib}
\bibliographystyle{IEEEtran}
\end{document}
"#;
<commit_msg>Implement the basic flow of commands<commit_after>extern crate arguments;
extern crate temporary;

use std::collections::HashMap;
use std::fmt::Display;
use std::fs::File;
use std::io::{Read, Write};
use std::process::Command;
use temporary::Directory;

const USAGE: &'static str = "
Usage: cite [options]

Options:
    --bib <FILE>       A bibliography file (required).
    --ref <NAME>       A reference name (required).

    --help             Display this message.
";

macro_rules! ok(
    ($result:expr) => (match $result {
        Ok(result) => result,
        Err(error) => raise!(error),
    });
);

macro_rules! raise(
    ($error:expr) => (return Err(Box::new($error)));
    ($($arg:tt)*) => (raise!(format!($($arg)*)));
);

pub type Error = Box<Display>;
pub type Result<T> = std::result::Result<T, Error>;

fn main() {
    start().unwrap_or_else(|error| fail(error));
}

fn start() -> Result<()> {
    let arguments = match arguments::parse(std::env::args()) {
        Ok(arguments) => arguments,
        Err(error) => raise!(error),
    };

    if arguments.get::<bool>("help").unwrap_or(false) {
        help();
    }

    let bibliography = match arguments.get::<String>("bib") {
        Some(bibliography) => bibliography,
        _ => raise!("a bibliography file is required"),
    };
    let reference = match arguments.get::<String>("ref") {
        Some(reference) => reference,
        _ => raise!("a reference name is required"),
    };

    process(TEMPLATE.trim(), &bibliography, &reference)
}

fn process(template: &str, bibliography: &str, reference: &str) -> Result<()> {
    let root = ok!(Directory::new("cite"));

    macro_rules! cmd(
        ($command:expr) => (Command::new($command));
    );
    macro_rules! run(
        ($command:expr) => ({
            let status = ok!($command.current_dir(&root).status());
            if !status.success() {
                raise!(status);
            }
        });
    );

    {
        let mut map = HashMap::new();
        map.insert("<bibliography>", bibliography);
        map.insert("<reference>", reference);
        let tex = replace(template, &map);

        let mut file = ok!(File::create(root.join("paper.tex")));
        ok!(file.write_all(tex.as_bytes()));
    }

    run!(cmd!("latex").arg("paper.tex"));
    run!(cmd!("bibtex").arg("paper"));
    run!(cmd!("latex").arg("paper.tex"));
    run!(cmd!("latex").arg("paper.tex"));
    run!(cmd!("dvipdf").arg("paper.dvi"));
    run!(cmd!("pdftotext").arg("paper.pdf"));

    let mut buffer = Vec::new();
    {
        let mut file = ok!(File::open(root.join("paper.txt")));
        ok!(file.read_to_end(&mut buffer));
    }

    let content = String::from_utf8_lossy(&buffer);
    println!("{}", content.trim());

    Ok(())
}

fn help() -> ! {
    println!("{}", USAGE.trim());
    std::process::exit(0);
}

fn fail(error: Error) -> ! {
    use std::io::{stderr, Write};
    let message = format!("Error: {}.\n{}", &*error, USAGE);
    stderr().write_all(message.as_bytes()).unwrap();
    std::process::exit(1);
}

fn replace(text: &str, map: &HashMap<&str, &str>) -> String {
    let mut text = text.to_string();
    for (key, value) in map {
        text = text.replace(key, value);
    }
    text
}

const TEMPLATE: &'static str = r#"
\documentclass[journal]{IEEEtran}
\pagestyle{empty}
\renewcommand{\refname}{}

\begin{document}
\nocite{<reference>}
\bibliography{IEEEabrv,<bibliography>}
\bibliographystyle{IEEEtran}
\end{document}
"#;
<|endoftext|>


<commit_before>//! Sets up a subtractive synth listening to the default MIDI input

extern crate oxcable;
use oxcable::types::{MidiEvent, MidiMessage};

mod subtractive_synth;
use subtractive_synth::{SubtractiveSynth, SubtractiveSynthMessage};

fn qx49_controls(event: MidiEvent) -> Option<SubtractiveSynthMessage> {
    let (byte1, byte2) = match event.payload {
        MidiMessage::ControlChange(byte1, byte2) => (byte1, byte2),
        _ => panic!("impossible midi event")
    };
    let range = byte2 as f32 / 127.0;
    match byte1 {
        22 => Some(SubtractiveSynthMessage::SetAttack(5.0*range)),
        23 => Some(SubtractiveSynthMessage::SetDecay(5.0*range)),
        24 => Some(SubtractiveSynthMessage::SetSustain(range)),
        25 => Some(SubtractiveSynthMessage::SetRelease(5.0*range)),
        _ => None
    }
}

fn main() {
    use oxcable::chain::DeviceChain;
    use oxcable::dynamics::Limiter;
    use oxcable::io::audio::AudioEngine;
    use oxcable::io::midi::MidiEngine;
    use oxcable::mixers::Gain;
    use oxcable::oscillator::{AntialiasType, Waveform};
    use oxcable::utils::tick::tick_until_enter;

    println!("Initializing signal chain...");
    let audio_engine = AudioEngine::open().unwrap();
    let midi_engine = MidiEngine::open().unwrap();
    let mut chain = DeviceChain::from(
        SubtractiveSynth::new(midi_engine.choose_input(), 10)
            .waveform(Waveform::Saw(AntialiasType::PolyBlep))
            .control_map(qx49_controls)
    ).into(
        Gain::new(-6.0, 1)
    ).into(
        Limiter::new(-3.0, 0.0, 1)
    ).into(
        audio_engine.default_output(1)
    );

    println!("Playing. Press Enter to quit...");
    tick_until_enter(&mut chain);
}
<commit_msg>Tweak use statements<commit_after>//! Sets up a subtractive synth listening to the default MIDI input

extern crate oxcable;
use oxcable::types::{MidiEvent, MidiMessage};

mod subtractive_synth;
use subtractive_synth::{SubtractiveSynth, SubtractiveSynthMessage};

fn qx49_controls(event: MidiEvent) -> Option<SubtractiveSynthMessage> {
    let (byte1, byte2) = match event.payload {
        MidiMessage::ControlChange(byte1, byte2) => (byte1, byte2),
        _ => panic!("impossible midi event")
    };
    let range = byte2 as f32 / 127.0;
    match byte1 {
        22 => Some(SubtractiveSynthMessage::SetAttack(5.0*range)),
        23 => Some(SubtractiveSynthMessage::SetDecay(5.0*range)),
        24 => Some(SubtractiveSynthMessage::SetSustain(range)),
        25 => Some(SubtractiveSynthMessage::SetRelease(5.0*range)),
        _ => None
    }
}

fn main() {
    use oxcable::chain::DeviceChain;
    use oxcable::dynamics::Limiter;
    use oxcable::io::audio::AudioEngine;
    use oxcable::io::midi::MidiEngine;
    use oxcable::mixers::Gain;
    use oxcable::oscillator::{Saw, PolyBlep};
    use oxcable::utils::tick::tick_until_enter;

    println!("Initializing signal chain...");
    let audio_engine = AudioEngine::open().unwrap();
    let midi_engine = MidiEngine::open().unwrap();
    let mut chain = DeviceChain::from(
        SubtractiveSynth::new(midi_engine.choose_input(), 10)
            .waveform(Saw(PolyBlep))
            .control_map(qx49_controls)
    ).into(
        Gain::new(-12.0, 1)
    ).into(
        Limiter::new(-3.0, 0.0, 1)
    ).into(
        audio_engine.default_output(1)
    );

    println!("Playing. Press Enter to quit...");
    tick_until_enter(&mut chain);
}
<|endoftext|>


<commit_before>//! Crates.fyi - Documentation generator for crates released into
//! [https://crates.io](https://crates.io)
//!
//! # SYNOPSIS
//!
//! ./cratesfyi -b _package_
//!
//! # DESCRIPTION
//!
//! This script is an attempt to make a centralized documentation repository
//! for crates available in crates.io. Script is using chroot environment to
//! build documentation and fixing links on the fly.
//!
//! ## PREPARING CHROOT ENVIRONMENT
//!
//! This script is using a chroot environment to build documentation. I don't
//! think it was necessary but I didn't wanted to add bunch of stuff to my
//! stable server and a little bit more security doesn't hurt anyone.
//!
//! chroot environment must be placed in **script\_dir/chroot** directory. And
//! you must install desired version of rustc inside chroot environment. Don't
//! forget to add a regular user and create a link named **build\_home** which is
//! pointing to chroot user's home directory.  Make sure regular user is using
//! same uid with your current user. You can change username of chroot user in
//! $OPTIONS variable placed on top of this script. By default it is using
//! _onur_.
//!
//! You also need clone crates.io-index respository. You can clone repository
//! from [crates.io-index](https://github.com/rust-lang/crates.io-index).
//!
//! This script is using _sudo_ to use chroot command. chroot is only command
//! called by sudo in this script. Make sure user has rights to call chroot
//! command with sudo.
//!
//! And lastly you need to copy build.sh script into users home directory with
//! **.build.sh** name. Make sure chroot user has permissions to execute
//! **.build.sh** script.
//!
//! Directory structure should look like this:
//!
//! ```text
//! .
//! ├── cratesfyi                       # Main program
//! ├── build_home -> chroot/home/onur  # Sym link to chroot user's home
//! ├── chroot                          # chroot environment
//! │   ├── bin
//! │   ├── etc
//! │   ├── home
//! │   │   └── onur                    # chroot user's home directory
//! │   │       └── .build.sh           # Build script to run cargo doc
//! │   └── ...
//! ├── crates.io-index                 # Clone of crates.io-index
//! │   ├── 1
//! │   ├── 2
//! │   └── ...
//! ├── logs                            # Build logs will be placed here
//! │   └── ...
//! └── public_html
//!     └── crates                      # Documentations will be placed here
//! ```
//!
//!
//! # ARGS
//!
//! - **-b, --build-documentation** _crate_
//!
//!     Build documentation of a crate. If no crate name is provided, script will
//!     try to build documentation for all crates.
//!
//! - **-v, --version** _version_
//!
//!     Build documentation of a crate with given version. Otherwise script will
//!     try to build documentation for all versions. This option must be used with
//!     _-b_ argument and a crate name.
//!
//! - **-s, --skip**
//!
//!     Skip generating if documentation is exist in destination directory.
//!
//! - **--skip-tried**
//!
//!     Skips generating documentation if it's already tried before and log file is
//!     available for crate in logs directory.
//!
//! - **-k, --keep-build-directory**
//!
//!     Keep crate files in build directory after operation finishes.
//!
//! - **--destination** _path_
//!
//!     Destination path. Generated documentation directories will be moved to this
//!     directory. Default value: **script\_dir/public\_html/crates**
//!
//! - **--chroot** _path_
//!
//!     Chroot path. Default value: **script\_dir/chroot**
//!
//! - **--debug**
//!
//!     Show debug messages and place debug info in logs.
//!
//! - **-h, --help**
//!
//!     Show usage information and exit.
//!
//! # COPYRIGHT
//!
//! Copyright 2016 Onur Aslan.
//!
//! This program is free software: you can redistribute it and/or modify
//! it under the terms of the GNU General Public License as published by
//! the Free Software Foundation, either version 3 of the License, or
//! (at your option) any later version.
//!
//! This program is distributed in the hope that it will be useful,
//! but WITHOUT ANY WARRANTY; without even the implied warranty of
//! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//! GNU General Public License for more details.
//!
//! You should have received a copy of the GNU General Public License
//! along with this program.  If not, see
//! [http://www.gnu.org/licenses/](http://www.gnu.org/licenses/).

extern crate rustc_serialize;
extern crate toml;

pub mod docbuilder;

fn main() {

    let crte = docbuilder::crte::Crate::new("sdl2".to_string(),
                                            vec!["0.9.1".to_string()]);

    let mut prefix = std::env::current_dir().unwrap();
    prefix.push("../cratesfyi-prefix");

    let sex = docbuilder::DocBuilder::from_prefix(prefix);
    println!("{:#?}", sex);

    //sex.build_doc_for_every_crate();
    let res = sex.build_doc_for_crate_version(&crte, 0);
    println!("{:#?}", res);
}
<commit_msg>Use regex crate<commit_after>//! Crates.fyi - Documentation generator for crates released into
//! [https://crates.io](https://crates.io)
//!
//! # SYNOPSIS
//!
//! ./cratesfyi -b _package_
//!
//! # DESCRIPTION
//!
//! This script is an attempt to make a centralized documentation repository
//! for crates available in crates.io. Script is using chroot environment to
//! build documentation and fixing links on the fly.
//!
//! ## PREPARING CHROOT ENVIRONMENT
//!
//! This script is using a chroot environment to build documentation. I don't
//! think it was necessary but I didn't wanted to add bunch of stuff to my
//! stable server and a little bit more security doesn't hurt anyone.
//!
//! chroot environment must be placed in **script\_dir/chroot** directory. And
//! you must install desired version of rustc inside chroot environment. Don't
//! forget to add a regular user and create a link named **build\_home** which is
//! pointing to chroot user's home directory.  Make sure regular user is using
//! same uid with your current user. You can change username of chroot user in
//! $OPTIONS variable placed on top of this script. By default it is using
//! _onur_.
//!
//! You also need clone crates.io-index respository. You can clone repository
//! from [crates.io-index](https://github.com/rust-lang/crates.io-index).
//!
//! This script is using _sudo_ to use chroot command. chroot is only command
//! called by sudo in this script. Make sure user has rights to call chroot
//! command with sudo.
//!
//! And lastly you need to copy build.sh script into users home directory with
//! **.build.sh** name. Make sure chroot user has permissions to execute
//! **.build.sh** script.
//!
//! Directory structure should look like this:
//!
//! ```text
//! .
//! ├── cratesfyi                       # Main program
//! ├── build_home -> chroot/home/onur  # Sym link to chroot user's home
//! ├── chroot                          # chroot environment
//! │   ├── bin
//! │   ├── etc
//! │   ├── home
//! │   │   └── onur                    # chroot user's home directory
//! │   │       └── .build.sh           # Build script to run cargo doc
//! │   └── ...
//! ├── crates.io-index                 # Clone of crates.io-index
//! │   ├── 1
//! │   ├── 2
//! │   └── ...
//! ├── logs                            # Build logs will be placed here
//! │   └── ...
//! └── public_html
//!     └── crates                      # Documentations will be placed here
//! ```
//!
//!
//! # ARGS
//!
//! - **-b, --build-documentation** _crate_
//!
//!     Build documentation of a crate. If no crate name is provided, script will
//!     try to build documentation for all crates.
//!
//! - **-v, --version** _version_
//!
//!     Build documentation of a crate with given version. Otherwise script will
//!     try to build documentation for all versions. This option must be used with
//!     _-b_ argument and a crate name.
//!
//! - **-s, --skip**
//!
//!     Skip generating if documentation is exist in destination directory.
//!
//! - **--skip-tried**
//!
//!     Skips generating documentation if it's already tried before and log file is
//!     available for crate in logs directory.
//!
//! - **-k, --keep-build-directory**
//!
//!     Keep crate files in build directory after operation finishes.
//!
//! - **--destination** _path_
//!
//!     Destination path. Generated documentation directories will be moved to this
//!     directory. Default value: **script\_dir/public\_html/crates**
//!
//! - **--chroot** _path_
//!
//!     Chroot path. Default value: **script\_dir/chroot**
//!
//! - **--debug**
//!
//!     Show debug messages and place debug info in logs.
//!
//! - **-h, --help**
//!
//!     Show usage information and exit.
//!
//! # COPYRIGHT
//!
//! Copyright 2016 Onur Aslan.
//!
//! This program is free software: you can redistribute it and/or modify
//! it under the terms of the GNU General Public License as published by
//! the Free Software Foundation, either version 3 of the License, or
//! (at your option) any later version.
//!
//! This program is distributed in the hope that it will be useful,
//! but WITHOUT ANY WARRANTY; without even the implied warranty of
//! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//! GNU General Public License for more details.
//!
//! You should have received a copy of the GNU General Public License
//! along with this program.  If not, see
//! [http://www.gnu.org/licenses/](http://www.gnu.org/licenses/).

extern crate rustc_serialize;
extern crate toml;
extern crate regex;

pub mod docbuilder;

fn main() {

    let crte = docbuilder::crte::Crate::new("sdl2".to_string(),
                                            vec!["0.9.1".to_string()]);

    let mut prefix = std::env::current_dir().unwrap();
    prefix.push("../cratesfyi-prefix");

    let sex = docbuilder::DocBuilder::from_prefix(prefix);
    println!("{:#?}", sex);

    //sex.build_doc_for_every_crate();
    let res = sex.build_doc_for_crate_version(&crte, 0);
    println!("{:#?}", res);
}
<|endoftext|>


<commit_before>extern crate git2;

use git2::Repository;
use git2::BranchType;

// fn get_current_branch_name(repo: Repository) -> String {
//     let head = match repo.head() {
//         Ok(head) => head,
//         Err(e) => panic!("failed to get head: {}", e)
//     };
//     return head.name().unwrap().to_string();
// }

fn main() {
    let repo = match Repository::open(".") {
        Ok(repo) => repo,
        Err(e) => panic!("failed to open: {}", e),
    };
    // let current_branch_name = get_current_branch_name(repo);
    // println!("{:?}", current_branch_name);
    let head = match repo.head() {
        Ok(head) => head,
        Err(e) => panic!("failed to get head: {}", e)
    };
    let oid = head.target().unwrap();
    let us = match repo.find_branch("origin/master", BranchType::Remote) {
        Ok(us) => us,
        Err(e) => panic!("failed to find origin/master: {}", e)
    };
    repo.graph_ahead_behind(oid, us.get().target().unwrap());
}
<commit_msg>start structuring program<commit_after>extern crate git2;

use git2::{Repository,Branch,BranchType,Oid,Reference};

struct Program {
    repo: Repository,
}

fn get_branch_remote(reference: Reference) -> Oid {
    let b = Branch::wrap(reference);
    let upstream = match b.upstream() {
        Ok(u) => u,
        Err(e) => panic!("Failed to get upstream: {}.", e)
    };
    match upstream.get().target() {
        Some(o) => o,
        None => panic!("Failed to get oid of branch.")
    }
}

impl Program {
    fn get_head(&self) -> Reference {
        match self.repo.head() {
            Ok(head) => head,
            Err(e) => panic!("Failed to get head: {}.", e)
        }
    }

    fn get_current_branch_oid(&self) -> Oid {
        let head = self.get_head();
        match head.target() {
            Some(v) => v,
            None => panic!("Failed to get reference to head."),
        }
    }

    fn get_current_branch_name(&self) -> String {
        match self.get_head().name() {
            Some(v) => v.to_string(),
            None => panic!("Failed to get name of head."),
        }
    }

    // fn get_current_branch_remote(&self) -> String {
    //     let oid = self.get_current_branch_oid();
    //     let b = Branch::wrap(oid);
    //     let upstream = b.upstream().ok().unwrap();
    //     String::from(upstream.name().ok().unwrap().unwrap())
    // }

    fn get_current_branch_remote_oid(&self) -> Oid {
        get_branch_remote(self.get_head())
    }

    fn get_current_branch_ahead_behind(&self) -> (usize, usize)  {
        let res = self.repo.graph_ahead_behind(
            self.get_current_branch_oid(),
            self.get_current_branch_remote_oid(),
        );
        match res {
            Ok(r) => r,
            Err(e) => panic!("failed to compute ahead/behind: {}", e)
        }
    }
}

fn main() {
    let repo = match Repository::open(".") {
        Ok(repo) => repo,
        Err(e) => panic!("failed to open: {}", e),
    };
    let program = Program{ repo: repo };
    println!("{}", program.get_current_branch_name());
    let (ahead, behind) = program.get_current_branch_ahead_behind();
    println!("A: {}, B: {}", ahead, behind);
    // let current_branch_name = get_current_branch_name(repo);
    // println!("{:?}", current_branch_name);
    // let us = match repo.find_branch("origin/master", BranchType::Remote) {
    //     Ok(us) => us,
    //     Err(e) => panic!("failed to find origin/master: {}", e)
    // };
}
<|endoftext|>


<commit_before>mod app;
mod board;
mod tiles;

fn main() {
    app::hello();
    println!("Hello, 2048!");
}
<commit_msg>Adds printing functions in main<commit_after>use std::io;
// TODO: Implement them modularly
//mod app;
//mod board;
//mod tiles;

fn main() {

    // TODO: Place in IO functions
    for  i in 0..42 {
        print!("=");
    }
    print!(" 2048 Game ");
    for i in 0..42 {
        print!("=");
    }

    println!("\n");
    // end fn

    // TODO: Place in IO function
    println!("Please key in your name: ");
    let mut name = String::new();

    io::stdin().read_line(&mut name)
        .ok()
        .expect("Failed to read name");

    println!("\nWelcome, {}", name);
    // end fn

    // TODO: Place in IO function
    println!("Instruction: ");
    println!("8 to move up");
    println!("2 to move down");
    println!("4 to move left");
    println!("6 to move right");

    let mut instruction = String::new();

    io::stdin().read_line(&mut instruction)
        .ok()
        .expect("Failed to read instruction");

    println!("\nSelected {}", instruction);
    // end fn
}
<|endoftext|>


<commit_before>#![allow(unstable_features)]
#![allow(non_snake_case)]
// Since both ConfigReader and Logger are not functional yet allow dead code.
#![allow(dead_code)]
#![feature(core,old_io,old_path)]
extern crate iron;
extern crate hyper;
extern crate url;
extern crate "rustc-serialize" as serialize;
extern crate toml;
extern crate cookie;

//use std::error::Error;

use iron::prelude::*;
//use iron::AroundMiddleware;

//use controller::Reservation;

use configreader::ConfigReader;
use redstart::URLParser;
use redstart::CookieParser;
use redstart::CookieSetter;
//use redstart::CookieSetter;
//use redstart::PermCheck;
//use redstart::Logger;
use redstart::Store;
use redstart::RedStart;

mod controller;
mod model;
mod configreader;
mod redstart;

fn setup() -> iron::Chain
{
    let mut config = ConfigReader::new();
    let address = config.get_value_or::<String>("General.address", "localhost".to_string());
    let port = config.get_value_or::<String>("General.port", "3000".to_string());
    println!("RedStart starting on {}:{}", address, port);
    let sessionstore = Store::new();
    let redstart = RedStart::new(sessionstore.clone());
    let cookieparser = CookieParser::new(sessionstore.clone());
    let cookesetter = CookieSetter::new(sessionstore.clone());
	let mut chain = Chain::new(redstart);
	chain.link_before(URLParser);
	chain.link_before(cookieparser);
    chain.link_after(cookesetter);
	return chain;
}

fn main()
{
	let chain: iron::Chain = setup();
	Iron::new(chain).http("localhost:3000").unwrap();
}
<commit_msg>Well port is an i32 not a String :P<commit_after>#![allow(unstable_features)]
#![allow(non_snake_case)]
// Since both ConfigReader and Logger are not functional yet allow dead code.
#![allow(dead_code)]
#![feature(core,old_io,old_path)]
extern crate iron;
extern crate hyper;
extern crate url;
extern crate "rustc-serialize" as serialize;
extern crate toml;
extern crate cookie;

//use std::error::Error;

use iron::prelude::*;
//use iron::AroundMiddleware;

//use controller::Reservation;

use configreader::ConfigReader;
use redstart::URLParser;
use redstart::CookieParser;
use redstart::CookieSetter;
//use redstart::CookieSetter;
//use redstart::PermCheck;
//use redstart::Logger;
use redstart::Store;
use redstart::RedStart;

mod controller;
mod model;
mod configreader;
mod redstart;

fn setup() -> iron::Chain
{
    let mut config = ConfigReader::new();
    let address = config.get_value_or::<String>("General.address", "localhost".to_string());
    let port = config.get_value_or::<i32>("General.port", 3000);
    println!("RedStart starting on {}:{}", address, port);
    let sessionstore = Store::new();
    let redstart = RedStart::new(sessionstore.clone());
    let cookieparser = CookieParser::new(sessionstore.clone());
    let cookesetter = CookieSetter::new(sessionstore.clone());
	let mut chain = Chain::new(redstart);
	chain.link_before(URLParser);
	chain.link_before(cookieparser);
    chain.link_after(cookesetter);
	return chain;
}

fn main()
{
	let chain: iron::Chain = setup();
	Iron::new(chain).http("localhost:3000").unwrap();
}
<|endoftext|>


<commit_before>#[macro_use] extern crate tera;

use tera::Tera;
use tera::Context;

extern crate iron;
extern crate router;
extern crate hyper;

use iron::prelude::*;
use router::Router;
use std::collections::HashMap;
use std::sync::{Arc, Mutex};

use hyper::header::{Headers, ContentType};
use hyper::mime::{Mime, TopLevel, SubLevel};

#[derive(Default,Clone)]
struct Spaceship {
    cache: Arc<Mutex<HashMap<String, String>>>,
    tera: Arc<Mutex<Tera>>,
}

impl Spaceship {
	fn tera<'a>(&'a self) -> &'a Arc<Mutex<Tera>> {
		&self.tera
	}
}

fn index(_: &mut Request, spaceship: &Spaceship) -> IronResult<Response> {
	let mut ctx = Context::new();
	ctx.add("title", &"spaceship!");
	ctx.add("body", &"it's working");

	let obj = match spaceship.tera().lock() {
        Ok(x) => x,
        Err(_) => return Ok(Response::with((iron::status::InternalServerError)))
    };
	let content = match obj.render("index.html", ctx) {
		Ok(x) => x,
		Err(_) => return Ok(Response::with((iron::status::InternalServerError)))
	};
	let mut resp = Response::with((iron::status::Ok, content));
	resp.headers.set(ContentType(Mime(TopLevel::Text, SubLevel::Html, vec![])));
	Ok(resp)
}

fn main() {
    let spaceship = Spaceship{tera: Arc::new(Mutex::new(compile_templates!("templates/**/*"))), ..Default::default()};
    let mut router = Router::new();

    router.get("/", move |request: &mut Request| index(request, &spaceship), "magicid");

    Iron::new(router).http("localhost:8080").unwrap();
}
<commit_msg>feat/arguments: use env vars for address and port to listen on<commit_after>#[macro_use] extern crate tera;

use std::env;

use tera::Tera;
use tera::Context;

extern crate iron;
extern crate router;
extern crate hyper;

use iron::prelude::*;
use router::Router;
use std::collections::HashMap;
use std::sync::{Arc, Mutex};

use hyper::header::{Headers, ContentType};
use hyper::mime::{Mime, TopLevel, SubLevel};

#[derive(Default,Clone)]
struct Spaceship {
    cache: Arc<Mutex<HashMap<String, String>>>,
    tera: Arc<Mutex<Tera>>,
}

impl Spaceship {
	fn tera<'a>(&'a self) -> &'a Arc<Mutex<Tera>> {
		&self.tera
	}
}

fn index(_: &mut Request, spaceship: &Spaceship) -> IronResult<Response> {
	let mut ctx = Context::new();
	ctx.add("title", &"spaceship!");
	ctx.add("body", &"it's working");

	let obj = match spaceship.tera().lock() {
        Ok(x) => x,
        Err(_) => return Ok(Response::with((iron::status::InternalServerError)))
    };
	let content = match obj.render("index.html", ctx) {
		Ok(x) => x,
		Err(_) => return Ok(Response::with((iron::status::InternalServerError)))
	};
	let mut resp = Response::with((iron::status::Ok, content));
	resp.headers.set(ContentType(Mime(TopLevel::Text, SubLevel::Html, vec![])));
	Ok(resp)
}

fn main() {

	let address = match env::var("SPACESHIP_ADDRESS") {
		Ok(x) => x,
		Err(_) => String::from("127.0.0.1"),
	};
	let port = match env::var("SPACESHIP_PORT") {
		Ok(x) => x,
		Err(_) => String::from("8080"),
	};

    let spaceship = Spaceship{tera: Arc::new(Mutex::new(compile_templates!("templates/**/*"))), ..Default::default()};
    let mut router = Router::new();

    router.get("/", move |request: &mut Request| index(request, &spaceship), "magicid");

    Iron::new(router).http(format!("{}:{}",address,port)).unwrap();
}
<|endoftext|>


<commit_before>//! Doc placeholder

extern crate opencl;
extern crate sdl2;

use sdl2::keyboard::Keycode;
use sdl2::pixels::{Color, self};

const KERNEL_SOURCE: &'static str = r"
__kernel void multiply_by_scalar(__global float const* const src_buf,
                                 __private float const coeff,
                                 __global float* dst_buf) {
    uint i = get_global_id(0);
    dst_buf[i] = src_buf[i] * coeff;
}
";

fn main() {
    // Initial kernel stuff
    {
        let (device, ctx, queue) = opencl::util::create_compute_context().expect("Could not initialise OpenCL");
        const COEFF: f32 = 5.4321;

        let vec_src = vec![1.0f32, 2.0, 3.0, 4.0, 5.0];

        let cl_src_buf = ctx.create_buffer::<f32>(vec_src.len(), opencl::cl::CL_MEM_READ_ONLY);
        let cl_dst_buf = ctx.create_buffer::<f32>(vec_src.len(), opencl::cl::CL_MEM_WRITE_ONLY);

        queue.write(&cl_src_buf, &&vec_src[..], ());

        let program = {
            let p = ctx.create_program_from_source(KERNEL_SOURCE);
            p.build(&device).expect("Could not build program");
            p
        };

        let kernel = program.create_kernel("multiply_by_scalar");
        kernel.set_arg(0, &cl_src_buf);
        kernel.set_arg(1, &COEFF);
        kernel.set_arg(2, &cl_dst_buf);

        let event = queue.enqueue_async_kernel(&kernel, vec_src.len(), None, ());

        let vec_dst: Vec<f32> = queue.get(&cl_dst_buf, &event);

        println!("  {:?}", &vec_src[..]);
        println!("* {:?}", COEFF);
        println!("= {:?}", &vec_dst[..]);
    }

    let sdl = sdl2::init().expect("Could not intialise SDL library");
    let mut renderer = sdl.video()
                          .expect("Could not initialise video")
                          .window("mandlebrot", 800, 600)
                          .position_centered()
                          .build()
                          .expect("Could not create a window from the video subsystem")
                          .renderer()
                          .accelerated()
                          .present_vsync()
                          .target_texture()
                          .build()
                          .expect("Could not get renderer from window");

    let mut events = sdl.event_pump().expect("Could not initialise events");
    'mainloop: loop {
        for e in events.poll_iter() {
            use sdl2::event::Event;
            match e {
                Event::Quit {..} | Event::KeyDown {keycode: Some(Keycode::Escape), ..} => break 'mainloop,
                _ => { }
            }
        }

        renderer.set_draw_color(Color::RGB(255, 0, 0));
        renderer.clear();

        let info = renderer.info();
        let (mx, my) = (info.max_texture_width, info.max_texture_height);
        let _ = renderer.create_texture_streaming(pixels::PixelFormatEnum::RGB888, (mx, my))
                        .and_then(|mut tex| {
                            tex.with_lock(None, |pixels, _pitch| {
                                for pixel in pixels {
                                    *pixel = 0xFF;
                                }
                            }).expect("Could not write pixels to screen texture");
                            Ok(tex)
                        })
                        .and_then(|tex| Ok(renderer.copy(&tex, None, None)))
                        .expect("Could not create texture from renderer");

        renderer.present();
    }
}
<commit_msg>Reset author<commit_after>//! Doc placeholder

extern crate opencl;
extern crate sdl2;

use sdl2::keyboard::Keycode;
use sdl2::pixels::{self, Color};
use sdl2::rect::Rect;

const KERNEL_SOURCE: &'static str = r"
__kernel void multiply_by_scalar(__global float const* const src_buf,
                                 __private float const coeff,
                                 __global float* dst_buf) {
    uint i = get_global_id(0);
    dst_buf[i] = src_buf[i] * coeff;
}
";

fn init_kernel() {
    let (device, ctx, queue) = opencl::util::create_compute_context()
                                   .expect("Could not initialise OpenCL");
    const COEFF: f32 = 5.4321;

    let vec_src = vec![1.0f32, 2.0, 3.0, 4.0, 5.0];

    let cl_src_buf = ctx.create_buffer::<f32>(vec_src.len(), opencl::cl::CL_MEM_READ_ONLY);
    let cl_dst_buf = ctx.create_buffer::<f32>(vec_src.len(), opencl::cl::CL_MEM_WRITE_ONLY);

    queue.write(&cl_src_buf, &&vec_src[..], ());

    let program = {
        let p = ctx.create_program_from_source(KERNEL_SOURCE);
        p.build(&device).expect("Could not build program");
        p
    };

    let kernel = program.create_kernel("multiply_by_scalar");
    kernel.set_arg(0, &cl_src_buf);
    kernel.set_arg(1, &COEFF);
    kernel.set_arg(2, &cl_dst_buf);

    let event = queue.enqueue_async_kernel(&kernel, vec_src.len(), None, ());

    let vec_dst: Vec<f32> = queue.get(&cl_dst_buf, &event);

    println!("  {:?}", &vec_src[..]);
    println!("* {:?}", COEFF);
    println!("= {:?}", &vec_dst[..]);
}

fn main() {
    init_kernel();

    let sdl = sdl2::init().expect("Could not intialise SDL library");
    let mut renderer = sdl.video()
                          .expect("Could not initialise video")
                          .window("mandlebrot", 800, 600)
                          .position_centered()
                          .build()
                          .expect("Could not create a window from the video subsystem")
                          .renderer()
                          .accelerated()
                          .present_vsync()
                          .target_texture()
                          .build()
                          .expect("Could not get renderer from window");

    renderer.set_draw_color(Color::RGB(255, 0, 0));

    let sz = renderer.window().map(|w| w.size()).unwrap_or((0, 0));
    let mut tex = renderer.create_texture_streaming(pixels::PixelFormatEnum::RGB888, sz).unwrap();

    let mut events = sdl.event_pump().expect("Could not initialise events");

    'mainloop: loop {
        for e in events.poll_iter() {
            use sdl2::event::Event;
            match e {
                Event::Quit {..} |
                Event::KeyDown {keycode: Some(Keycode::Escape), ..} => break 'mainloop,
                _ => {}
            }
        }
        renderer.clear();

        tex.with_lock(None, |pixels, pitch| {
               let (mut row, mut col) = (1, 1);
               for pixel in pixels {
                   if col >= pitch {
                       row += 1;
                       col = 1;
                   } else {
                       col += 1;
                   }
                   *pixel = 0x00 + col as u8;
               }
           })
           .expect("Could not write pixels to screen texture");

        renderer.copy(&tex, None, Some(Rect::new_unwrap(0, 0, 800, 600)));

        renderer.present();
    }
}
<|endoftext|>


<commit_before>use std::f32::{NEG_INFINITY, INFINITY};
use std::cmp::Ordering;
use std::collections::HashMap;
use std::sync::{Arc, Mutex};
use std::sync::mpsc;
use std::thread;
use std::time::Duration;

use time;

use identity::{Team, JobDescription, Agent};
use life::{Commit, WorldState};
use landmark::{CENTER_OF_THE_WORLD, LOW_COLONELCY,
               LOW_SEVENTH_HEAVEN, HIGH_COLONELCY, HIGH_SEVENTH_HEAVEN};
use space::Pinfield;

pub fn orientation(team: Team) -> f32 {
    match team {
        Team::Orange => 1.0,
        Team::Blue => -1.0,
    }
}

pub fn figurine_valuation(agent: Agent) -> f32 {
    let value = match agent.job_description {
        // en.wikipedia.org/wiki/
        // Chess_piece_relative_value#Hans_Berliner.27s_system
        JobDescription::Servant => 1.0,
        JobDescription::Pony => 3.2,
        JobDescription::Scholar => 3.3,
        JobDescription::Cop => 5.1,
        JobDescription::Princess => 8.8,
        JobDescription::Figurehead => 20000.0,
    };
    orientation(agent.team) * value
}

pub fn score(world: WorldState) -> f32 {
    let mut valuation = 0.0;

    for team in Team::league().into_iter() {
        for agent in Agent::dramatis_personæ(team).into_iter() {
            valuation += world.agent_to_pinfield_ref(
                agent).pincount() as f32 * figurine_valuation(agent);
        }
        // breadth of scholarship bonus
        if world.agent_to_pinfield_ref(Agent {
                    team: team,
                    job_description: JobDescription::Scholar,
                })
                .to_locales()
                .len() >= 2 {
            valuation += orientation(team) * 0.5
        }
    }

    // ponies and servants want to be in the center of the world's action
    let center = Pinfield(CENTER_OF_THE_WORLD);
    // cast to signed to avoid overflow
    let orange_centerism: i8 = world.orange_servants.union(
        world.orange_ponies).intersection(center).pincount() as i8;
    let blue_centerism: i8 = world.blue_servants.union(
        world.blue_ponies).intersection(center).pincount() as i8;
    valuation += 0.1 * (orange_centerism - blue_centerism) as f32;

    // a cop's favorite beat is the seventh rank
    let high_seventh = Pinfield(HIGH_SEVENTH_HEAVEN);
    let orange_beat = world.orange_cops.intersection(high_seventh).pincount();
    valuation += 0.5 * orange_beat as f32;
    let low_seventh = Pinfield(LOW_SEVENTH_HEAVEN);
    let blue_beat = world.blue_cops.intersection(low_seventh).pincount();
    valuation -= 0.5 * blue_beat as f32;

    // servants should aspire to something more in life someday
    let orange_subascendants = world.orange_servants.intersection(high_seventh)
        .pincount();
    valuation += 0.5 * orange_subascendants as f32;
    let high_colonelcy = Pinfield(HIGH_COLONELCY);
    let orange_subsubascendants = world.orange_servants.intersection(
        high_colonelcy).pincount();
    valuation += 0.2 * orange_subsubascendants as f32;
    let blue_subascendants = world.blue_servants.intersection(low_seventh)
        .pincount();
    valuation -= 0.5 * blue_subascendants as f32;
    let low_colonelcy = Pinfield(LOW_COLONELCY);
    let blue_subsubascendants = world.blue_servants.intersection(
        low_colonelcy).pincount();
    valuation -= 0.2 * blue_subsubascendants as f32;

    valuation
}

fn mmv_lva_heuristic(commit: &Commit) -> f32 {
    // https://chessprogramming.wikispaces.com/MVV-LVA
    match commit.hospitalization {
        Some(patient) => (
            figurine_valuation(patient) - figurine_valuation(commit.patch.star)),
        None => 0.0,
    }
}

fn order_moves(commits: &mut Vec<Commit>) {
    commits.sort_by(|a, b| {
        mmv_lva_heuristic(&b)
            .partial_cmp(&mmv_lva_heuristic(&a))
            .unwrap_or(Ordering::Equal)
    });
}

pub fn α_β_negamax_search(
    world: WorldState, depth: u8, mut α: f32, β: f32,
    memory_bank: Arc<Mutex<HashMap<WorldState, f32>>>) -> (Option<Commit>, f32) {
    let team = world.initiative;
    let potential_score = orientation(team) * score(world);
    let mut premonitions = world.reckless_lookahead();
    order_moves(&mut premonitions);
    if depth == 0 || premonitions.is_empty() {
        return (None, potential_score)
    };
    let mut optimum = NEG_INFINITY;
    let mut optimand = None;
    for premonition in premonitions.into_iter() {
        let mut value = NEG_INFINITY;  // can't hurt to be pessimistic
        let cached: bool;
        {
            let open_vault = memory_bank.lock().unwrap();
            let cached_value_maybe = open_vault.get(&premonition.tree);
            match cached_value_maybe {
                Some(&cached_value) => {
                    cached = true;
                    value = cached_value;
                }
                None => { cached = false; }
            };
        }

        if !cached {
            let (_, acquired_value) = α_β_negamax_search(
                premonition.tree, depth - 1,
                -β, -α, memory_bank.clone()
            );
            value = -acquired_value;
            memory_bank.lock().unwrap().insert(premonition.tree, value);
        }

        if value > optimum {
            optimum = value;
            optimand = Some(premonition);
        }
        if value > α {
            α = value;
        }
        if α >= β {
            break;
        }
    }

    (optimand, optimum)
}

#[allow(type_complexity)]
pub fn potentially_timebound_kickoff(world: &WorldState, depth: u8,
                                     nihilistically: bool,
                                     deadline_maybe: Option<time::Timespec>)
                                     -> Option<Vec<(Commit, f32)>> {
    let déjà_vu_table: HashMap<WorldState, f32> = HashMap::new();
    let memory_bank = Arc::new(Mutex::new(déjà_vu_table));
    let mut premonitions;
    if nihilistically {
        premonitions = world.reckless_lookahead();
    } else {
        premonitions = world.lookahead();
    }
    order_moves(&mut premonitions);
    let mut forecasts = Vec::new();
    let mut time_radios: Vec<(Commit, mpsc::Receiver<(Option<Commit>, f32)>)> =
        Vec::new();
    for &premonition in &premonitions {
        let travel_bank = memory_bank.clone();
        let (tx, rx) = mpsc::channel();
        let explorer_radio = tx.clone();
        time_radios.push((premonition, rx));
        thread::spawn(move || {
            let search_hit: (Option<Commit>, f32) = α_β_negamax_search(
                premonition.tree, depth - 1,
                NEG_INFINITY, INFINITY,
                travel_bank
            );
            explorer_radio.send(search_hit).ok();
        });
    }
    while !time_radios.is_empty() {  // polling for results
        if let Some(deadline) = deadline_maybe {
            if time::get_time() > deadline {
                return None;
            }
        }
        // iterate over indices so that we can use swap_remove during the loop
        for i in (0..time_radios.len()).rev() {
            let premonition = time_radios[i].0;
            if let Some(search_hit) = time_radios[i].1.try_recv().ok() {
                let (_grandchild, mut value) = search_hit;
                value = -value;
                forecasts.push((premonition, value));
                time_radios.swap_remove(i);
            }
        }
        thread::sleep(Duration::from_millis(2));
    }
    forecasts.sort_by(|a, b| b.1.partial_cmp(&a.1).unwrap_or(Ordering::Equal));
    Some(forecasts)
}

pub fn kickoff(world: &WorldState, depth: u8,
               nihilistically: bool) -> Vec<(Commit, f32)> {
    potentially_timebound_kickoff(world, depth, nihilistically, None).unwrap()
}

pub fn iterative_deepening_kickoff(world: &WorldState, timeout: time::Duration,
                                   nihilistically: bool)
                                   -> (Vec<(Commit, f32)>, u8) {
    let deadline = time::get_time() + timeout;
    let mut depth = 1;
    let mut forecasts = potentially_timebound_kickoff(
        world, depth, nihilistically, None).unwrap();
    while let Some(prophecy) = potentially_timebound_kickoff(
            world, depth, nihilistically, Some(deadline)) {
        forecasts = prophecy;
        depth += 1;
    }
    (forecasts, depth-1)
}

#[cfg(test)]
mod tests {
    extern crate test;
    use self::test::Bencher;

    use time;
    use super::{kickoff, score};
    use space::Locale;
    use life::WorldState;
    use identity::Team;

    impl WorldState {
        fn no_castling_at_all(&mut self) {
            self.orange_east_service_eligibility = false;
            self.orange_west_service_eligibility = false;
            self.blue_east_service_eligibility = false;
            self.blue_west_service_eligibility = false;
        }
    }

    #[bench]
    fn benchmark_scoring(b: &mut Bencher) {
        b.iter(|| score(WorldState::new()));
    }

    #[bench]
    fn benchmark_kickoff_depth_1(b: &mut Bencher) {
        let ws = WorldState::new();
        b.iter(|| kickoff(&ws, 1, true));
    }

    #[bench]
    fn benchmark_kickoff_depth_2_arbys(b: &mut Bencher) {
        let ws = WorldState::new();
        b.iter(|| kickoff(&ws, 2, true));
    }

    #[bench]
    fn benchmark_kickoff_depth_2_carefully(b: &mut Bencher) {
        let ws = WorldState::new();
        b.iter(|| kickoff(&ws, 2, false));
    }

    #[bench]
    fn benchmark_kickoff_depth_3(b: &mut Bencher) {
        let ws = WorldState::new();
        b.iter(|| kickoff(&ws, 3, true));
    }

    #[test]
    #[ignore]  // more research is needed
    fn concerning_short_circuiting_upon_finding_critical_endangerment() {
        let ws = WorldState::reconstruct("7K/r7/1r6/8/8/8/8/7k b -".to_owned());
        let start = time::get_time();
        kickoff(&ws, 30, true);
        let duration = time::get_time() - start;
        assert!(duration.num_seconds() < 20);
    }

    #[test]
    #[allow(float_cmp)]
    fn concerning_fairness_of_the_initial_position() {
        // It's okay to assume this is really 0.0. Floats may be imprecise,
        // but they do have well-defined behavior.
        assert_eq!(0.0, score(WorldState::new()));
    }

    #[test]
    fn concerning_servant_ascension_choices() {
        let ws = WorldState::reconstruct("8/q1P1k/8/8/8/8/6PP/7K w -".to_owned());
        // looking ahead 3 moves allows the Leafline AI to catch the
        // split, whereby transforming into a pony (rather than
        // transitioning into a princess, as would usually be
        // expected) endangers both the blue princess and figurehead
        let (ref best_move, score) = kickoff(&ws, 3, true)[0];
        println!("{:?}", best_move);
        assert!(score > 0.0);
        assert_eq!(best_move.tree.preserve(), "2N5/q3k3/8/8/8/8/6PP/7K b -");
    }

    #[test]
    fn experimentally_about_kickoff() {
        let mut world = WorldState::new_except_empty();
        // SCENARIO: let's imagine Orange (to move) has separate attacks against
        // Blue's pony and servant, against which Blue has no defense but
        // to run away. We predict that Orange will take the pony, and
        // then Blue will move the servant out of the way.

        // scholar endangers pony
        world.blue_ponies = world.blue_ponies.alight(
            Locale { rank: 0, file: 0 });
        world.orange_scholars = world.orange_scholars.alight(
            Locale { rank: 2, file: 2 });

        // pony endangers servant
        world.blue_servants = world.blue_servants.alight(
            Locale { rank: 7, file: 1 });
        world.orange_ponies = world.orange_ponies.alight(
            Locale { rank: 5, file: 2 });

        // Blue has another servant sitting nowhere interesting
        world.blue_servants = world.blue_servants.alight(
            Locale { rank: 3, file: 6 });
        world.no_castling_at_all();

        let depth = 2;
        let advisory = kickoff(&world, depth, true);

        // taking the pony is the right thing to do
        assert_eq!(Locale { rank: 0, file: 0 }, advisory[0].0.patch.whither);

        // And, furthermore, the answer should be the same if we face the
        // same situation with the colors reversed
        //
        // XXX this would be tidier and less copy-pastey if I had more
        // general figurine-placing functions that were three rather than
        // two levels of abstraction above twiddling bits on an unsigned
        // int ... oh, well
        let mut negaworld = WorldState::new_except_empty();
        negaworld.initiative = Team::Blue;

        // scholar endangers pony
        negaworld.orange_ponies = negaworld.orange_ponies.alight(
            Locale { rank: 0, file: 0 });
        negaworld.blue_scholars = negaworld.blue_scholars.alight(
            Locale { rank: 2, file: 2 });

        // pony endangers servant
        negaworld.orange_servants = negaworld.orange_servants.alight(
            Locale { rank: 7, file: 1 });
        negaworld.blue_ponies = negaworld.blue_ponies.alight(
            Locale { rank: 5, file: 2 });

        // Orange has another servant sitting nowhere interesting
        negaworld.orange_servants = negaworld.orange_servants.alight(
            Locale { rank: 3, file: 6 });
        negaworld.initiative = Team::Blue;

        negaworld.no_castling_at_all();

        let negadvisory = kickoff(&negaworld, depth, true);

        // taking the pony is still the right thing to do, even in the
        // negaworld
        assert_eq!(Locale { rank: 0, file: 0 },
                   negadvisory[0].0.patch.whither);
    }

}
<commit_msg>recognize option value of secret service eligibility<commit_after>use std::f32::{NEG_INFINITY, INFINITY};
use std::cmp::Ordering;
use std::collections::HashMap;
use std::sync::{Arc, Mutex};
use std::sync::mpsc;
use std::thread;
use std::time::Duration;

use time;

use identity::{Team, JobDescription, Agent};
use life::{Commit, WorldState};
use landmark::{CENTER_OF_THE_WORLD, LOW_COLONELCY,
               LOW_SEVENTH_HEAVEN, HIGH_COLONELCY, HIGH_SEVENTH_HEAVEN};
use space::Pinfield;

pub fn orientation(team: Team) -> f32 {
    match team {
        Team::Orange => 1.0,
        Team::Blue => -1.0,
    }
}

pub fn figurine_valuation(agent: Agent) -> f32 {
    let value = match agent.job_description {
        // en.wikipedia.org/wiki/
        // Chess_piece_relative_value#Hans_Berliner.27s_system
        JobDescription::Servant => 1.0,
        JobDescription::Pony => 3.2,
        JobDescription::Scholar => 3.3,
        JobDescription::Cop => 5.1,
        JobDescription::Princess => 8.8,
        JobDescription::Figurehead => 20000.0,
    };
    orientation(agent.team) * value
}

pub fn score(world: WorldState) -> f32 {
    let mut valuation = 0.0;

    for team in Team::league().into_iter() {
        for agent in Agent::dramatis_personæ(team).into_iter() {
            valuation += world.agent_to_pinfield_ref(
                agent).pincount() as f32 * figurine_valuation(agent);
        }
        // breadth of scholarship bonus
        if world.agent_to_pinfield_ref(Agent {
                    team: team,
                    job_description: JobDescription::Scholar,
                })
                .to_locales()
                .len() >= 2 {
            valuation += orientation(team) * 0.5
        }
    }

    // ponies and servants want to be in the center of the world's action
    let center = Pinfield(CENTER_OF_THE_WORLD);
    // cast to signed to avoid overflow
    let orange_centerism: i8 = world.orange_servants.union(
        world.orange_ponies).intersection(center).pincount() as i8;
    let blue_centerism: i8 = world.blue_servants.union(
        world.blue_ponies).intersection(center).pincount() as i8;
    valuation += 0.1 * (orange_centerism - blue_centerism) as f32;

    // a cop's favorite beat is the seventh rank
    let high_seventh = Pinfield(HIGH_SEVENTH_HEAVEN);
    let orange_beat = world.orange_cops.intersection(high_seventh).pincount();
    valuation += 0.5 * orange_beat as f32;
    let low_seventh = Pinfield(LOW_SEVENTH_HEAVEN);
    let blue_beat = world.blue_cops.intersection(low_seventh).pincount();
    valuation -= 0.5 * blue_beat as f32;

    // servants should aspire to something more in life someday
    let orange_subascendants = world.orange_servants.intersection(high_seventh)
        .pincount();
    valuation += 0.5 * orange_subascendants as f32;
    let high_colonelcy = Pinfield(HIGH_COLONELCY);
    let orange_subsubascendants = world.orange_servants.intersection(
        high_colonelcy).pincount();
    valuation += 0.2 * orange_subsubascendants as f32;
    let blue_subascendants = world.blue_servants.intersection(low_seventh)
        .pincount();
    valuation -= 0.5 * blue_subascendants as f32;
    let low_colonelcy = Pinfield(LOW_COLONELCY);
    let blue_subsubascendants = world.blue_servants.intersection(
        low_colonelcy).pincount();
    valuation -= 0.2 * blue_subsubascendants as f32;

    // secret service eligbility has option value
    if world.orange_west_service_eligibility ||
        world.orange_east_service_eligibility {
            valuation += 0.1
    }
    if world.blue_west_service_eligibility ||
        world.blue_east_service_eligibility {
            valuation -= 0.1
    }

    valuation
}

fn mmv_lva_heuristic(commit: &Commit) -> f32 {
    // https://chessprogramming.wikispaces.com/MVV-LVA
    match commit.hospitalization {
        Some(patient) => (
            figurine_valuation(patient) - figurine_valuation(commit.patch.star)),
        None => 0.0,
    }
}

fn order_moves(commits: &mut Vec<Commit>) {
    commits.sort_by(|a, b| {
        mmv_lva_heuristic(&b)
            .partial_cmp(&mmv_lva_heuristic(&a))
            .unwrap_or(Ordering::Equal)
    });
}

pub fn α_β_negamax_search(
    world: WorldState, depth: u8, mut α: f32, β: f32,
    memory_bank: Arc<Mutex<HashMap<WorldState, f32>>>) -> (Option<Commit>, f32) {
    let team = world.initiative;
    let potential_score = orientation(team) * score(world);
    let mut premonitions = world.reckless_lookahead();
    order_moves(&mut premonitions);
    if depth == 0 || premonitions.is_empty() {
        return (None, potential_score)
    };
    let mut optimum = NEG_INFINITY;
    let mut optimand = None;
    for premonition in premonitions.into_iter() {
        let mut value = NEG_INFINITY;  // can't hurt to be pessimistic
        let cached: bool;
        {
            let open_vault = memory_bank.lock().unwrap();
            let cached_value_maybe = open_vault.get(&premonition.tree);
            match cached_value_maybe {
                Some(&cached_value) => {
                    cached = true;
                    value = cached_value;
                }
                None => { cached = false; }
            };
        }

        if !cached {
            let (_, acquired_value) = α_β_negamax_search(
                premonition.tree, depth - 1,
                -β, -α, memory_bank.clone()
            );
            value = -acquired_value;
            memory_bank.lock().unwrap().insert(premonition.tree, value);
        }

        if value > optimum {
            optimum = value;
            optimand = Some(premonition);
        }
        if value > α {
            α = value;
        }
        if α >= β {
            break;
        }
    }

    (optimand, optimum)
}

#[allow(type_complexity)]
pub fn potentially_timebound_kickoff(world: &WorldState, depth: u8,
                                     nihilistically: bool,
                                     deadline_maybe: Option<time::Timespec>)
                                     -> Option<Vec<(Commit, f32)>> {
    let déjà_vu_table: HashMap<WorldState, f32> = HashMap::new();
    let memory_bank = Arc::new(Mutex::new(déjà_vu_table));
    let mut premonitions;
    if nihilistically {
        premonitions = world.reckless_lookahead();
    } else {
        premonitions = world.lookahead();
    }
    order_moves(&mut premonitions);
    let mut forecasts = Vec::new();
    let mut time_radios: Vec<(Commit, mpsc::Receiver<(Option<Commit>, f32)>)> =
        Vec::new();
    for &premonition in &premonitions {
        let travel_bank = memory_bank.clone();
        let (tx, rx) = mpsc::channel();
        let explorer_radio = tx.clone();
        time_radios.push((premonition, rx));
        thread::spawn(move || {
            let search_hit: (Option<Commit>, f32) = α_β_negamax_search(
                premonition.tree, depth - 1,
                NEG_INFINITY, INFINITY,
                travel_bank
            );
            explorer_radio.send(search_hit).ok();
        });
    }
    while !time_radios.is_empty() {  // polling for results
        if let Some(deadline) = deadline_maybe {
            if time::get_time() > deadline {
                return None;
            }
        }
        // iterate over indices so that we can use swap_remove during the loop
        for i in (0..time_radios.len()).rev() {
            let premonition = time_radios[i].0;
            if let Some(search_hit) = time_radios[i].1.try_recv().ok() {
                let (_grandchild, mut value) = search_hit;
                value = -value;
                forecasts.push((premonition, value));
                time_radios.swap_remove(i);
            }
        }
        thread::sleep(Duration::from_millis(2));
    }
    forecasts.sort_by(|a, b| b.1.partial_cmp(&a.1).unwrap_or(Ordering::Equal));
    Some(forecasts)
}

pub fn kickoff(world: &WorldState, depth: u8,
               nihilistically: bool) -> Vec<(Commit, f32)> {
    potentially_timebound_kickoff(world, depth, nihilistically, None).unwrap()
}

pub fn iterative_deepening_kickoff(world: &WorldState, timeout: time::Duration,
                                   nihilistically: bool)
                                   -> (Vec<(Commit, f32)>, u8) {
    let deadline = time::get_time() + timeout;
    let mut depth = 1;
    let mut forecasts = potentially_timebound_kickoff(
        world, depth, nihilistically, None).unwrap();
    while let Some(prophecy) = potentially_timebound_kickoff(
            world, depth, nihilistically, Some(deadline)) {
        forecasts = prophecy;
        depth += 1;
    }
    (forecasts, depth-1)
}

#[cfg(test)]
mod tests {
    extern crate test;
    use self::test::Bencher;

    use time;
    use super::{kickoff, score};
    use space::Locale;
    use life::WorldState;
    use identity::Team;

    impl WorldState {
        fn no_castling_at_all(&mut self) {
            self.orange_east_service_eligibility = false;
            self.orange_west_service_eligibility = false;
            self.blue_east_service_eligibility = false;
            self.blue_west_service_eligibility = false;
        }
    }

    #[bench]
    fn benchmark_scoring(b: &mut Bencher) {
        b.iter(|| score(WorldState::new()));
    }

    #[bench]
    fn benchmark_kickoff_depth_1(b: &mut Bencher) {
        let ws = WorldState::new();
        b.iter(|| kickoff(&ws, 1, true));
    }

    #[bench]
    fn benchmark_kickoff_depth_2_arbys(b: &mut Bencher) {
        let ws = WorldState::new();
        b.iter(|| kickoff(&ws, 2, true));
    }

    #[bench]
    fn benchmark_kickoff_depth_2_carefully(b: &mut Bencher) {
        let ws = WorldState::new();
        b.iter(|| kickoff(&ws, 2, false));
    }

    #[bench]
    fn benchmark_kickoff_depth_3(b: &mut Bencher) {
        let ws = WorldState::new();
        b.iter(|| kickoff(&ws, 3, true));
    }

    #[test]
    #[ignore]  // more research is needed
    fn concerning_short_circuiting_upon_finding_critical_endangerment() {
        let ws = WorldState::reconstruct("7K/r7/1r6/8/8/8/8/7k b -".to_owned());
        let start = time::get_time();
        kickoff(&ws, 30, true);
        let duration = time::get_time() - start;
        assert!(duration.num_seconds() < 20);
    }

    #[test]
    #[allow(float_cmp)]
    fn concerning_fairness_of_the_initial_position() {
        // It's okay to assume this is really 0.0. Floats may be imprecise,
        // but they do have well-defined behavior.
        assert_eq!(0.0, score(WorldState::new()));
    }

    #[test]
    fn concerning_servant_ascension_choices() {
        let ws = WorldState::reconstruct("8/q1P1k/8/8/8/8/6PP/7K w -".to_owned());
        // looking ahead 3 moves allows the Leafline AI to catch the
        // split, whereby transforming into a pony (rather than
        // transitioning into a princess, as would usually be
        // expected) endangers both the blue princess and figurehead
        let (ref best_move, score) = kickoff(&ws, 3, true)[0];
        println!("{:?}", best_move);
        assert!(score > 0.0);
        assert_eq!(best_move.tree.preserve(), "2N5/q3k3/8/8/8/8/6PP/7K b -");
    }

    #[test]
    fn experimentally_about_kickoff() {
        let mut world = WorldState::new_except_empty();
        // SCENARIO: let's imagine Orange (to move) has separate attacks against
        // Blue's pony and servant, against which Blue has no defense but
        // to run away. We predict that Orange will take the pony, and
        // then Blue will move the servant out of the way.

        // scholar endangers pony
        world.blue_ponies = world.blue_ponies.alight(
            Locale { rank: 0, file: 0 });
        world.orange_scholars = world.orange_scholars.alight(
            Locale { rank: 2, file: 2 });

        // pony endangers servant
        world.blue_servants = world.blue_servants.alight(
            Locale { rank: 7, file: 1 });
        world.orange_ponies = world.orange_ponies.alight(
            Locale { rank: 5, file: 2 });

        // Blue has another servant sitting nowhere interesting
        world.blue_servants = world.blue_servants.alight(
            Locale { rank: 3, file: 6 });
        world.no_castling_at_all();

        let depth = 2;
        let advisory = kickoff(&world, depth, true);

        // taking the pony is the right thing to do
        assert_eq!(Locale { rank: 0, file: 0 }, advisory[0].0.patch.whither);

        // And, furthermore, the answer should be the same if we face the
        // same situation with the colors reversed
        //
        // XXX this would be tidier and less copy-pastey if I had more
        // general figurine-placing functions that were three rather than
        // two levels of abstraction above twiddling bits on an unsigned
        // int ... oh, well
        let mut negaworld = WorldState::new_except_empty();
        negaworld.initiative = Team::Blue;

        // scholar endangers pony
        negaworld.orange_ponies = negaworld.orange_ponies.alight(
            Locale { rank: 0, file: 0 });
        negaworld.blue_scholars = negaworld.blue_scholars.alight(
            Locale { rank: 2, file: 2 });

        // pony endangers servant
        negaworld.orange_servants = negaworld.orange_servants.alight(
            Locale { rank: 7, file: 1 });
        negaworld.blue_ponies = negaworld.blue_ponies.alight(
            Locale { rank: 5, file: 2 });

        // Orange has another servant sitting nowhere interesting
        negaworld.orange_servants = negaworld.orange_servants.alight(
            Locale { rank: 3, file: 6 });
        negaworld.initiative = Team::Blue;

        negaworld.no_castling_at_all();

        let negadvisory = kickoff(&negaworld, depth, true);

        // taking the pony is still the right thing to do, even in the
        // negaworld
        assert_eq!(Locale { rank: 0, file: 0 },
                   negadvisory[0].0.patch.whither);
    }

}
<|endoftext|>


<commit_before>use std::f32::NEG_INFINITY;
use std::cmp::Ordering;

use identity::{Team, JobDescription, Agent};
use life::{Commit, WorldState};

pub fn orientation(team: Team) -> f32 {
    match team {
        Team::Orange => 1.0,
        Team::Blue => -1.0
    }
}

pub fn figurine_valuation(agent: Agent) -> f32 {
    let Agent { team: team, job_description: job_description } = agent;
    let value = match job_description {
        // en.wikipedia.org/wiki/
        // Chess_piece_relative_value#Hans_Berliner.27s_system
        JobDescription::Servant => 1.0,
        JobDescription::Pony => 3.2,
        JobDescription::Scholar => 3.3,
        JobDescription::Cop => 5.1,
        JobDescription::Princess => 8.8,
        JobDescription::Figurehead => 20000.0
    };
    orientation(team) * value
}

pub fn score(world: WorldState) -> f32 {
    let mut valuation = 0.0;
    for team in Team::league().into_iter() {
        for agent in Agent::dramatis_personae(team).into_iter() {
            valuation += world.agent_to_pinfield_ref(
                agent).pincount() as f32 * figurine_valuation(agent);
        }
    }
    valuation
}

pub fn negamax_search(world: WorldState, depth: u8) -> (Option<Commit>, f32) {
    let team = world.to_move;
    let premonitions = world.lookahead();
    if depth == 0 || premonitions.is_empty() {
        return (None, orientation(team) * score(world))
    }
    let mut optimum = NEG_INFINITY;
    let mut optimand = None;
    for premonition in premonitions.into_iter() {
        let (_after, mut value) = negamax_search(premonition.tree, depth-1);
        value = -value;
        if value > optimum {
            optimum = value;
            optimand = Some(premonition);
        }
    }
    (optimand, optimum)
}

// The vision here is that for the turn I'm immediately going to take,
// I want a report of all possible moves ranked by negamax-computed
// optimality, but that we don't want to bother with all that bookkeeping
// for subsequent levels of the game tree; minimax is expensive enough
// already!!
pub fn negamax_kickoff(world: WorldState, depth: u8) -> Vec<(Commit, f32)> {
    let team = world.to_move;
    let premonitions = world.lookahead();
    let mut forecasts = Vec::new();
    for premonition in premonitions.into_iter() {
        let (_grandchild, score) = negamax_search(premonition.tree, depth-1);
        forecasts.push((premonition, score));
    }
    forecasts.sort_by(|a, b| b.1.partial_cmp(&a.1).unwrap_or(Ordering::Equal));
    forecasts
}

#[cfg(test)]
mod test {
    use time;

    use super::{negamax_search, negamax_kickoff, score};
    use space::Locale;
    use life::WorldState;

    #[test]
    fn concerning_fairness_of_the_initial_position() {
        assert_eq!(0.0, score(WorldState::new()));
    }

    #[test]
    #[ignore]
    fn concerning_negamax_implementation_suitability() {
        for depth in 1..5 {
            let start = time::get_time();
            negamax_search(WorldState::new(), depth);
            let end = time::get_time();
            println!("searching the initial position to depth {} took {:?}",
                     depth, end-start);
        }
    }

    #[test]
    fn experimentally_about_negamax_kickoff_in_faceoff_while_masters_away() {
        let mut world = WorldState::new_except_empty();
        let orange_files = [1u8, 2, 3];
        let blue_files = [2u8, 3, 4];
        for &file in orange_files.iter() {
            world.orange_servants = world.orange_servants.alight(
                Locale { rank: 3, file: file }
            );
        }
        for &file in blue_files.iter() {
            world.blue_servants = world.blue_servants.alight(
                Locale { rank: 4, file: file }
            );
        }
        println!("negamax kickoff {:?}", negamax_kickoff(world, 2));
        // TODO: learn how to debug stuff
    }

}
<commit_msg>informative scenario highlights likelihood of parity blunder<commit_after>use std::f32::NEG_INFINITY;
use std::cmp::Ordering;

use identity::{Team, JobDescription, Agent};
use life::{Commit, WorldState};

pub fn orientation(team: Team) -> f32 {
    match team {
        Team::Orange => 1.0,
        Team::Blue => -1.0
    }
}

pub fn figurine_valuation(agent: Agent) -> f32 {
    let Agent { team: team, job_description: job_description } = agent;
    let value = match job_description {
        // en.wikipedia.org/wiki/
        // Chess_piece_relative_value#Hans_Berliner.27s_system
        JobDescription::Servant => 1.0,
        JobDescription::Pony => 3.2,
        JobDescription::Scholar => 3.3,
        JobDescription::Cop => 5.1,
        JobDescription::Princess => 8.8,
        JobDescription::Figurehead => 20000.0
    };
    orientation(team) * value
}

pub fn score(world: WorldState) -> f32 {
    let mut valuation = 0.0;
    for team in Team::league().into_iter() {
        for agent in Agent::dramatis_personae(team).into_iter() {
            valuation += world.agent_to_pinfield_ref(
                agent).pincount() as f32 * figurine_valuation(agent);
        }
    }
    valuation
}

pub fn negamax_search(world: WorldState, depth: u8) -> (Option<Commit>, f32) {
    let team = world.to_move;
    let premonitions = world.lookahead();
    if depth == 0 || premonitions.is_empty() {
        return (None, orientation(team) * score(world))
    }
    let mut optimum = NEG_INFINITY;
    let mut optimand = None;
    for premonition in premonitions.into_iter() {
        let (_after, mut value) = negamax_search(premonition.tree, depth-1);
        value = -value;
        if value > optimum {
            optimum = value;
            optimand = Some(premonition);
        }
    }
    (optimand, optimum)
}

// The vision here is that for the turn I'm immediately going to take,
// I want a report of all possible moves ranked by negamax-computed
// optimality, but that we don't want to bother with all that bookkeeping
// for subsequent levels of the game tree; minimax is expensive enough
// already!!
pub fn negamax_kickoff(world: WorldState, depth: u8) -> Vec<(Commit, f32)> {
    let team = world.to_move;
    let premonitions = world.lookahead();
    let mut forecasts = Vec::new();
    for premonition in premonitions.into_iter() {
        let (_grandchild, score) = negamax_search(premonition.tree, depth-1);
        forecasts.push((premonition, score));
    }
    forecasts.sort_by(|a, b| b.1.partial_cmp(&a.1).unwrap_or(Ordering::Equal));
    forecasts
}

#[cfg(test)]
mod test {
    use time;

    use super::{negamax_search, negamax_kickoff, score};
    use space::Locale;
    use life::WorldState;

    #[test]
    fn concerning_fairness_of_the_initial_position() {
        assert_eq!(0.0, score(WorldState::new()));
    }

    #[test]
    #[ignore]
    fn concerning_negamax_implementation_suitability() {
        for depth in 1..5 {
            let start = time::get_time();
            negamax_search(WorldState::new(), depth);
            let end = time::get_time();
            println!("searching the initial position to depth {} took {:?}",
                     depth, end-start);
        }
    }

    #[test]
    fn experimentally_about_negamax_kickoff() {
        let mut world = WorldState::new_except_empty();
        // SCENARIO: let's imagine Orange (to move) has separate attacks against
        // Blue's pony and servant, against which Blue has no defense but
        // to run away. We predict that Orange will take the pony, and
        // then Blue will move the servant out of the way.

        // scholar endangers pony
        world.blue_ponies = world.blue_ponies.alight(
            Locale { rank: 0, file: 0 }
        );
        world.orange_scholars = world.orange_scholars.alight(
            Locale { rank: 2, file: 2 }
        );

        // pony endanger servant
        world.blue_servants = world.blue_servants.alight(
            Locale { rank: 7, file: 1 }
        );
        world.orange_ponies = world.orange_ponies.alight(
            Locale { rank: 5, file: 2 }
        );

        let depth = 2;
        let start = time::get_time();
        let advisory = negamax_kickoff(world, depth);
        let end = time:: get_time();

        println!("negamax kickoff: evaluating {} possible choices to \
                  depth {} took {:?}", advisory.len(), depth, end-start);
        for item in advisory.iter() {
            println!("{:?}", item);
        }
        // XXX OK, I think I must have a sign error somewhere;
        // capturing the servant and pony are the lowest-ranked options
        // at -3.3 and -5.5, respectively: and the top option is to move
        // the Orange pony to a7 where the servant can get it!
    }

}
<|endoftext|>