<commit_before>// Copyright (c) 2015, Sam Payson
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
// associated documentation files (the "Software"), to deal in the Software without restriction,
// including without limitation the rights to use, copy, modify, merge, publish, distribute,
// sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
// NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

pub struct TakeWhileInclusive<I, P>
    where I: Iterator,
          P: Fn(&<I as Iterator>::Item) -> bool {

    inner: I,
    pred:  P,
    done:  bool,
}

impl<I, P> Iterator for TakeWhileInclusive<I, P>
    where I: Iterator,
          P: Fn(&<I as Iterator>::Item) -> bool {

    type Item = <I as Iterator>::Item;

    fn next(&mut self) -> Option<<I as Iterator>::Item> {
        if self.done {
            None
        } else {
            match self.inner.next() {
                Some(x) => {
                    self.done = !(self.pred)(&x);
                    Some(x)
                },
                None => None,
            }
        }
    }
}

/// `RexIterExt` provides methods on top of iterators (which feel generally useful).
pub trait RexIterExt: Iterator + Sized {

    /// `take_while_incl` returns an iterator which will return the elements of an underlying
    /// iterator until `pred` fails (or the iterator runs out). `take_while_incl` differs from
    /// `take_while` in that it *also returns the element for which `pred` failed*.
    fn take_while_incl<P>(self, pred: P) -> TakeWhileInclusive<Self, P>
        where P: Fn(&<Self as Iterator>::Item) -> bool {

        TakeWhileInclusive {
            inner: self,
            pred:  pred,
            done:  false,
        }
    }
}

impl<I> RexIterExt for I where I: Iterator {}
<commit_msg>Added ResultIterExt and the TakeOrErr iterator.<commit_after>// Copyright (c) 2015, Sam Payson
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
// associated documentation files (the "Software"), to deal in the Software without restriction,
// including without limitation the rights to use, copy, modify, merge, publish, distribute,
// sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
// NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

use std::error::FromError;
use std::mem;

pub struct TakeWhileInclusive<I, P>
    where I: Iterator,
          P: Fn(&<I as Iterator>::Item) -> bool {

    inner: I,
    pred:  P,
    done:  bool,
}

impl<I, P> Iterator for TakeWhileInclusive<I, P>
    where I: Iterator,
          P: Fn(&<I as Iterator>::Item) -> bool {

    type Item = <I as Iterator>::Item;

    fn next(&mut self) -> Option<<I as Iterator>::Item> {
        if self.done {
            None
        } else {
            match self.inner.next() {
                Some(x) => {
                    self.done = !(self.pred)(&x);
                    Some(x)
                },
                None => None,
            }
        }
    }
}

/// `RexIterExt` provides methods on top of iterators (which feel generally useful).
pub trait RexIterExt: Iterator + Sized {

    /// `take_while_incl` returns an iterator which will return the elements of an underlying
    /// iterator until `pred` fails (or the iterator runs out). `take_while_incl` differs from
    /// `take_while` in that it *also returns the element for which `pred` failed*.
    fn take_while_incl<P>(self, pred: P) -> TakeWhileInclusive<Self, P>
        where P: Fn(&<Self as Iterator>::Item) -> bool {

        TakeWhileInclusive {
            inner: self,
            pred:  pred,
            done:  false,
        }
    }
}

impl<I> RexIterExt for I where I: Iterator {}

pub struct TakeOrErr<I, V, E1, E2>
    where I: Iterator<Item = Result<V, E1>>, E2: FromError<E1> {

    inner:     I,
    remaining: usize,
    err:       Option<E2>,
}

impl<I, V, E1, E2> Iterator for TakeOrErr<I, V, E1, E2>
    where I: Iterator<Item = Result<V, E1>>, E2: FromError<E1> {

    type Item = Result<V, E2>;

    fn next(&mut self) -> Option<Result<V, E2>> {
        if self.remaining == 0 {
            None
        } else {
            match self.inner.next() {
                Some(Ok(v)) => {
                    self.remaining -= 1;
                    Some(Ok(v))
                }

                Some(Err(e)) => Some(Err(FromError::from_error(e))),

                None => match mem::replace(&mut self.err, None) {
                    Some(err) => Some(Err(err)),
                    None      => None,
                }
            }
        }
    }
}

/// `ResultIterExt` provides some convenient methods for iterators which yield `Result`s.
pub trait ResultIterExt<V, E>: Iterator<Item = Result<V, E>> + Sized {

    /// `take_or_err` returns an iterator which, if the stream ends prematurely, will place an
    /// error at the end of it to indicate this. This is intended to be used with `result::fold` to
    /// detect EOF in iterator streams (but might have other uses).
    fn take_or_err<E2>(self, num: usize, err: E2) -> TakeOrErr<Self, V, E, E2>
        where E2: FromError<E> {

        TakeOrErr {
            inner:     self,
            remaining: num,
            err:       Some(err),
        }
    }
}

impl<I, V, E> ResultIterExt<V, E> for I where I: Iterator<Item = Result<V, E>> {}
<|endoftext|>


<commit_before>use notify;
use time;

use std::collections::{HashMap, HashSet};
use std::sync::mpsc;
use super::task::Task;

struct Item<'a> {
    last_seen: time::PreciseTime,
    task: &'a Box<Task>,
}

pub struct ShellGrunt2<'a> {
    tasks: &'a [Box<Task>],
    events_rx: mpsc::Receiver<notify::DebouncedEvent>,
    work_items: HashMap<String, Item<'a>>,
}

impl<'a> ShellGrunt2<'a> {
    pub fn new(tasks: &'a [Box<Task>],
               events_rx: mpsc::Receiver<notify::DebouncedEvent>)
               -> ShellGrunt2<'a> {

        ShellGrunt2 {
            tasks: tasks,
            work_items: HashMap::new(),
            events_rx: events_rx,
        }
    }

    pub fn spin(&mut self) {
        self.check_for_new_work();

        let ev = match self.events_rx.try_recv() {
            Ok(ev) => ev,
            Err(_) => return,
        };

        use notify::DebouncedEvent::*;

        let path = match ev {
            NoticeWrite(path) |
            NoticeRemove(path) |
            Create(path) |
            Write(path) |
            Remove(path) => path,

            Rename(_, new_path) => new_path,

            Error(err, path) => {
                println!("Ignored error: {:?}, ({:?})", err, path);
                return;
            }
            Rescan | Chmod(_) => return,
        };

        for task in self.tasks {
            if !task.should_run(&path) {
                continue;
            }

            let entry = self.work_items.entry(task.name()).or_insert(Item {
                last_seen:
                    time::PreciseTime::now(),
                    task: &task,
            });
            entry.last_seen = time::PreciseTime::now();
            entry.task = &task;
        }
    }

    fn check_for_new_work(&mut self) {
        let mut done = HashSet::new();

        let now = time::PreciseTime::now();
        for (entry_name, entry) in &self.work_items {
            if entry.last_seen.to(now) > entry.task.start_delay() {
                entry.task.run();
                done.insert(entry_name.to_string());
            }
        }

        for key in &done {
            self.work_items.remove(key);
        }
    }
}
<commit_msg>Fix slowdown.<commit_after>use notify;
use time;

use std::collections::{HashMap, HashSet};
use std::sync::mpsc;
use super::task::Task;

struct Item<'a> {
    last_seen: time::PreciseTime,
    task: &'a Box<Task>,
}

pub struct ShellGrunt2<'a> {
    tasks: &'a [Box<Task>],
    events_rx: mpsc::Receiver<notify::DebouncedEvent>,
    work_items: HashMap<String, Item<'a>>,
}

impl<'a> ShellGrunt2<'a> {
    pub fn new(tasks: &'a [Box<Task>],
               events_rx: mpsc::Receiver<notify::DebouncedEvent>)
               -> ShellGrunt2<'a> {

        ShellGrunt2 {
            tasks: tasks,
            work_items: HashMap::new(),
            events_rx: events_rx,
        }
    }

    pub fn spin(&mut self) {
        while let Ok(ev) = self.events_rx.try_recv() {
            use notify::DebouncedEvent::*;

            let path = match ev {
                NoticeWrite(path) |
                    NoticeRemove(path) |
                    Create(path) |
                    Write(path) |
                    Remove(path) => path,

                    Rename(_, new_path) => new_path,

                    Error(err, path) => {
                        println!("Ignored error: {:?}, ({:?})", err, path);
                        continue;
                    }
                Rescan | Chmod(_) => continue,
            };
            for task in self.tasks {
                if !task.should_run(&path) {
                    continue;
                }

                let entry = self.work_items.entry(task.name()).or_insert(Item {
                    last_seen:
                        time::PreciseTime::now(),
                        task: &task,
                });
                entry.last_seen = time::PreciseTime::now();
                entry.task = &task;
            }
        }

        self.check_for_new_work();
    }

    fn check_for_new_work(&mut self) {
        let mut done = HashSet::new();

        let now = time::PreciseTime::now();
        for (entry_name, entry) in &self.work_items {
            if entry.last_seen.to(now) > entry.task.start_delay() {
                entry.task.run();
                done.insert(entry_name.to_string());
            }
        }

        for key in &done {
            self.work_items.remove(key);
        }
    }
}
<|endoftext|>


<commit_before>/*
 * Cymbalum, Molecular Simulation in Rust
 * Copyright (C) 2015 Guillaume Fraux
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/
*/
//! Testing physical properties of a NaCl crystal
extern crate cymbalum;
use self::cymbalum::*;

use std::path::Path;

fn setup() -> (Simulation, Universe) {
    let data_dir = Path::new(file!()).parent().unwrap();
    let configuration = data_dir.join("data").join("NaCl.xyz");
    let mut universe = Universe::from_file(configuration.to_str().unwrap()).unwrap();
    universe.set_cell(UnitCell::cubic(11.2804));

    let potentials = data_dir.join("data").join("NaCl.yml");
    input::read_interactions(&mut universe, potentials).unwrap();

    let mut velocities = BoltzmanVelocities::new(units::from(300.0, "K").unwrap());
    velocities.init(&mut universe);

    let simulation = Simulation::new(
        MolecularDynamics::new(units::from(1.0, "fs").unwrap())
    );
    return (simulation, universe);
}

#[test]
fn constant_energy() {
    Logger::stdout();
    let (mut simulation, mut universe) = setup();

    let e_initial = universe.total_energy();
    simulation.run(&mut universe, 1000);
    let e_final = universe.total_energy();
    assert!(f64::abs(e_initial - e_final)/e_final < 1e-6);
}
<commit_msg>Anisotropic Berendsen barostat test<commit_after>/*
 * Cymbalum, Molecular Simulation in Rust
 * Copyright (C) 2015 Guillaume Fraux
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/
*/
//! Testing physical properties of a NaCl crystal
extern crate cymbalum;
use self::cymbalum::*;

use std::path::Path;
use std::sync::{Once, ONCE_INIT};
static START: Once = ONCE_INIT;

fn setup_universe() -> Universe {
    let data_dir = Path::new(file!()).parent().unwrap();
    let configuration = data_dir.join("data").join("NaCl.xyz");
    let mut universe = Universe::from_file(configuration.to_str().unwrap()).unwrap();
    universe.set_cell(UnitCell::cubic(11.2804));

    let potentials = data_dir.join("data").join("NaCl.yml");
    input::read_interactions(&mut universe, potentials).unwrap();

    let mut velocities = BoltzmanVelocities::new(units::from(300.0, "K").unwrap());
    velocities.init(&mut universe);
    return universe;
}

#[test]
fn constant_energy() {
    START.call_once(|| {Logger::stdout();});
    let mut universe = setup_universe();
    let mut simulation = Simulation::new(
        MolecularDynamics::new(units::from(1.0, "fs").unwrap())
    );

    let e_initial = universe.total_energy();
    simulation.run(&mut universe, 1000);
    let e_final = universe.total_energy();
    assert!(f64::abs(e_initial - e_final)/e_final < 1e-6);
}

#[test]
fn anisotropic_berendsen() {
    START.call_once(|| {Logger::stdout();});
    let mut universe = setup_universe();
    let mut simulation = Simulation::new(
        MolecularDynamics::from_integrator(
            AnisoBerendsenBarostat::hydrostatic(
                units::from(1.0, "fs").unwrap(),
                units::from(5e4, "bar").unwrap()
            )
        )
    );

    simulation.run(&mut universe, 10000);
    let pressure = units::from(5e4, "bar").unwrap();
    assert!(f64::abs(universe.pressure() - pressure)/pressure < 1e-2);
}
<|endoftext|>


<commit_before>//! This file contains automated tests, but they require virtual ports and therefore can't work on Windows ...
#![cfg(not(windows))]
extern crate midir;

use std::thread::sleep;
use std::time::Duration;

use midir::{MidiInput, MidiOutput, Ignore};
use midir::os::unix::{VirtualInput, VirtualOutput};

#[test]
fn end_to_end() {
    let mut midi_in = MidiInput::new("My Test Input").unwrap();
    midi_in.ignore(Ignore::None);
    let midi_out = MidiOutput::new("My Test Output").unwrap();

    let previous_count = midi_out.port_count();

    println!("Creating virtual input port ...");
    let conn_in = midi_in.create_virtual("midir-test", |stamp, message, _| {
        println!("{}: {:?} (len = {})", stamp, message, message.len());
    }, ()).unwrap();

    assert_eq!(midi_out.port_count(), previous_count + 1);

    println!("Connecting to port '{}' ...", midi_out.port_name(previous_count).unwrap());
    let mut conn_out = midi_out.connect(previous_count, "midir-test").unwrap();
    println!("Starting to send messages ...");
    conn_out.send(&[144, 60, 1]).unwrap();
    sleep(Duration::from_millis(200));
    conn_out.send(&[144, 60, 0]).unwrap();
    sleep(Duration::from_millis(50));
    conn_out.send(&[144, 60, 1]).unwrap();
    sleep(Duration::from_millis(200));
    conn_out.send(&[144, 60, 0]).unwrap();
    println!("Closing output ...");
    let midi_out = conn_out.close();
    println!("Closing virtual input ...");
    let midi_in = conn_in.close().0;
    assert_eq!(midi_out.port_count(), previous_count);

    let previous_count = midi_in.port_count();

    // reuse midi_in and midi_out, but swap roles
    println!("\nCreating virtual output port ...");
    let mut conn_out = midi_out.create_virtual("midir-test").unwrap();
    assert_eq!(midi_in.port_count(), previous_count + 1);

    println!("Connecting to port '{}' ...", midi_in.port_name(previous_count).unwrap());
    let conn_in = midi_in.connect(previous_count, "midir-test", |stamp, message, _| {
        println!("{}: {:?} (len = {})", stamp, message, message.len());
    }, ()).unwrap();
    println!("Starting to send messages ...");
    conn_out.send(&[144, 60, 1]).unwrap();
    sleep(Duration::from_millis(200));
    conn_out.send(&[144, 60, 0]).unwrap();
    sleep(Duration::from_millis(50));
    conn_out.send(&[144, 60, 1]).unwrap();
    sleep(Duration::from_millis(200));
    conn_out.send(&[144, 60, 0]).unwrap();
    println!("Closing input ...");
    let midi_in = conn_in.close().0;
    println!("Closing virtual output ...");
    conn_out.close();
    assert_eq!(midi_in.port_count(), previous_count);
}
<commit_msg>Give the test some more time to receive the messages<commit_after>//! This file contains automated tests, but they require virtual ports and therefore can't work on Windows ...
#![cfg(not(windows))]
extern crate midir;

use std::thread::sleep;
use std::time::Duration;

use midir::{MidiInput, MidiOutput, Ignore};
use midir::os::unix::{VirtualInput, VirtualOutput};

#[test]
fn end_to_end() {
    let mut midi_in = MidiInput::new("My Test Input").unwrap();
    midi_in.ignore(Ignore::None);
    let midi_out = MidiOutput::new("My Test Output").unwrap();

    let previous_count = midi_out.port_count();

    println!("Creating virtual input port ...");
    let conn_in = midi_in.create_virtual("midir-test", |stamp, message, _| {
        println!("{}: {:?} (len = {})", stamp, message, message.len());
    }, ()).unwrap();

    assert_eq!(midi_out.port_count(), previous_count + 1);

    println!("Connecting to port '{}' ...", midi_out.port_name(previous_count).unwrap());
    let mut conn_out = midi_out.connect(previous_count, "midir-test").unwrap();
    println!("Starting to send messages ...");
    conn_out.send(&[144, 60, 1]).unwrap();
    sleep(Duration::from_millis(200));
    conn_out.send(&[144, 60, 0]).unwrap();
    sleep(Duration::from_millis(50));
    conn_out.send(&[144, 60, 1]).unwrap();
    sleep(Duration::from_millis(200));
    conn_out.send(&[144, 60, 0]).unwrap();
    sleep(Duration::from_millis(50));
    println!("Closing output ...");
    let midi_out = conn_out.close();
    println!("Closing virtual input ...");
    let midi_in = conn_in.close().0;
    assert_eq!(midi_out.port_count(), previous_count);

    let previous_count = midi_in.port_count();

    // reuse midi_in and midi_out, but swap roles
    println!("\nCreating virtual output port ...");
    let mut conn_out = midi_out.create_virtual("midir-test").unwrap();
    assert_eq!(midi_in.port_count(), previous_count + 1);

    println!("Connecting to port '{}' ...", midi_in.port_name(previous_count).unwrap());
    let conn_in = midi_in.connect(previous_count, "midir-test", |stamp, message, _| {
        println!("{}: {:?} (len = {})", stamp, message, message.len());
    }, ()).unwrap();
    println!("Starting to send messages ...");
    conn_out.send(&[144, 60, 1]).unwrap();
    sleep(Duration::from_millis(200));
    conn_out.send(&[144, 60, 0]).unwrap();
    sleep(Duration::from_millis(50));
    conn_out.send(&[144, 60, 1]).unwrap();
    sleep(Duration::from_millis(200));
    conn_out.send(&[144, 60, 0]).unwrap();
    sleep(Duration::from_millis(50));
    println!("Closing input ...");
    let midi_in = conn_in.close().0;
    println!("Closing virtual output ...");
    conn_out.close();
    assert_eq!(midi_in.port_count(), previous_count);
}
<|endoftext|>


<commit_before>//! Uniform point distribution in an annulus using Bridson’s algorithm for Poisson-disc sampling
//! from [Visualizing Algorithms](http://bost.ocks.org/mike/algorithms/).
//!
//! Uses [qhull](http://qhull.org/) to generate a Delaunay triangulation.
extern crate rand;
extern crate gnuplot;

use std::f64::consts::PI;
#[allow(unused_imports)]
use gnuplot::{Figure, Caption, Color, Fix, AxesCommon, PlotOption, DashType, Coordinate, TextColor};
use rand::Rng;
use rand::distributions::{IndependentSample, Range};
use std::io::{Read, Write, Cursor, BufRead};
use std::process::{Command, Stdio};

fn dist(x: (f64, f64), y: (f64, f64)) -> f64 {
    ((x.0 - y.0).powi(2) + (x.1 - y.1).powi(2)).sqrt()
}

fn qhull_triangulation(ps: &[(f64, f64)]) -> Vec<Vec<i32>> {
    let mut process = Command::new("qhull")
        .stdin(Stdio::piped())
        .stdout(Stdio::piped())
        .arg("d")
        .arg("i")
        .spawn()
        .unwrap_or_else(|e|
            panic!("couldn't spawn qhull: {:?}", e)
        );

    if let Some(ref mut out) = process.stdin {
        write!(out, "2\n{}\n", ps.len()).unwrap();

        for &(x,y) in ps {
            write!(out, "{} {}\n", x, y).unwrap();
        }
    }

    // process.stdout.unwrap().read_to_string(&mut s);
    let output = process.wait_with_output().unwrap();

    let mut lines = Cursor::new(output.stdout).lines();

    let n = lines.next().unwrap().unwrap().parse::<usize>().unwrap();

    let mut res = vec![];

    for line in lines {
        let s = line.unwrap();
        let poly: Vec<i32> = s.split_whitespace().map(|e| e.parse::<i32>().unwrap()).collect();
        res.push(poly);
    }

    assert_eq!(res.len(), n);
    res
}

fn main() {
    let mut rng = rand::thread_rng();

    let mut ps = vec![];
    let mut active: Vec<(f64, f64)> = vec![];

    let r1 = 0.1;
    let r2 = 1.;
    let n_gen = 50;

    let h = 0.05;
    let mean_dist_ratio = 0.7;

    let k1 = (mean_dist_ratio * 2. * PI * r1 / h).round() as i32;
    let k2 = (mean_dist_ratio * 2. * PI * r2 / h).round() as i32;

    for &(k, r) in &[(k1, r1), (k2, r2)] {
        for i in 0..k {
            ps.push((r * (2. * PI * i as f64 / k as f64).cos(),
                    r * (2. * PI * i as f64 / k as f64).sin()));
        }
    }

    active.extend(&ps);

    let x_range = Range::new(h * h, 4. * h * h);
    let theta_range = Range::new(0., 2. * PI);

    while !active.is_empty() {
        let i = rng.gen_range(0, active.len());

        let c = active[i];
        let mut deactivate = true;

        for _ in 0..n_gen {
            let mut p;

            loop {
                let r = x_range.ind_sample(&mut rng).sqrt();
                let theta = theta_range.ind_sample(&mut rng);

                p = (r * theta.cos() + c.0, r * theta.sin() + c.1);
                let d = dist(p, (0., 0.));

                if r1 <= d && d <= r2 {
                    break;
                }
            }

            if ps.iter().all(|&q| dist(p, q) >= h) {
                ps.push(p);
                active.push(p);
                deactivate = false;
                break;
            }
        }

        if deactivate {
            active.remove(i);
        }

    }

    let indices = qhull_triangulation(&ps);

    let mut fg = Figure::new();
    // fg.clear_axes();
    // fg.axes2d()
    //     .set_aspect_ratio(Fix(1.))
    //     .points(ps.iter().map(|&x| x.0), ps.iter().map(|&x| x.1), &[]);

    fg.clear_axes();
    {
        let axes = fg.axes2d();
        axes.set_aspect_ratio(Fix(1.));
        for poly in indices {
            axes.lines(poly.iter().cycle().take(poly.len() + 1).map(|&i| ps[i as usize].0),
                    poly.iter().cycle().take(poly.len() + 1).map(|&i| ps[i as usize].1), &[]);
        }
    }

    fg.show();

}
<commit_msg>Simple png output<commit_after>//! Uniform point distribution in an annulus using Bridson’s algorithm for Poisson-disc sampling
//! from [Visualizing Algorithms](http://bost.ocks.org/mike/algorithms/).
//!
//! Uses [qhull](http://qhull.org/) to generate a Delaunay triangulation.
extern crate rand;
extern crate gnuplot;

use std::f64::consts::PI;
#[allow(unused_imports)]
use gnuplot::{Figure, Caption, Color, Fix, AxesCommon, PlotOption, DashType, Coordinate, TextColor};
use rand::Rng;
use rand::distributions::{IndependentSample, Range};
use std::io::{Read, Write, Cursor, BufRead};
use std::process::{Command, Stdio};

fn dist(x: (f64, f64), y: (f64, f64)) -> f64 {
    ((x.0 - y.0).powi(2) + (x.1 - y.1).powi(2)).sqrt()
}

fn qhull_triangulation(ps: &[(f64, f64)]) -> Vec<Vec<i32>> {
    let mut process = Command::new("qhull")
        .stdin(Stdio::piped())
        .stdout(Stdio::piped())
        .arg("d")
        .arg("i")
        .spawn()
        .unwrap_or_else(|e|
            panic!("couldn't spawn qhull: {:?}", e)
        );

    if let Some(ref mut out) = process.stdin {
        write!(out, "2\n{}\n", ps.len()).unwrap();

        for &(x,y) in ps {
            write!(out, "{} {}\n", x, y).unwrap();
        }
    }

    // process.stdout.unwrap().read_to_string(&mut s);
    let output = process.wait_with_output().unwrap();

    let mut lines = Cursor::new(output.stdout).lines();

    let n = lines.next().unwrap().unwrap().parse::<usize>().unwrap();

    let mut res = vec![];

    for line in lines {
        let s = line.unwrap();
        let poly: Vec<i32> = s.split_whitespace().map(|e| e.parse::<i32>().unwrap()).collect();
        res.push(poly);
    }

    assert_eq!(res.len(), n);
    res
}

fn main() {
    let mut rng = rand::thread_rng();

    let mut ps = vec![];
    let mut active: Vec<(f64, f64)> = vec![];

    let r1 = 0.2;
    let r2 = 1.;
    let n_gen = 50;

    let h = 0.025;
    let mean_dist_ratio = 0.7;

    let k1 = (mean_dist_ratio * 2. * PI * r1 / h).round() as i32;
    let k2 = (mean_dist_ratio * 2. * PI * r2 / h).round() as i32;

    for &(k, r) in &[(k1, r1), (k2, r2)] {
        for i in 0..k {
            ps.push((r * (2. * PI * i as f64 / k as f64).cos(),
                    r * (2. * PI * i as f64 / k as f64).sin()));
        }
    }

    active.extend(&ps);

    let x_range = Range::new(h * h, 4. * h * h);
    let theta_range = Range::new(0., 2. * PI);

    while !active.is_empty() {
        let i = rng.gen_range(0, active.len());

        let c = active[i];
        let mut deactivate = true;

        for _ in 0..n_gen {
            let mut p;

            loop {
                let r = x_range.ind_sample(&mut rng).sqrt();
                let theta = theta_range.ind_sample(&mut rng);

                p = (r * theta.cos() + c.0, r * theta.sin() + c.1);
                let d = dist(p, (0., 0.));

                if r1 <= d && d <= r2 {
                    break;
                }
            }

            if ps.iter().all(|&q| dist(p, q) >= h) {
                ps.push(p);
                active.push(p);
                deactivate = false;
                break;
            }
        }

        if deactivate {
            active.remove(i);
        }

    }

    let indices = qhull_triangulation(&ps);

    let mut fg = Figure::new();
    fg.set_terminal("pngcairo size 720, 720", "/tmp/delaunay.png");
    // fg.clear_axes();
    // fg.axes2d()
    //     .set_aspect_ratio(Fix(1.))
    //     .points(ps.iter().map(|&x| x.0), ps.iter().map(|&x| x.1), &[]);

    fg.clear_axes();
    {
        let axes = fg.axes2d();
        axes.set_aspect_ratio(Fix(1.));
        for poly in indices {
            axes.lines(poly.iter().cycle().take(poly.len() + 1).map(|&i| ps[i as usize].0),
                    poly.iter().cycle().take(poly.len() + 1).map(|&i| ps[i as usize].1), &[]);
        }
    }

    fg.show();

}
<|endoftext|>


<commit_before>#![feature(phase)]
#[phase(plugin, link)] extern crate log;
#[phase(plugin)] extern crate nickel_macros;
extern crate nickel;
extern crate serialize;

use p150::{CpuState, P150Cpu};

use serialize::json;
use serialize::hex::FromHex;
use std::collections::HashMap;
use std::io::net::ip::Ipv4Addr;
use std::sync::{Arc,RWLock};
use nickel::{JsonBody, Nickel, Request, Response};
use nickel::{Middleware, HttpRouter, StaticFilesHandler};
use nickel::{MiddlewareResult, NickelError};

mod p150;

static MAX_CYCLES: i32 = 100000; // maximum number of cycles CPU can execute to prevent DoS attacks.

/// Injects a mutex-protected CpuServ into request map when invoked
struct CpuMw { db: Arc<RWLock<CpuServ>> }

/// A database of multiple uniquely identified P150 CPU emulators.
///
/// Each emulator maintains its own state and can be recalled
/// using the integer identification.
struct CpuServ {
	next_cpu: i32,
	database: HashMap<i32, P150Cpu>,
}

impl Middleware for CpuMw {
	fn invoke(&self, req: &mut Request, _res: &mut Response) -> MiddlewareResult {
		req.map.insert(self.db.clone());
		Ok(nickel::Continue)
	}
}

impl CpuServ {
	fn new() -> CpuServ {
		CpuServ {
			next_cpu: 0,
			database: HashMap::new(),
		}
	}
}

fn main() {
	let mut server = Nickel::new();
	let mut router = Nickel::router();

	fn index_show(_request: &Request, response: &mut Response) {
		let mut page = HashMap::new();
		page.insert("title", "P150 Emulator");

		response.render("./assets/views/index.html", &page);
	}

	fn about_show(_request: &Request, response: &mut Response) {
		let mut page = HashMap::new();
		page.insert("title", "P150 Emulator");

		response.render("./assets/views/about.html", &page);
	}

	/// POST /cpu/new: creates a new CPU and adds it to the CpuServ with the next
	/// available ID number.
	fn cpu_new(req: &Request, response: &mut Response) {
		match req.map.find::<Arc<RWLock<CpuServ>>>() {
			Some(cpuserv) => {
				let mut w_cpuserv = cpuserv.write();
				let cpu_no = w_cpuserv.next_cpu;

				w_cpuserv.database.insert(cpu_no, P150Cpu::new());
				w_cpuserv.next_cpu += 1;

				response.send(json::encode(&cpu_no));
			},
			None => { response.send("did not find cpu serv"); }
		}
	}

	/// POST /cpu/:id/load
	/// Overwrites the CPUs system memory with response data.
	/// The current machine state is then dumped into the response as JSON.
	fn cpu_load(req: &Request, response: &mut Response) {
		let id = from_str::<i32>(req.param("id")).unwrap();
		let mem_js = req.json_as::<Vec<String>>().unwrap();
		let mem_native: Vec<u8> = mem_js.iter().map(|hex| {
			match hex.as_slice().from_hex() {
				Ok(decoded) => { if decoded.len() > 0 { decoded[0] } else { 0xFF } },
				Err(msg) => { debug!("error reading json memory: {}", msg); 0xFF },
			}
		}).collect();

		info!("length of mem instructions: {}", mem_native.len());

		// pair odd u8s with even u8s to produce u16 ops.
		let even_mn = mem_native.iter().enumerate().filter(|&(idx, _)| { idx % 2 == 0 });
		let odd_mn  = mem_native.iter().enumerate().filter(|&(idx, _)| { idx % 2 != 0 });
		let ops: Vec<u16> = even_mn.zip(odd_mn).map(|((_, &msb), (_, &lsb))| {
			(msb as u16 << 8) | (lsb as u16)
		}).collect();

		match req.map.find::<Arc<RWLock<CpuServ>>>() {
			Some(cpuserv) => {
				match cpuserv.write().database.find_mut(&id) {
					Some(cpu) => {
						cpu.init_mem(ops.as_slice()); // TODO: load from req.
						response.send(format!("{}", cpu.js_dump()));
					},
					None => { response.send("did not find the cpu") },
				};
			},
			None => { response.send("did not find cpu serv"); }
		}
	}

	/// POST /cpu/:id/dump
	/// Dumps the CPUs current state to a JSON format.
	/// This request does not modify the CPU state in any way.
	fn cpu_dump(req: &Request, response: &mut Response) {
		let id = from_str::<i32>(req.param("id")).unwrap();
		match req.map.find::<Arc<RWLock<CpuServ>>>() {
			Some(cpuserv) => {
				let r_serv = cpuserv.read();
				let cpu        = r_serv.database.find(&id).unwrap();

				response.send(format!("{}", cpu.js_dump()));
			},
			None => { response.send("did not find cpu serv"); }
		}
	}

	/// POST /cpu/:id/tick
	/// Resumes execution from the next instruction; running the machine to completion.
	/// The resultant state is then dumped to the console.
	fn cpu_tick(req: &Request, response: &mut Response) {
		let id = from_str::<i32>(req.param("id")).unwrap();
		match req.map.find::<Arc<RWLock<CpuServ>>>() {
			Some(cpuserv) => {
				let mut w_serv = cpuserv.write();
				let cpu        = w_serv.database.find_mut(&id).unwrap();
				let _          = cpu.tick();

				response.send(format!("{}", cpu.js_dump()));
			},
			None => { response.send("did not find cpu serv"); }
		}
	}

	/// POST /cpu/:id/run
	/// Resumes execution from the next instruction; running the machine to completion.
	/// The resultant state is then dumped to the console.
	fn cpu_run(req: &Request, response: &mut Response) {
		let id = from_str::<i32>(req.param("id")).unwrap();

		match req.map.find::<Arc<RWLock<CpuServ>>>() {
			Some(cpuserv) => {
				let mut cycles = 0i32;
				let mut w_serv = cpuserv.write();
				let cpu    = w_serv.database.find_mut(&id).unwrap();
				loop {
					if cycles >= MAX_CYCLES { println!("CPU executed > {} cycles.", MAX_CYCLES); break; }
					cycles += 1;

					match cpu.tick() {
						CpuState::Halt => { break; },
						CpuState::Continue => { continue; },
					}
				}

				response.send(format!("{}", cpu.js_dump()));
			},
			None => { response.send("did not find cpu serv"); }
		}
	}

	router.get("/", index_show);
	router.get("/about", about_show);

	router.post("/cpu/new", cpu_new);
	router.post("/cpu/:id/tick", cpu_tick);
	router.post("/cpu/:id/run", cpu_run);
	router.post("/cpu/:id/load", cpu_load);
	router.get("/cpu/:id/dump", cpu_dump);
	// TODO: /cpu/:id/tick, /cpu/:id/reset
	// TODO: /cpu/:id/save ???

	server.utilize(CpuMw { db: Arc::new(RWLock::new(CpuServ::new())) });
	server.utilize(StaticFilesHandler::new("./public"));
	server.utilize(Nickel::json_body_parser());
	server.utilize(router);

	server.listen(Ipv4Addr(0,0,0,0), 3200);
}

<commit_msg>(Fix warnings.)<commit_after>#![feature(phase)]
#[phase(plugin, link)] extern crate log;
#[phase(plugin)] extern crate nickel_macros;
extern crate nickel;
extern crate serialize;

use p150::{CpuState, P150Cpu};

use serialize::json;
use serialize::hex::FromHex;
use std::collections::HashMap;
use std::io::net::ip::Ipv4Addr;
use std::sync::{Arc,RWLock};
use nickel::{JsonBody, Nickel, Request, Response};
use nickel::{Middleware, HttpRouter, StaticFilesHandler};
use nickel::{MiddlewareResult};

mod p150;

static MAX_CYCLES: i32 = 100000; // maximum number of cycles CPU can execute to prevent DoS attacks.

/// Injects a mutex-protected CpuServ into request map when invoked
struct CpuMw { db: Arc<RWLock<CpuServ>> }

/// A database of multiple uniquely identified P150 CPU emulators.
///
/// Each emulator maintains its own state and can be recalled
/// using the integer identification.
struct CpuServ {
	next_cpu: i32,
	database: HashMap<i32, P150Cpu>,
}

impl Middleware for CpuMw {
	fn invoke(&self, req: &mut Request, _res: &mut Response) -> MiddlewareResult {
		req.map.insert(self.db.clone());
		Ok(nickel::Continue)
	}
}

impl CpuServ {
	fn new() -> CpuServ {
		CpuServ {
			next_cpu: 0,
			database: HashMap::new(),
		}
	}
}

fn main() {
	let mut server = Nickel::new();
	let mut router = Nickel::router();

	fn index_show(_request: &Request, response: &mut Response) {
		let mut page = HashMap::new();
		page.insert("title", "P150 Emulator");

		response.render("./assets/views/index.html", &page);
	}

	fn about_show(_request: &Request, response: &mut Response) {
		let mut page = HashMap::new();
		page.insert("title", "P150 Emulator");

		response.render("./assets/views/about.html", &page);
	}

	/// POST /cpu/new: creates a new CPU and adds it to the CpuServ with the next
	/// available ID number.
	fn cpu_new(req: &Request, response: &mut Response) {
		match req.map.get::<Arc<RWLock<CpuServ>>>() {
			Some(cpuserv) => {
				let mut w_cpuserv = cpuserv.write();
				let cpu_no = w_cpuserv.next_cpu;

				w_cpuserv.database.insert(cpu_no, P150Cpu::new());
				w_cpuserv.next_cpu += 1;

				response.send(json::encode(&cpu_no));
			},
			None => { response.send("did not find cpu serv"); }
		}
	}

	/// POST /cpu/:id/load
	/// Overwrites the CPUs system memory with response data.
	/// The current machine state is then dumped into the response as JSON.
	fn cpu_load(req: &Request, response: &mut Response) {
		let id = from_str::<i32>(req.param("id")).unwrap();
		let mem_js = req.json_as::<Vec<String>>().unwrap();
		let mem_native: Vec<u8> = mem_js.iter().map(|hex| {
			match hex.as_slice().from_hex() {
				Ok(decoded) => { if decoded.len() > 0 { decoded[0] } else { 0xFF } },
				Err(msg) => { debug!("error reading json memory: {}", msg); 0xFF },
			}
		}).collect();

		info!("length of mem instructions: {}", mem_native.len());

		// pair odd u8s with even u8s to produce u16 ops.
		let even_mn = mem_native.iter().enumerate().filter(|&(idx, _)| { idx % 2 == 0 });
		let odd_mn  = mem_native.iter().enumerate().filter(|&(idx, _)| { idx % 2 != 0 });
		let ops: Vec<u16> = even_mn.zip(odd_mn).map(|((_, &msb), (_, &lsb))| {
			(msb as u16 << 8) | (lsb as u16)
		}).collect();

		match req.map.get::<Arc<RWLock<CpuServ>>>() {
			Some(cpuserv) => {
				match cpuserv.write().database.get_mut(&id) {
					Some(cpu) => {
						cpu.init_mem(ops.as_slice()); // TODO: load from req.
						response.send(format!("{}", cpu.js_dump()));
					},
					None => { response.send("did not find the cpu") },
				};
			},
			None => { response.send("did not find cpu serv"); }
		}
	}

	/// POST /cpu/:id/dump
	/// Dumps the CPUs current state to a JSON format.
	/// This request does not modify the CPU state in any way.
	fn cpu_dump(req: &Request, response: &mut Response) {
		let id = from_str::<i32>(req.param("id")).unwrap();
		match req.map.get::<Arc<RWLock<CpuServ>>>() {
			Some(cpuserv) => {
				let r_serv = cpuserv.read();
				let cpu        = r_serv.database.get(&id).unwrap();

				response.send(format!("{}", cpu.js_dump()));
			},
			None => { response.send("did not find cpu serv"); }
		}
	}

	/// POST /cpu/:id/tick
	/// Resumes execution from the next instruction; running the machine to completion.
	/// The resultant state is then dumped to the console.
	fn cpu_tick(req: &Request, response: &mut Response) {
		let id = from_str::<i32>(req.param("id")).unwrap();
		match req.map.get::<Arc<RWLock<CpuServ>>>() {
			Some(cpuserv) => {
				let mut w_serv = cpuserv.write();
				match w_serv.database.get_mut(&id) {
					Some(cpu) => { cpu.tick(); response.send(format!("{}", cpu.js_dump())); },
					None => { response.send("did not find cpu"); }
				};
			},
			None => { response.send("did not find cpu serv"); }
		}
	}

	/// POST /cpu/:id/run
	/// Resumes execution from the next instruction; running the machine to completion.
	/// The resultant state is then dumped to the console.
	fn cpu_run(req: &Request, response: &mut Response) {
		let id = from_str::<i32>(req.param("id")).unwrap();

		match req.map.get::<Arc<RWLock<CpuServ>>>() {
			Some(cpuserv) => {
				let mut cycles = 0i32;
				let mut w_serv = cpuserv.write();
				let cpu    = w_serv.database.get_mut(&id).unwrap();
				loop {
					if cycles >= MAX_CYCLES { println!("CPU executed > {} cycles.", MAX_CYCLES); break; }
					cycles += 1;

					match cpu.tick() {
						CpuState::Halt => { break; },
						CpuState::Continue => { continue; },
					}
				}

				response.send(format!("{}", cpu.js_dump()));
			},
			None => { response.send("did not find cpu serv"); }
		}
	}

	router.get("/", index_show);
	router.get("/about", about_show);

	router.post("/cpu/new", cpu_new);
	router.post("/cpu/:id/tick", cpu_tick);
	router.post("/cpu/:id/run", cpu_run);
	router.post("/cpu/:id/load", cpu_load);
	router.get("/cpu/:id/dump", cpu_dump);
	// TODO: /cpu/:id/tick, /cpu/:id/reset
	// TODO: /cpu/:id/save ???

	server.utilize(CpuMw { db: Arc::new(RWLock::new(CpuServ::new())) });
	server.utilize(StaticFilesHandler::new("./public"));
	server.utilize(Nickel::json_body_parser());
	server.utilize(router);

	server.listen(Ipv4Addr(0,0,0,0), 3200);
}

<|endoftext|>


<commit_before>#![feature(globs)]
#![feature(macro_rules)]

extern crate xml;

use std::io::{File, BufferedReader};
use std::default::Default;
use xml::reader::EventReader;
use fromxml::{parse_root};

mod fromxml;

deriving_fromxml! {
    struct Device {
        vendor:Option<String>,
        vendorID:Option<String>,
        licenseText:Option<String>,
        series:Option<String>,
        version:Option<String>,
        description:Option<String>,
        cpu:Option<CPU>,
        peripherals: Vec<Peripheral>,
    }

    struct Peripheral {
        name: String,
        version:Option<String>,
        description:Option<String>,
        groupName:Option<String>,
        prependToName:Option<String>,
        baseAddress:Option<String>,
        access:Option<String>,
        interrupt:Option<Interrupt>,
        registers: Vec<Register>,
    }

    struct Interrupt {
        name: String,
        value:Option<uint>,
    }

    struct Register {
        name: String,
        dim:Option<uint>,
        dimIncrement:Option<String>,
        description:Option<String>,
        addressOffset:Option<String>,
        size:Option<uint>,
        access:Option<String>,
        fields: Vec<Field>,
    }

    struct Field {
        name: String,
        description:Option<String>,
        bitOffset:Option<uint>,
        bitWidth:Option<uint>,
        access:Option<String>,
        enumeratedValues: Vec<EnumeratedValue>,
    }

    struct EnumeratedValue {
        name: String,
        value: String,
        description:Option<String>,
    }

    struct CPU {
        name:Option<String>,
        revision:Option<String>,
    }
}

fn print_doc_comment(doc: Option<&String>) {
    if let Some(d) = doc {
        print!(" //= {}", d);
    }
}

fn main() {
    let file = File::open(&Path::new("file.xml")).unwrap();
    let reader = BufferedReader::new(file);

    let mut parser = EventReader::new(reader);
    let mut iter = parser.events();
    let device: Device = parse_root(&mut iter).unwrap();

    for peripheral in device.peripherals.iter() {
        println!("ioregs!({} = {{", peripheral.name);
        for register in peripheral.registers.iter() {
            let offset = register.addressOffset.as_ref().map_or("", |x| x.as_slice());
            let size = register.size.unwrap_or(0);
            print!("    {} => reg{} {} {{", offset, size, register.name);
            print_doc_comment(register.description.as_ref());
            print!("\n");

            for field in register.fields.iter() {
                let lsb = field.bitOffset.unwrap();
                let width = field.bitWidth.unwrap();

                print!("         {}", lsb);

                if width > 1 {
                    print!("..{}", lsb + width - 1);
                }

                print!(" => {}", field.name);

                if field.enumeratedValues.len() == 0 {
                    print!(",");
                } else {
                    print!(" {{");
                }

                print_doc_comment(field.description.as_ref());
                print!("\n");

                if field.enumeratedValues.len() != 0 {
                    for en in field.enumeratedValues.iter() {
                        if en.name.len() == 0 { continue } // TODO: this is a <name>, not an <enumeratedValues>
                        print!("             {} => {}", en.name, en.value);
                        print_doc_comment(en.description.as_ref());
                        print!("\n");
                    }
                    println!("         }}");
                }
            }

            println!("    }}");
        }
        println!("}}")
    }
}
<commit_msg>Refactor ioreg output<commit_after>#![feature(globs)]
#![feature(macro_rules)]

extern crate xml;

use std::io::{File, BufferedReader};
use std::default::Default;

use xml::reader::EventReader;
use fromxml::{parse_root};

mod fromxml;

deriving_fromxml! {
    struct Device {
        vendor:Option<String>,
        vendorID:Option<String>,
        licenseText:Option<String>,
        series:Option<String>,
        version:Option<String>,
        description:Option<String>,
        cpu:Option<CPU>,
        peripherals: Vec<Peripheral>,
    }

    struct Peripheral {
        name: String,
        version:Option<String>,
        description:Option<String>,
        groupName:Option<String>,
        prependToName:Option<String>,
        baseAddress:Option<String>,
        access:Option<String>,
        interrupt:Option<Interrupt>,
        registers: Vec<Register>,
    }

    struct Interrupt {
        name: String,
        value:Option<uint>,
    }

    struct Register {
        name: String,
        dim:Option<uint>,
        dimIncrement:Option<String>,
        description:Option<String>,
        addressOffset:Option<String>,
        size:Option<uint>,
        access:Option<String>,
        fields: Vec<Field>,
    }

    struct Field {
        name: String,
        description:Option<String>,
        bitOffset:Option<uint>,
        bitWidth:Option<uint>,
        access:Option<String>,
        enumeratedValues: Vec<EnumeratedValue>,
    }

    struct EnumeratedValue {
        name: String,
        value: String,
        description:Option<String>,
    }

    struct CPU {
        name:Option<String>,
        revision:Option<String>,
    }
}

fn write_doc_comment(doc: Option<&String>) {
    if let Some(d) = doc {
        print!(" //= {}", d);
    }
}

fn write_device(device: &Device) {
    for peripheral in device.peripherals.iter() {
        write_peripheral(peripheral);
    }
}

fn write_peripheral(peripheral: &Peripheral) {
    println!("ioregs!({} = {{", peripheral.name);
    for register in peripheral.registers.iter() {
        write_register(register);
    }
    println!("}}")
}

fn write_register(register: &Register) {
    let offset = register.addressOffset.as_ref().map_or("", |x| x.as_slice());
    let size = register.size.unwrap_or(0);
    print!("    {} => reg{} {} {{", offset, size, register.name);
    write_doc_comment(register.description.as_ref());
    print!("\n");

    for field in register.fields.iter() {
        write_field(field);
    }
    println!("    }}");
}

fn write_field(field: &Field) {
    let lsb = field.bitOffset.unwrap();
    let width = field.bitWidth.unwrap();

    print!("         {}", lsb);

    if width > 1 {
        print!("..{}", lsb + width - 1);
    }

    print!(" => {}", field.name);

    if field.enumeratedValues.len() == 0 {
        print!(",");
    } else {
        print!(" {{");
    }

    write_doc_comment(field.description.as_ref());
    print!("\n");

    if field.enumeratedValues.len() != 0 {
        for en in field.enumeratedValues.iter() {
            if en.name.len() == 0 { continue } // TODO: this is a <name>, not an <enumeratedValues>
            print!("             {} => {}", en.name, en.value);
            write_doc_comment(en.description.as_ref());
            print!("\n");
        }
        println!("         }}");
    }
}

fn main() {
    let file = File::open(&Path::new("file.xml")).unwrap();
    let reader = BufferedReader::new(file);

    let mut parser = EventReader::new(reader);
    let mut iter = parser.events();
    let device: Device = parse_root(&mut iter).unwrap();

    write_device(&device);
}
<|endoftext|>


<commit_before>#![feature(slice_patterns)]
#![feature(convert)]

extern crate yaml;
extern crate term;

use std::io::prelude::*;
use std::io::BufReader;
use std::fs::File;
use std::fmt;
use std::env;
use std::ascii::{AsciiExt, OwnedAsciiExt};

use yaml::constructor::*;
use yaml::constructor::YamlStandardData::{YamlMapping, YamlString, YamlInteger};

struct Season {
    num: isize,
    matches: Vec<Match>,
}

impl Season {
    fn new(num: isize, matches: Vec<Match>) -> Season {
        Season { num: num, matches: matches }
    }

    fn winrate(&self) -> f32 {
        let wins: Vec<&Match> = self.matches.iter()
            .filter(|m| m.result == MatchResult::Win).collect();

        let total   = self.matches.len() as f32;
        let winrate = (wins.len() as f32) / total * 100.0;

        winrate
    }

    fn winrate_by_deck(&self, name: &String, class: &String) -> f32 {
        let deck = lowercase(&format!("{} {}", name, class));

        let dms: Vec<&Match> = self.matches.iter()
            .filter(|m| lowercase(&m.deck) == deck).collect();

        let wins: Vec<&&Match> = dms.iter()
            .filter(|m| m.result == MatchResult::Win).collect();

        let total   = dms.len() as f32;
        let winrate = (wins.len() as f32) / total * 100.0;

        winrate
    }
}

struct Match {
    id: isize,
    deck: String,
    opponent: String,
    result: MatchResult,
    kind: MatchType,
}

impl Match {
    fn new(id: isize) -> Match {
        Match { id: id,
                deck: String::new(),
                opponent: String::new(),
                result: MatchResult::Win,
                kind: MatchType::Casual }
    }
}

impl fmt::Display for Season {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        //let mut result = vec![];
        writeln!(f, "{}", format!("Season {}", self.num));
        let mut t = term::stdout().unwrap();

        for m in &self.matches {
            if (m.result == MatchResult:: Win) {
                t.fg(term::color::GREEN).unwrap();
            } else {
                t.fg(term::color::RED).unwrap();
            }
            //result.push(
            writeln!(f, "{}",
                format!(" {}) {} vs {} \t\t{}",
                    m.id, m.deck, m.opponent, m.kind));

            t.reset().unwrap();
        }

        writeln!(f, "{}", "")
        //.reset().unwrap();
    }
}

#[derive(PartialEq, Eq)]
enum MatchResult {
    Win,
    Loss,
}

impl fmt::Display for MatchResult {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let s = match self {
            &MatchResult::Win  => "Win",
            &MatchResult::Loss => "Loss",
        };

        write!(f, "{}", s)
    }
}

enum MatchType {
    Ranked,
    Casual,
    Friendly,
}

impl fmt::Display for MatchType {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let s = match self {
            &MatchType::Ranked   => "Rankend",
            &MatchType::Casual   => "Casual",
            &MatchType::Friendly => "Friendly",
        };

        write!(f, "{}", s)
    }
}

fn parse_seasons(map: &Vec<(YamlStandardData, YamlStandardData)>) -> Result<Vec<Season>, &'static str> {
    let mut seasons: Vec<Season> = Vec::new();

    match map.as_slice() {
        [(YamlString(ref name), YamlMapping(ref map))] => {
            let mut matches: Vec<Match>  = Vec::new();

            for m in map.as_slice() {

                match m {
                    &(YamlInteger(ref id), YamlMapping(ref content)) =>
                        matches.push(parse_match(*id, content).unwrap()),

                    _ => continue,
                }
            }

            let s_name = name.to_string();
            let temp: Vec<&str> = s_name.split(' ').collect();
            let season_num = temp[1].to_string().parse::<isize>().unwrap();

            seasons.push(Season::new(season_num, matches));
            Ok(seasons)
        },

        _ => Err("Error"),
    }
}

fn lowercase(s: &String) -> String {
    s.chars().map(|c| c.to_lowercase().next().unwrap()).collect::<String>()
}

fn capitalize(s: &String) -> String {
    s.chars().enumerate()
        .map(|(i, c)| if (i == 0) {
                c.to_uppercase().next().unwrap()
            } else {
                c.to_lowercase().next().unwrap()
            } ).collect::<String>()
}

fn parse_match(id: isize, map: &Vec<(YamlStandardData, YamlStandardData)>) -> Result<Match, &'static str> {
    let mut m = Match::new(id);

    for e in map.as_slice() {
        match e {
            &(YamlString(ref key), YamlString(ref value)) =>

                match key.as_str() {
                    "deck"     => m.deck = value.trim().to_string(),
                    "opponent" => m.opponent = value.trim().to_string(),
                    "result"   =>
                        match value.as_str() {
                            "Win"  => m.result = MatchResult::Win,
                            "Loss" => m.result = MatchResult::Loss,
                            _      => continue,
                        },
                    "type"     =>
                        match value.as_str() {
                            "Ranked"   => m.kind = MatchType::Ranked,
                            "Casual"   => m.kind = MatchType::Casual,
                            "Friendly" => m.kind = MatchType::Friendly,
                            _          => continue,
                        },
                    _ => continue,
                },

            _ => continue
        }
    }

    Ok(m)
}

fn parse(data: Vec<YamlStandardData>) -> Result<Vec<Season>, &'static str> {
    for doc in data.iter() {
        match doc {
            &YamlMapping(ref map) => return parse_seasons(map),

            _ => return Err("No docs"),
        }
    }

    Err("No docs")
}

fn main() {
    let path = "/Users/Gabriele/Dropbox/hearthstone.yaml";

    let mut reader = BufReader::new(File::open(path).unwrap());
    let data = yaml::parse_io_utf8(&mut reader).unwrap();

    let seasons = parse(data);

    for s in seasons.unwrap() {
        println!("{}", s);

        if (env::args().count() == 3) {
            let name  = env::args().nth(1).unwrap();
            let class = env::args().nth(2).unwrap();

            println!("{} {} Winrate: {}%", capitalize(&name),
                capitalize(&class), s.winrate_by_deck(&name, &class));
        }

        println!("Total Winrate: {}%", s.winrate());
    }

}
<commit_msg>added options<commit_after>#![feature(advanced_slice_patterns, slice_patterns, convert)]

extern crate argparse;
extern crate yaml;
extern crate term;

use std::io::prelude::*;
use std::io::BufReader;
use std::fs::File;
use std::fmt;
use std::env;

use yaml::constructor::*;
use yaml::constructor::YamlStandardData::{YamlMapping, YamlString, YamlInteger};

use std::process::exit;
use argparse::{ArgumentParser, StoreTrue, Store, List};

struct Season {
    num: isize,
    matches: Vec<Match>,
}

impl Season {
    fn new(num: isize, matches: Vec<Match>) -> Season {
        Season { num: num, matches: matches }
    }

    fn winrate(&self) -> f32 {
        let wins: Vec<&Match> = self.matches.iter()
            .filter(|m| m.result == MatchResult::Win).collect();

        let total   = self.matches.len() as f32;
        let winrate = (wins.len() as f32) / total * 100.0;

        winrate
    }

    fn winrate_by_deck(&self, name: &String, class: &String) -> f32 {
        let deck = lowercase(&format!("{} {}", name, class));

        let dms: Vec<&Match> = self.matches.iter()
            .filter(|m| lowercase(&m.deck) == deck).collect();

        let wins: Vec<&&Match> = dms.iter()
            .filter(|m| m.result == MatchResult::Win).collect();

        let total   = dms.len() as f32;
        let winrate = (wins.len() as f32) / total * 100.0;

        winrate
    }
}

struct Match {
    id: isize,
    deck: String,
    opponent: String,
    result: MatchResult,
    kind: MatchType,
}

impl Match {
    fn new(id: isize) -> Match {
        Match { id: id,
                deck: String::new(),
                opponent: String::new(),
                result: MatchResult::Win,
                kind: MatchType::Casual }
    }
}

impl fmt::Display for Season {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        writeln!(f, "{}", format!("Season {}", self.num));
        let mut t = term::stdout().unwrap();

        for m in &self.matches {
            if m.result == MatchResult:: Win {
                t.fg(term::color::GREEN).unwrap();
            } else {
                t.fg(term::color::RED).unwrap();
            }
            writeln!(f, "{}",
                format!(" {}) {} vs {} \t\t{}",
                    m.id, m.deck, m.opponent, m.kind));

            t.reset().unwrap();
        }

        writeln!(f, "{}", "")
    }
}

#[derive(PartialEq, Eq)]
enum MatchResult {
    Win,
    Loss,
}

impl fmt::Display for MatchResult {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let s = match self {
            &MatchResult::Win  => "Win",
            &MatchResult::Loss => "Loss",
        };

        write!(f, "{}", s)
    }
}

enum MatchType {
    Ranked,
    Casual,
    Friendly,
}

impl fmt::Display for MatchType {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let s = match self {
            &MatchType::Ranked   => "Rankend",
            &MatchType::Casual   => "Casual",
            &MatchType::Friendly => "Friendly",
        };

        write!(f, "{}", s)
    }
}

fn parse_seasons(map: &Vec<(YamlStandardData, YamlStandardData)>) -> Result<Vec<Season>, &'static str> {
    let mut seasons: Vec<Season> = Vec::new();

    match map.as_slice() {
        [(YamlString(ref name), YamlMapping(ref map))] => {
            let mut matches: Vec<Match>  = Vec::new();

            for m in map.as_slice() {

                match m {
                    &(YamlInteger(ref id), YamlMapping(ref content)) =>
                        matches.push(parse_match(*id, content).unwrap()),

                    _ => continue,
                }
            }

            let s_name = name.to_string();
            let temp: Vec<&str> = s_name.split(' ').collect();
            let season_num = temp[1].to_string().parse::<isize>().unwrap();

            seasons.push(Season::new(season_num, matches));
            Ok(seasons)
        },

        _ => Err("Error"),
    }
}

fn lowercase(s: &String) -> String {
    s.chars().map(|c| c.to_lowercase().next().unwrap()).collect::<String>()
}

fn capitalize(s: &String) -> String {
    s.chars().enumerate()
        .map(|(i, c)| if (i == 0) {
                c.to_uppercase().next().unwrap()
            } else {
                c.to_lowercase().next().unwrap()
            }).collect::<String>()
}

fn parse_match(id: isize, map: &Vec<(YamlStandardData, YamlStandardData)>) -> Result<Match, &'static str> {
    let mut m = Match::new(id);

    for e in map.as_slice() {
        match e {
            &(YamlString(ref key), YamlString(ref value)) =>

                match key.as_str() {
                    "deck"     => m.deck = value.trim().to_string(),
                    "opponent" => m.opponent = value.trim().to_string(),
                    "result"   =>
                        match value.as_str() {
                            "Win"  => m.result = MatchResult::Win,
                            "Loss" => m.result = MatchResult::Loss,
                            _      => continue,
                        },
                    "type"     =>
                        match value.as_str() {
                            "Ranked"   => m.kind = MatchType::Ranked,
                            "Casual"   => m.kind = MatchType::Casual,
                            "Friendly" => m.kind = MatchType::Friendly,
                            _          => continue,
                        },
                    _ => continue,
                },

            _ => continue
        }
    }

    Ok(m)
}

fn parse(data: Vec<YamlStandardData>) -> Result<Vec<Season>, &'static str> {
    for doc in data.iter() {
        match doc {
            &YamlMapping(ref map) => return parse_seasons(map),

            _ => return Err("No docs"),
        }
    }

    Err("No docs")
}

fn main() {
    let path = "hearthstone.yaml";

    let mut args: Vec<String> = Vec::new();

    {
        let mut ap = ArgumentParser::new();
        ap.set_description("Calc HS stats");
        ap.refer(&mut args)
            .add_argument("args", List,
                          "Deck to calc winrate for");
        ap.parse_args_or_exit();
    }

    let mut reader = BufReader::new(File::open(path).unwrap());
    let data = yaml::parse_io_utf8(&mut reader).unwrap();

    let seasons = parse(data).unwrap();

    if args.len() >= 1 {
        let season = seasons.last().unwrap();

        match args[0].as_str() {
            "deck" => {
                let deck   = &args[1..3];
                let name   = deck[0].to_string();
                let class  = deck[1].to_string();

                println!("{} {} Winrate: {}%", capitalize(&name),
                    capitalize(&class), season.winrate_by_deck(&name, &class));
            },

            "show" => {
                print!("{}", season);
                println!("Total Winrate: {}%", season.winrate());
            },

            _ => println!("Command unknown"),
        }
    }
}
<|endoftext|>


<commit_before>extern crate piston_window;

mod entity;

use piston_window::*;
use entity::Entity;
use std::time::SystemTime;

#[derive(Debug, Clone)]
pub struct Point(f64, f64);

const MU: f64 = 0.99;
const WIDTH: u32 = 1024;
const HEIGHT: u32 = 800;
const WAIT_TIME: u32 = 300_000_000; //nanoseconds

fn main() {
    let title = "Goober";
    let mut inputs_submitted = false;
    let mut inputs = Vec::new();
    let mut timestamp = SystemTime::now();
    let mut i: usize = 0;
    let mut goobs = vec![
        Entity::new(Point(0.0, 0.0), [0.3, 0.0, 0.7, 0.5], 25.0, 25.0)
    ];

    let mut window: PistonWindow = WindowSettings::new(title, [WIDTH, HEIGHT])
        .exit_on_esc(true)
        .build()
        .unwrap_or_else(|e| panic!("Failed to build PistonWindow: {}", e));

    let sprite_path = "./assets/green-blob-hi.png";
    let sprite = Texture::from_path(
            &mut window.factory,
            &sprite_path,
            Flip::None,
            &TextureSettings::new())
            .unwrap();

    let font = "assets/FiraSans-Regular.ttf";
    let factory = window.factory.clone();
    let mut glyphs = Glyphs::new(font, factory).unwrap();

    while let Some(e) = window.next() {

        if let Some(_) = e.render_args() {
            window.draw_2d(&e, |c, g| {
                clear([0.8, 0.0, 0.8, 1.0], g);
                for goob in &goobs {
                    image(&sprite, c.transform.trans(goob.geometry()[0], goob.geometry()[1]), g);
                }

                text::Text::new_color([0.0, 1.0, 0.0, 1.0], 16).draw(
                    &format_inputs(&inputs),
                    &mut glyphs,
                    &c.draw_state,
                    c.transform.trans(40.0, 40.0), g
                );
            });
        }

        if let Some(button) = e.press_args() {
            if !inputs_submitted {
                match button {
                    Button::Keyboard(Key::Up)     |
                    Button::Keyboard(Key::Down)   |
                    Button::Keyboard(Key::Left)   |
                    Button::Keyboard(Key::Right)  |
                    Button::Keyboard(Key::Space)  |
                    Button::Keyboard(Key::A)      => inputs.push(button),
                    Button::Keyboard(Key::Return) => {inputs_submitted = true; inputs.reverse()},
                    _ => ()
                }
            }
        }

        if let Some(_) = e.update_args() {
            if inputs_submitted && wait_time_elapsed(timestamp) {
                timestamp = SystemTime::now();
                if let Some(button) = inputs.pop() { handle_input(button, &mut goobs, &mut i); }
            } else if inputs.is_empty() {
                inputs_submitted = false;
            }
            for goob in &mut goobs {
                goob.nudge();
            }
        }
    }

    fn handle_input(button: Button, goobs: &mut Vec<Entity>, i: &mut usize) {
        match button {
            Button::Keyboard(Key::Up)     => goobs[*i].adjust_dy(-1.0),
            Button::Keyboard(Key::Down)   => goobs[*i].adjust_dy(1.0),
            Button::Keyboard(Key::Left)   => goobs[*i].adjust_dx(-1.0),
            Button::Keyboard(Key::Right)  => goobs[*i].adjust_dx(1.0),
            Button::Keyboard(Key::Space)  => if *i == goobs.len() - 1 { *i = 0 } else { *i += 1 },
            Button::Keyboard(Key::A)      => {
                let new_position = Point(goobs[*i].geometry()[0], goobs[*i].geometry()[1]);
                goobs.push(
                    Entity::new(
                    new_position,
                    [0.3, 0.0, 0.7, 0.5],
                    25.0, 25.0
                    )
                );
            }
            _ => ()
        }
    }

    fn wait_time_elapsed(timestamp: SystemTime) -> bool {
        match timestamp.elapsed() {
            Ok(elapsed) => elapsed.subsec_nanos() >= WAIT_TIME,
            Err(e) => {println!("{:?}", e); false}
        }
    }

    fn format_inputs(inputs: &[Button]) -> String {
        inputs.iter().map(|button|
            match *button {
                Button::Keyboard(Key::Up)    => "↑",
                Button::Keyboard(Key::Down)  => "↓",
                Button::Keyboard(Key::Left)  => "←",
                Button::Keyboard(Key::Right) => "→",
                Button::Keyboard(Key::Space) => "↔",
                Button::Keyboard(Key::A)     => "+",
                _ => ""
            }
        ).collect::<Vec<_>>().concat()
    }
}
<commit_msg>Stop passing around Buttons as inputs<commit_after>extern crate piston_window;

mod entity;

use piston_window::*;
use entity::Entity;
use std::time::SystemTime;
use std::fmt;

#[derive(Debug, Clone)]
pub struct Point(f64, f64);

const MU: f64 = 0.99;
const WIDTH: u32 = 1024;
const HEIGHT: u32 = 800;
const WAIT_TIME: u32 = 300_000_000; //nanoseconds

fn main() {
    let title = "Goober";
    let mut inputs_submitted = false;
    let mut inputs = Vec::new();
    let mut timestamp = SystemTime::now();
    let mut i: usize = 0;
    let mut goobs = vec![
        Entity::new(Point(0.0, 0.0), [0.3, 0.0, 0.7, 0.5], 25.0, 25.0)
    ];

    let mut window: PistonWindow = WindowSettings::new(title, [WIDTH, HEIGHT])
        .exit_on_esc(true)
        .build()
        .unwrap_or_else(|e| panic!("Failed to build PistonWindow: {}", e));

    let sprite_path = "./assets/green-blob-hi.png";
    let sprite = Texture::from_path(
            &mut window.factory,
            &sprite_path,
            Flip::None,
            &TextureSettings::new())
            .unwrap();

    let font = "assets/FiraSans-Regular.ttf";
    let factory = window.factory.clone();
    let mut glyphs = Glyphs::new(font, factory).unwrap();

    while let Some(e) = window.next() {

        if let Some(_) = e.render_args() {
            window.draw_2d(&e, |c, g| {
                clear([0.8, 0.0, 0.8, 1.0], g);
                for goob in &goobs {
                    image(&sprite, c.transform.trans(goob.geometry()[0], goob.geometry()[1]), g);
                }

                text::Text::new_color([0.0, 1.0, 0.0, 1.0], 16).draw(
                    &format_inputs(&inputs),
                    &mut glyphs,
                    &c.draw_state,
                    c.transform.trans(40.0, 40.0), g
                );
            });
        }

        if let Some(button) = e.press_args() {
            if !inputs_submitted {
                match button {
                    Button::Keyboard(Key::Up)     => inputs.push(Action::Up),
                    Button::Keyboard(Key::Down)   => inputs.push(Action::Down),
                    Button::Keyboard(Key::Left)   => inputs.push(Action::Left),
                    Button::Keyboard(Key::Right)  => inputs.push(Action::Right),
                    Button::Keyboard(Key::Space)  => inputs.push(Action::Swap),
                    Button::Keyboard(Key::A)      => inputs.push(Action::Spawn),
                    Button::Keyboard(Key::Return) => {inputs_submitted = true; inputs.reverse()},
                    _ => ()
                }
            }
        }

        if let Some(_) = e.update_args() {
            if inputs_submitted && wait_time_elapsed(timestamp) {
                timestamp = SystemTime::now();
                if let Some(button) = inputs.pop() { handle_input(button, &mut goobs, &mut i); }
            } else if inputs.is_empty() {
                inputs_submitted = false;
            }
            for goob in &mut goobs {
                goob.nudge();
            }
        }
    }

    fn handle_input(action: Action, goobs: &mut Vec<Entity>, i: &mut usize) {
        match action {
            Action::Up     => goobs[*i].adjust_dy(-1.0),
            Action::Down   => goobs[*i].adjust_dy(1.0),
            Action::Left   => goobs[*i].adjust_dx(-1.0),
            Action::Right  => goobs[*i].adjust_dx(1.0),
            Action::Swap   => if *i == goobs.len() - 1 { *i = 0 } else { *i += 1 },
            Action::Spawn  => {
                let new_position = Point(goobs[*i].geometry()[0], goobs[*i].geometry()[1]);
                goobs.push(
                    Entity::new(
                    new_position,
                    [0.3, 0.0, 0.7, 0.5],
                    25.0, 25.0
                    )
                );
            }
        }
    }

    fn wait_time_elapsed(timestamp: SystemTime) -> bool {
        match timestamp.elapsed() {
            Ok(elapsed) => elapsed.subsec_nanos() >= WAIT_TIME,
            Err(e) => {println!("{:?}", e); false}
        }
    }

    fn format_inputs(inputs: &[Action]) -> String {
        inputs.iter().cloned().map(|action| action.to_string()).collect::<Vec<_>>().concat()
    }
}

#[derive(Debug, Clone)]
pub enum Action {
    Up,
    Down,
    Left,
    Right,
    Swap,
    Spawn
}

impl fmt::Display for Action {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Action::Up    => write!(f, "↑"),
            Action::Down  => write!(f, "↓"),
            Action::Left  => write!(f, "←"),
            Action::Right => write!(f, "→"),
            Action::Swap  => write!(f, "↔"),
            Action::Spawn => write!(f, "+")
        }
    }
}
<|endoftext|>


<commit_before>#![feature(globs)]

extern crate piston;
extern crate graphics;
extern crate opengl_graphics;
extern crate sdl2_game_window;
extern crate hgl;

use Window = sdl2_game_window::GameWindowSDL2;
use graphics::*;
use piston::{
    AssetStore,
    GameIterator,
    GameIteratorSettings,
    GameWindowSettings,
    Render,
};
use opengl_graphics::{
    Gl,
    Texture,
};
use hgl::{
    Shader,
    Program,
    Triangles,
    Vbo,
    Vao,
};

pub enum MinecraftTexture {
    Grass,
}

static VERTEX_SHADER: &'static str = r"
attribute vec3 position;
attribute vec4 fill_color;
attribute vec2 tex_coord;

uniform mat4 m_projection;
uniform mat4 m_view;
uniform mat4 m_model;
uniform sampler2D s_texture;

varying vec2 v_tex_coord;
varying vec4 v_fill_color;

void main() {
    v_tex_coord = tex_coord;
    v_fill_color = fill_color;
    gl_Position = m_projection * m_view * m_model * vec4(position, 1.0);
}
";

static FRAGMENT_SHADER: &'static str = r"
uniform sampler2D s_texture;

varying vec2 v_tex_coord;
varying vec4 v_fill_color;

void main() {
    gl_FragColor = texture2D(s_texture, v_tex_coord) * v_fill_color;
}
";

static TEST_TEXTURE: MinecraftTexture = Grass;

impl MinecraftTexture {
    pub fn src_xy(&self) -> (i32, i32) {
        match *self {
            Grass => (0, 0),
        }
    }
}

fn main() {
    let mut window = Window::new(
        GameWindowSettings {
            title: "Hematite".to_string(),
            size: [640, 480],
            fullscreen: false,
            exit_on_esc: true,
        }
    );

    let asset_store = AssetStore::from_folder("assets");

    // Load texture.
    let image = asset_store.path("minecraft-texture.png").unwrap();
    let image = Texture::from_path(&image).unwrap();
    let game_iter_settings = GameIteratorSettings {
            updates_per_second: 120,
            max_frames_per_second: 60,
        };
    let ref mut gl = Gl::new();

    // Compile shaders.
    let program = Program::link([
            Shader::compile(VERTEX_SHADER, hgl::VertexShader),
            Shader::compile(FRAGMENT_SHADER, hgl::FragmentShader)
        ]).unwrap();
    program.bind();

    for e in GameIterator::new(&mut window, &game_iter_settings) {
        match e {
            Render(args) => {
                gl.viewport(0, 0, args.width as i32, args.height as i32);

                let c = Context::abs(args.width as f64, args.height as f64);
                c.rgb(0.0, 0.0, 0.0).draw(gl);
                let (src_x, src_y) = TEST_TEXTURE.src_xy();
                c
                    .image(&image)
                    .src_rect(src_x * 16, src_y * 16, 16, 16)
                    .draw(gl);
            },
            _ => {}
        }
    }
}
<commit_msg>Added cube vertices<commit_after>#![feature(globs)]

extern crate piston;
extern crate graphics;
extern crate opengl_graphics;
extern crate sdl2_game_window;
extern crate hgl;

use Window = sdl2_game_window::GameWindowSDL2;
use graphics::*;
use piston::{
    AssetStore,
    GameIterator,
    GameIteratorSettings,
    GameWindowSettings,
    Render,
};
use opengl_graphics::{
    Gl,
    Texture,
};
use hgl::{
    Shader,
    Program,
    Triangles,
    Vbo,
    Vao,
};

pub enum MinecraftTexture {
    Grass,
}

static VERTEX_SHADER: &'static str = r"
attribute vec3 position;
attribute vec3 fill_color;
attribute vec2 tex_coord;

uniform mat4 m_projection;
uniform mat4 m_view;
uniform mat4 m_model;
uniform sampler2D s_texture;

varying vec2 v_tex_coord;
varying vec4 v_fill_color;

void main() {
    v_tex_coord = tex_coord;
    v_fill_color = vec4(fill_color, 1.0);
    gl_Position = m_projection * m_view * m_model * vec4(position, 1.0);
}
";

static FRAGMENT_SHADER: &'static str = r"
uniform sampler2D s_texture;

varying vec2 v_tex_coord;
varying vec4 v_fill_color;

void main() {
    gl_FragColor = texture2D(s_texture, v_tex_coord) * v_fill_color;
}
";

static TEST_TEXTURE: MinecraftTexture = Grass;

impl MinecraftTexture {
    pub fn src_xy(&self) -> (i32, i32) {
        match *self {
            Grass => (0, 0),
        }
    }
}

fn main() {
    let mut window = Window::new(
        GameWindowSettings {
            title: "Hematite".to_string(),
            size: [640, 480],
            fullscreen: false,
            exit_on_esc: true,
        }
    );

    let asset_store = AssetStore::from_folder("assets");

    // Load texture.
    let image = asset_store.path("minecraft-texture.png").unwrap();
    let image = Texture::from_path(&image).unwrap();
    let game_iter_settings = GameIteratorSettings {
            updates_per_second: 120,
            max_frames_per_second: 60,
        };
    let ref mut gl = Gl::new();

    // Compile shaders.
    let program = Program::link([
            Shader::compile(VERTEX_SHADER, hgl::VertexShader),
            Shader::compile(FRAGMENT_SHADER, hgl::FragmentShader)
        ]).unwrap();
    program.bind();

    /*
            2  --------- 3
              /       / |
             /       /  |
         7  -------- 6  | 1
           |        |  /
           |        | /
           |        |/
         4  -------- 5

           ---- ---- ---- ----
          |    |    |    |    |
          |    |    |    |    |
           ---- ---- ---- ----
    */

    let cube_quads = vec![
        4u, 5, 6, 7,
        5, 1, 3, 6,
        1, 0, 2, 3,
        0, 4, 7, 2,
        7, 6, 3, 2,
        0, 1, 5, 4,
    ];

    // Cube vertices.
    let cube_vertices = [
        // This is the back surface
        -1.0f32,    -1.0,       1.0, // 0
         1.0,       -1.0,       1.0, // 1
         1.0,        1.0,       1.0, // 2
        -1.0,        1.0,       1.0, // 3

        // This is the front surface
        -1.0,       -1.0,      -1.0, // 4
         1.0,       -1.0,      -1.0, // 5
         1.0,        1.0,      -1.0, // 6
        -1.0,        1.0,      -1.0  // 7
    ];

    /*
    // Initialize a vertex array buffer with the cube vertices.
    let vao = Vao::new();
    vao.bind();
    vao.enable_attrib(&program, "position", gl::FLOAT, 3, 3 * size_of::<f32>() as i32, 0);
    cube_vbo.bind();

    // vao.enable_attrib(&program, "fill_color", gl::FLOAT, 3, 3 * size_of::<f32>() as i32, 0);
    // vao.enable_attrib(&program, "tex_coord", gl::FLOAT, 2, 2 * size_of::<f32>() as i32, 0);
    */

    for e in GameIterator::new(&mut window, &game_iter_settings) {
        match e {
            Render(args) => {
                gl.viewport(0, 0, args.width as i32, args.height as i32);

                let c = Context::abs(args.width as f64, args.height as f64);
                c.rgb(0.0, 0.0, 0.0).draw(gl);
                let (src_x, src_y) = TEST_TEXTURE.src_xy();
                c
                    .image(&image)
                    .src_rect(src_x * 16, src_y * 16, 16, 16)
                    .draw(gl);
            },
            _ => {}
        }
    }
}
<|endoftext|>


<commit_before>extern crate argparse;

use std::io::prelude::*;
use std::io::BufReader;
use std::fs::File;

use argparse::{ArgumentParser, Store};

#[derive(Debug)]
enum SatError {
    InvalidSyntax
}

fn parse_dimacs(reader: &mut BufReader<std::fs::File>) -> Result<String, SatError> {
    for line in reader.lines() {
        let line = line.expect("Could not read file");
        match &line[..2] {
            "c " => println!("Comment"), // Comment, ignore
            "p " => println!("Problem statement"), // Problem statement
            _    => return Err(SatError::InvalidSyntax)
        }
    }
    Ok("No errors".into())
}

fn main() {
    let mut filename = "".to_string();
    {  // this block limits scope of borrows by ap.refer() method
        let mut ap = ArgumentParser::new();
        ap.set_description("Satyrs: A lustful, drunken SAT solver");
        ap.refer(&mut filename)
            .add_argument(
                "filename",
                Store,
                "SAT filename to read"
            ).required();
        ap.parse_args_or_exit();
    }

    // Read the file
    let f = File::open(filename)
        .expect("Could not open file");
    let mut reader = BufReader::new(f);

    // TODO: This is definitely not the correct way to handle errors
    let line = parse_dimacs(&mut reader).expect("Parse error");

    println!("{}", line)
}
<commit_msg>Some better stylistic decisions<commit_after>extern crate argparse;

use std::io::prelude::*;
use std::io::BufReader;
use std::fs::File;

use argparse::{ArgumentParser, Store};

#[derive(Debug)]
enum SatError {
    InvalidSyntax
}

fn parse_dimacs(reader: &mut BufReader<std::fs::File>) -> Result<String, SatError> {
    for line in reader.lines() {
        let line = line.expect("Could not read file");
        // TODO: Will panic if line length < 2 chars. Split on whitespace instead
        match &line[..2] {
            "c " => println!("Comment"), // Comment, ignore
            "p " => println!("Problem statement"), // Problem statement
            _    => return Err(SatError::InvalidSyntax)
        }
    }
    Ok(String::from("No errors"))
}

fn main() {
    let mut filename = String::new();
    {  // this block limits scope of borrows by ap.refer() method
        let mut ap = ArgumentParser::new();
        ap.set_description("Satyrs: A lustful, drunken SAT solver");
        ap.refer(&mut filename)
            .add_argument(
                "filename",
                Store,
                "SAT filename to read")
            .required();
        ap.parse_args_or_exit();
    }

    // Read the file
    let f = File::open(filename)
        .expect("Could not open file");
    let mut reader = BufReader::new(f);

    // TODO: This is definitely not the correct way to handle errors
    let line = parse_dimacs(&mut reader)
        .expect("Parse error");

    println!("{}", line);
}
<|endoftext|>


<commit_before>#![feature(old_io)]
use std::old_io;
//static ITERATIONS: u16 = 5000;
static DEFAULT_GRID: u8 = 10;

enum PlayerType {
	AI,
	Human
}

struct Player {
	name: String,
	num: u8,
	player_type: PlayerType
}

fn main() {
	let mut stdin = old_io::stdin();
	//Choose the grid size
	println!("First, please answer to some questions...");
	println!("Please give us grid size :");
	let grid_input = stdin.lock().lines().next().unwrap().ok().unwrap();
	let grid_size: u8 = match grid_input.trim().parse::<u8>() {
			Ok(0) => DEFAULT_GRID,
			Ok(x) => x,
			Err(_) => DEFAULT_GRID
		};
	//Build the grid
	let mut grid: Vec<Vec<u8>> = generate_grid(grid_size);
	println!("Your grid have now a size of {size}", size = grid_size);

	let players: [Player; 2] = [get_a_player(&mut stdin, 1), get_a_player(&mut stdin, 2)];
	//game loop
	let mut turn : u32 = 0;

	loop {
		print_grid(&grid);
		if has_winner_path(&grid, 1) {
			println!("Congratulations, {}, you've won.", players[0].name);
			break;
		} else if has_winner_path(&grid, 2) {
			println!("Congratulations, {}, you've won.", players[1].name);
			break;
		}
		let player : &Player = &players[(turn % 2)  as usize];
		let player_status = match player.player_type {
			PlayerType::AI => "AI",
			PlayerType::Human => "Human"
		};
		println!("It's your turn (turn {turn}), {player} ({status})", turn = turn + 1, player = player.name, status = player_status);
		match player.player_type {
			PlayerType::AI => {
//				let position: [u8; 2] =
			},
			PlayerType::Human => {
				let position_x: u8 = get_a_position(&mut stdin, grid_size, "X".to_string());
				let position_y: u8 = get_a_position(&mut stdin, grid_size, "Y".to_string());
				if is_free_cell(&grid, position_x, position_y) {
					edit_grid(&mut grid, player.num, position_x, position_y);
					turn = turn + 1;
				} else {
					println!("This cell is not free");
				}
			}
		};
	}
}

fn get_a_player(stdin: &mut std::old_io::stdio::StdinReader, player_num: u8) -> Player {
	println!("Please, give us a name for player {}", player_num);
	let grid_input = stdin.lock().lines().next().unwrap().ok().unwrap();
	let name = grid_input.trim();
	let player_type: PlayerType;
	loop {
		println!("{} will be human ? (yes/no)", name);
		let grid_input = stdin.lock().lines().next().unwrap().ok().unwrap();
		match grid_input.trim() {
				"yes" => { player_type = PlayerType::Human; break; },
				"no" => { player_type = PlayerType::AI; break;},
				_ => {continue;}
			};
	};
	return Player { num: player_num, name: name.to_string(), player_type: player_type};
}

fn get_a_position(stdin: &mut std::old_io::stdio::StdinReader, max_value_plus_one: u8, axe: String) -> u8 {
	let position: u8;
	loop {
		println!("Give us {} position", axe);
		let grid_input = stdin.lock().lines().next().unwrap().ok().unwrap();
		match grid_input.trim().parse::<u8>() {
			Ok(x) if x < max_value_plus_one => { position = x; break; },
			Ok(_) => {continue;},
			Err(_) => {continue;}
		};
	};
	return position;
}

//For performances considerations, sides can't be > to 255.
fn generate_grid(side_length: u8) -> Vec<Vec<u8>> {
	let mut vector: Vec<Vec<u8>> = Vec::with_capacity(side_length as usize);
	for _ in 0..side_length {
		let mut vector_internal: Vec<u8> = Vec::with_capacity(side_length as usize);
		for _ in 0..side_length {
			vector_internal.push(0);
		}
		vector.push(vector_internal);
	}
	return vector;
}

fn edit_grid(grid: &mut Vec<Vec<u8>>, new_value: u8, x: u8, y: u8) {
	grid[x as usize][y as usize] = new_value;
}

fn print_grid(grid: &Vec<Vec<u8>>) {
	for x in grid.iter() {
		for y in x.iter() {
			print!(" {} ", match *y {
				0u8 => "-",
				1u8 => "B",
				2u8 => "W",
				_ => "E"
			});
		}
		print!("\n");
	}
}

fn is_free_cell(grid: &Vec<Vec<u8>>, x: u8, y: u8) -> bool {
	if grid[x as usize][y as usize] == 0u8 { true } else { false }
}

fn has_winner_path(grid: &Vec<Vec<u8>>, player: u8) -> bool {
	for i in 0u8..grid.len() as u8 {
		let vector: Vec<[u8; 2]> = Vec::new();
		let is_win: bool = match player {
			1u8 => go_to_goal(&grid, player, 0, i, &vector),
			2u8 => go_to_goal(&grid, player, i, 0, &vector),
			_ => { panic!("Incorrect player for has_winner_path"); }
		};
		if is_win {
			return true;
		}
	}
	return false;
}

fn go_to_goal(grid: &Vec<Vec<u8>>, player: u8, x: u8, y: u8, to_ignore: &Vec<[u8; 2]>) -> bool {
	if is_a_goal(&grid, player, x, y) {
		return true;
	}
	let mut to_ignore_cell = to_ignore.clone();
	to_ignore_cell.push([x, y]);

	let available_cells_close = not_visited_cells_close(&grid, player, x, y, &to_ignore_cell, true);

	for cell in available_cells_close.iter() {
		if go_to_goal(&grid, player, cell[0], cell[1], &to_ignore_cell) {
			return true;
		}
	}
	return false;
}

fn is_a_goal(grid: &Vec<Vec<u8>>, player: u8, x: u8, y: u8) -> bool{
	let max_index: u8 = grid.len() as u8 - 1;
	(player == 1 && x == max_index) || (player == 2 && y == max_index)
}

fn not_visited_cells_close(grid: &Vec<Vec<u8>>, player: u8, x: u8, y: u8, visited: &Vec<[u8; 2]>, focus_on_player: bool) -> Vec<[u8; 2]> {
	let cells_close: Vec<[u8; 2]> = available_cells_close(&grid, player, x, y, focus_on_player);
	let mut not_visited_cells_close: Vec<[u8; 2]> = Vec::with_capacity(cells_close.len());

	for cell in cells_close.iter() {
		if !has_pos_in_vector(&visited, *cell) {
			not_visited_cells_close.push(*cell);
		}
	}
	return not_visited_cells_close;
}

fn has_pos_in_vector(positions: &Vec<[u8; 2]>, search: [u8; 2]) -> bool {
	for pos in positions.iter() {
		if search == *pos {
			return true;
		}
	}
	return false;
}

fn revert_player(player: u8) -> u8 {
	if player == 1 { 2 } else if player == 2 { 1 } else { 0 }
}

fn available_cells_close(grid: &Vec<Vec<u8>>, player: u8, x: u8, y: u8, focus_on_player: bool) -> Vec<[u8; 2]> {
	let cells_close: Vec<[u8; 2]> = cells_close(&grid, x, y);
	let mut available_cells_close: Vec<[u8; 2]> = Vec::with_capacity(cells_close.len());

	let opp_player = revert_player(player);

	for cell in cells_close.iter() {
		let grid_value: u8 = grid[cell[0] as usize][cell[1] as usize];
		if (grid_value != opp_player && !focus_on_player) || (grid_value != opp_player && grid_value != 0)  {
			available_cells_close.push(*cell);
		}
	}
	return available_cells_close;
}

fn cells_close(grid: &Vec<Vec<u8>>, x: u8, y: u8) -> Vec<[u8; 2]> {
	let mut cells_values: Vec<[u8; 2]> = Vec::with_capacity(8);
	let grid_length: u8 = grid.len() as u8;
	let relative_positions: [[i8; 2]; 8] = [
		[-1, -1],	[-1, 0],	[-1, 1],
		[0, -1], 	/*0,0*/		[0, 1],
		[1, -1],	[1, 0],		[1, 1]];
	for relative_position in relative_positions.iter() {
		let new_i_x = x as i8 + relative_position[0];
		if new_i_x < 0 || new_i_x >= grid_length as i8 {
			continue;
		}
		let new_x = new_i_x as u8;

		let new_i_y = y as i8 + relative_position[1];
		if new_i_y < 0 || new_i_y >= grid_length as i8 {
			continue;
		}
		let new_y = new_i_y as u8;
		cells_values.push([new_x, new_y]);
	}
	return cells_values;
}

/*************************/
#[test]
#[should_fail]
fn test_two_grids_shuffled_must_not_be_equals() {
	let grid: Vec<Vec<u8>> = generate_grid(10u8);
	assert_eq!(get_shuffled_free_cells(&grid), get_shuffled_free_cells(&grid));
}

#[test]
fn test_winned_game() {
	let mut grid1: Vec<Vec<u8>> = generate_grid(10u8);
	let mut grid2: Vec<Vec<u8>> = generate_grid(10u8);
	for i in 0u8..10 {
		edit_grid(&mut grid1, 1, i, 0);
		edit_grid(&mut grid2, 2, 0, i);
	}
	assert!(has_winner_path(&grid1, 1));
	assert!(has_winner_path(&grid2, 2));
}

#[test]
#[should_fail]
fn test_not_winned_game() {
	let mut grid: Vec<Vec<u8>> = generate_grid(10u8);
	for i in 0u8..grid.len() as u8 {
		edit_grid(&mut grid, i % 2 + 1, 0, i);
	}
	assert!(has_winner_path(&grid, 1));
	assert!(has_winner_path(&grid, 2));
}

#[test]
fn test_cells_close() {
	let grid: Vec<Vec<u8>> = generate_grid(10u8);
	//Corner left top, only 3 cells are available
	assert_eq!(cells_close(&grid, 0, 0).len(), 3);
	//Corner right bottom, only 3 cells are available
	assert_eq!(cells_close(&grid, 9, 9).len(), 3);
	//Corner close to center, 8 cells are available
	assert_eq!(cells_close(&grid, 4, 4).len(), 8);
}
<commit_msg>working, but not efficient<commit_after>#![feature(old_io)]
use std::old_io;
//static ITERATIONS: u16 = 5000;
static DEFAULT_GRID: u8 = 10;

enum PlayerType {
	AI,
	Human
}

struct Player {
	name: String,
	num: u8,
	player_type: PlayerType
}

fn main() {
	let mut stdin = old_io::stdin();
	//Choose the grid size
	println!("First, please answer to some questions...");
	println!("Please give us grid size :");
	let grid_input = stdin.lock().lines().next().unwrap().ok().unwrap();
	let grid_size: u8 = match grid_input.trim().parse::<u8>() {
			Ok(0) => DEFAULT_GRID,
			Ok(x) => x,
			Err(_) => DEFAULT_GRID
		};
	//Build the grid
	let mut grid: Vec<Vec<u8>> = generate_grid(grid_size);
	println!("Your grid have now a size of {size}", size = grid_size);

	let players: [Player; 2] = [get_a_player(&mut stdin, 1), get_a_player(&mut stdin, 2)];
	//game loop
	let mut turn : u32 = 0;

	loop {
		print_grid(&grid);
		if has_winner_path(&grid, 1) {
			println!("Congratulations, {}, you've won.", players[0].name);
			break;
		} else if has_winner_path(&grid, 2) {
			println!("Congratulations, {}, you've won.", players[1].name);
			break;
		}
		let player : &Player = &players[(turn % 2)  as usize];
		let player_status = match player.player_type {
			PlayerType::AI => "AI",
			PlayerType::Human => "Human"
		};
		println!("It's your turn (turn {turn}), {player} ({status})", turn = turn + 1, player = player.name, status = player_status);
		match player.player_type {
			PlayerType::AI => {
				let shuffled_grid: Vec<[u8; 2]> = get_shuffled_free_cells(&grid);
				let mut better_position: [u8; 2] = shuffled_grid[0];
				let mut better_weight = 255;
				for try_position in shuffled_grid.iter() {
					let current_weight = get_lower_weight_for_simulation(&grid, player.num, try_position);
					if better_weight < current_weight {
						better_position = *try_position;
						better_weight = current_weight;
					}
				}
				edit_grid(&mut grid, player.num, better_position[0], better_position[1]);
			},
			PlayerType::Human => {
				let position_x: u8 = get_a_position(&mut stdin, grid_size, "X".to_string());
				let position_y: u8 = get_a_position(&mut stdin, grid_size, "Y".to_string());
				if is_free_cell(&grid, position_x, position_y) {
					edit_grid(&mut grid, player.num, position_x, position_y);
				} else {
					println!("This cell is not free");
				}
			}
		};
		turn = turn + 1;
	}
}

fn get_lower_weight_for_simulation(grid: &Vec<Vec<u8>>, player: u8, position: &[u8; 2]) -> u8 {
	let mut grid_simulated: Vec<Vec<u8>> = grid.clone();
	edit_grid(&mut grid_simulated, player, position[0], position[1]);
	let mut weight: u8 = 255;
	for i in 0u8..grid.len() as u8 {
		let vector: Vec<[u8; 2]> = Vec::new();
		let (current_weight, has_reach_the_goal) = match player {
			1u8 => get_faster_to_goal(&grid_simulated, player, 0, i, &vector),
			2u8 => get_faster_to_goal(&grid_simulated, player, i, 0, &vector),
			_ => { panic!("Incorrect player for get_lower_weight"); }
		};
		if current_weight < weight && has_reach_the_goal {
			weight = current_weight;
		}
	}
	return weight;
}

fn get_faster_to_goal(grid: &Vec<Vec<u8>>, player: u8, x: u8, y: u8, to_ignore: &Vec<[u8; 2]>) -> (u8, bool) {
	let mut path_weight: u8 = get_weight(&grid, player, x, y);

	if (is_a_goal(&grid, player, x, y)) {
		return (path_weight, true);
	}

	let mut to_ignore_cell = to_ignore.clone();
	to_ignore_cell.push([x, y]);

	let available_cells_close = not_visited_cells_close(&grid, player, x, y, &to_ignore_cell, false);

	let mut goal_reached: bool = false;
	if available_cells_close.len() != 0 {
		let mut shorter_path = 255;
		for cell in available_cells_close.iter() {
			let (faster_to_goal, reach_goal) = get_faster_to_goal(&grid, player, cell[0], cell[1], &to_ignore_cell);
			if (!reach_goal) {
				continue;
			}
			goal_reached = true;
			if faster_to_goal < shorter_path {
				shorter_path = faster_to_goal;
			}
		}
		path_weight = path_weight + shorter_path;
	}
//	println!("{:?}", available_cells_close);
	return (path_weight, goal_reached);
}

fn get_shuffled_free_cells(grid: &Vec<Vec<u8>>) -> Vec<[u8; 2]> {
	use std::rand::{thread_rng, Rng};

	let mut free_cells: Vec<[u8; 2]> = Vec::new();
	for x in 0..grid.len() {
		for y in 0..grid[0].len() {
			if is_free_cell(&grid, x as u8, y as u8) {
				free_cells.push([x as u8, y as u8]);
			}
		}
	}
	let sliced_free_cells: &mut [[u8; 2]] = free_cells.as_mut_slice();
	thread_rng().shuffle(sliced_free_cells);

	let mut sliced_shuffled_free_cells: Vec<[u8; 2]> = Vec::new();
	sliced_shuffled_free_cells.push_all(&sliced_free_cells);
	return sliced_shuffled_free_cells;
}

fn get_weight(grid: &Vec<Vec<u8>>, player: u8, x: u8, y: u8) -> u8 {
	if grid[x as usize][y as usize] == player { 0 } else { 1 }
}

fn get_a_player(stdin: &mut std::old_io::stdio::StdinReader, player_num: u8) -> Player {
	println!("Please, give us a name for player {}", player_num);
	let grid_input = stdin.lock().lines().next().unwrap().ok().unwrap();
	let name = grid_input.trim();
	let player_type: PlayerType;
	loop {
		println!("{} will be human ? (yes/no)", name);
		let grid_input = stdin.lock().lines().next().unwrap().ok().unwrap();
		match grid_input.trim() {
				"yes" => { player_type = PlayerType::Human; break; },
				"no" => { player_type = PlayerType::AI; break;},
				_ => {continue;}
			};
	};
	return Player { num: player_num, name: name.to_string(), player_type: player_type};
}

fn get_a_position(stdin: &mut std::old_io::stdio::StdinReader, max_value_plus_one: u8, axe: String) -> u8 {
	let position: u8;
	loop {
		println!("Give us {} position", axe);
		let grid_input = stdin.lock().lines().next().unwrap().ok().unwrap();
		match grid_input.trim().parse::<u8>() {
			Ok(x) if x < max_value_plus_one => { position = x; break; },
			Ok(_) => {continue;},
			Err(_) => {continue;}
		};
	};
	return position;
}

//For performances considerations, sides can't be > to 255.
fn generate_grid(side_length: u8) -> Vec<Vec<u8>> {
	let mut vector: Vec<Vec<u8>> = Vec::with_capacity(side_length as usize);
	for _ in 0..side_length {
		let mut vector_internal: Vec<u8> = Vec::with_capacity(side_length as usize);
		for _ in 0..side_length {
			vector_internal.push(0);
		}
		vector.push(vector_internal);
	}
	return vector;
}

fn edit_grid(grid: &mut Vec<Vec<u8>>, new_value: u8, x: u8, y: u8) {
	grid[x as usize][y as usize] = new_value;
}

fn print_grid(grid: &Vec<Vec<u8>>) {
	for x in grid.iter() {
		for y in x.iter() {
			print!(" {} ", match *y {
				0u8 => "-",
				1u8 => "B",
				2u8 => "W",
				_ => "E"
			});
		}
		print!("\n");
	}
}

fn is_free_cell(grid: &Vec<Vec<u8>>, x: u8, y: u8) -> bool {
	if grid[x as usize][y as usize] == 0u8 { true } else { false }
}

fn has_winner_path(grid: &Vec<Vec<u8>>, player: u8) -> bool {
	for i in 0u8..grid.len() as u8 {
		let vector: Vec<[u8; 2]> = Vec::new();
		let is_win: bool = match player {
			1u8 => go_to_goal(&grid, player, 0, i, &vector),
			2u8 => go_to_goal(&grid, player, i, 0, &vector),
			_ => { panic!("Incorrect player for has_winner_path"); }
		};
		if is_win {
			return true;
		}
	}
	return false;
}

fn go_to_goal(grid: &Vec<Vec<u8>>, player: u8, x: u8, y: u8, to_ignore: &Vec<[u8; 2]>) -> bool {
	if is_a_goal(&grid, player, x, y) {
		return true;
	}
	let mut to_ignore_cell = to_ignore.clone();
	to_ignore_cell.push([x, y]);

	let available_cells_close = not_visited_cells_close(&grid, player, x, y, &to_ignore_cell, true);

	for cell in available_cells_close.iter() {
		if go_to_goal(&grid, player, cell[0], cell[1], &to_ignore_cell) {
			return true;
		}
	}
	return false;
}

fn is_a_goal(grid: &Vec<Vec<u8>>, player: u8, x: u8, y: u8) -> bool{
	let max_index: u8 = grid.len() as u8 - 1;
	(player == 1 && x == max_index) || (player == 2 && y == max_index)
}

fn not_visited_cells_close(grid: &Vec<Vec<u8>>, player: u8, x: u8, y: u8, visited: &Vec<[u8; 2]>, focus_on_player: bool) -> Vec<[u8; 2]> {
	let cells_close: Vec<[u8; 2]> = available_cells_close(&grid, player, x, y, focus_on_player);
	let mut not_visited_cells_close: Vec<[u8; 2]> = Vec::with_capacity(cells_close.len());

	for cell in cells_close.iter() {
		if !has_pos_in_vector(&visited, *cell) {
			not_visited_cells_close.push(*cell);
		}
	}
	return not_visited_cells_close;
}

fn has_pos_in_vector(positions: &Vec<[u8; 2]>, search: [u8; 2]) -> bool {
	for pos in positions.iter() {
		if search == *pos {
			return true;
		}
	}
	return false;
}

fn revert_player(player: u8) -> u8 {
	if player == 1 { 2 } else if player == 2 { 1 } else { 0 }
}

fn available_cells_close(grid: &Vec<Vec<u8>>, player: u8, x: u8, y: u8, focus_on_player: bool) -> Vec<[u8; 2]> {
	let cells_close: Vec<[u8; 2]> = cells_close(&grid, x, y);
	let mut available_cells_close: Vec<[u8; 2]> = Vec::with_capacity(cells_close.len());

	let opp_player = revert_player(player);

	for cell in cells_close.iter() {
		let grid_value: u8 = grid[cell[0] as usize][cell[1] as usize];
		if (grid_value != opp_player && !focus_on_player) || (grid_value != opp_player && grid_value != 0)  {
			available_cells_close.push(*cell);
		}
	}
	return available_cells_close;
}

fn cells_close(grid: &Vec<Vec<u8>>, x: u8, y: u8) -> Vec<[u8; 2]> {
	let mut cells_values: Vec<[u8; 2]> = Vec::with_capacity(8);
	let grid_length: u8 = grid.len() as u8;
	let relative_positions: [[i8; 2]; 8] = [
		[-1, -1],	[-1, 0],	[-1, 1],
		[0, -1], 	/*0,0*/		[0, 1],
		[1, -1],	[1, 0],		[1, 1]];
	for relative_position in relative_positions.iter() {
		let new_i_x = x as i8 + relative_position[0];
		if new_i_x < 0 || new_i_x >= grid_length as i8 {
			continue;
		}
		let new_x = new_i_x as u8;

		let new_i_y = y as i8 + relative_position[1];
		if new_i_y < 0 || new_i_y >= grid_length as i8 {
			continue;
		}
		let new_y = new_i_y as u8;
		cells_values.push([new_x, new_y]);
	}
	return cells_values;
}

/*************************/
#[test]
#[should_fail]
fn test_two_grids_shuffled_must_not_be_equals() {
	let grid: Vec<Vec<u8>> = generate_grid(10u8);
	assert_eq!(get_shuffled_free_cells(&grid), get_shuffled_free_cells(&grid));
}

#[test]
fn test_winned_game() {
	let mut grid1: Vec<Vec<u8>> = generate_grid(10u8);
	let mut grid2: Vec<Vec<u8>> = generate_grid(10u8);
	for i in 0u8..10 {
		edit_grid(&mut grid1, 1, i, 0);
		edit_grid(&mut grid2, 2, 0, i);
	}
	assert!(has_winner_path(&grid1, 1));
	assert!(has_winner_path(&grid2, 2));
}

#[test]
#[should_fail]
fn test_not_winned_game() {
	let mut grid: Vec<Vec<u8>> = generate_grid(10u8);
	for i in 0u8..grid.len() as u8 {
		edit_grid(&mut grid, i % 2 + 1, 0, i);
	}
	assert!(has_winner_path(&grid, 1));
	assert!(has_winner_path(&grid, 2));
}

#[test]
fn test_cells_close() {
	let grid: Vec<Vec<u8>> = generate_grid(10u8);
	//Corner left top, only 3 cells are available
	assert_eq!(cells_close(&grid, 0, 0).len(), 3);
	//Corner right bottom, only 3 cells are available
	assert_eq!(cells_close(&grid, 9, 9).len(), 3);
	//Corner close to center, 8 cells are available
	assert_eq!(cells_close(&grid, 4, 4).len(), 8);
}
<|endoftext|>