<commit_before>extern crate native;
extern crate kiss3d;
extern crate nalgebra;
extern crate genmesh;

use std::rc::Rc;
use std::cell::RefCell;
use nalgebra::na::Vec3;
use nalgebra::na;
use kiss3d::window::Window;
use kiss3d::resource::Mesh;
use kiss3d::light;

use genmesh::{MapToVertices, Triangulate};
use genmesh::{LruIndexer, Indexer};
use genmesh::generators::{Plane, Cube, SphereUV};
use genmesh::generators::{SharedVertex, IndexedPolygon};

#[start]
fn start(argc: int, argv: *const *const u8) -> int {
    native::start(argc, argv, main)
}

fn main() {
    let mut window = Window::new("Kiss3d: custom_mesh");

    let mut cube_v = Vec::new();
    let cube_i: Vec<Vec3<u32>> = {
        let mut indexer = LruIndexer::new(8, |_, v| cube_v.push(v));
        Cube::new()
            .vertex(|(a, b, c)| {
                Vec3::new(a, b, c)
            })
            .vertex(|v| indexer.index(v) as u32)
            .triangulate()
            .map(|p| Vec3::new(p.x, p.y, p.z) )
            .collect()
    };
    let cube_mesh = Rc::new(RefCell::new(Mesh::new(cube_v, cube_i, None, None, false)));
    let mut cube0 = window.add_mesh(cube_mesh, na::one());

    cube0.set_color(1.0, 0.0, 0.0);
    cube0.set_local_scale(0.1, 0.1, 0.1);
    cube0.prepend_to_local_rotation(&Vec3::new(-0.5f32, 0., 0.));

    let cube_v: Vec<Vec3<f32>> = Cube::new()
        .shared_vertex_iter()
        .map(|(x, y, z)| Vec3::new(x, y, z))
        .collect();

    let cube_i: Vec<Vec3<u32>> = Cube::new()
        .indexed_polygon_iter()
        .triangulate()
        .map(|v| Vec3::new(v.x as u32, v.y as u32, v.z as u32))
        .collect();
    let cube_mesh = Rc::new(RefCell::new(Mesh::new(cube_v, cube_i, None, None, false)));
    let mut cube1 = window.add_mesh(cube_mesh, na::one());

    cube1.set_color(1.0, 0.0, 0.0);
    cube1.set_local_scale(0.1, 0.1, 0.1);
    cube1.set_local_translation(Vec3::new(0.0f32, 0.25, 0.0));
    cube1.prepend_to_local_rotation(&Vec3::new(-0.5f32, 0., 0.));

    let mut plane_v = Vec::new();
    let plane_i: Vec<Vec3<u32>> = {
        let mut indexer = LruIndexer::new(8, |_, v| plane_v.push(v));
        Plane::subdivide(8, 8)
            .triangulate()
            .vertex(|(a, b)| {
                Vec3::new(a, b, 0.)
            })
            .vertex(|v| indexer.index(v) as u32)
            .map(|p| Vec3::new(p.x, p.y, p.z) )
            .collect()
    };
    let plane_mesh = Rc::new(RefCell::new(Mesh::new(plane_v, plane_i, None, None, false)));
    let mut plane0 = window.add_mesh(plane_mesh, na::one());

    plane0.set_color(0.0, 1.0, 0.0);
    plane0.set_local_scale(0.1, 0.1, 0.1);
    plane0.set_local_translation(Vec3::new(0.25f32, 0.0, 0.0));
    plane0.prepend_to_local_rotation(&Vec3::new(-0.5f32, 0., 0.));

    let plane_v: Vec<Vec3<f32>> = Plane::subdivide(2, 2)
        .shared_vertex_iter()
        .map(|(x, y)| Vec3::new(x, y, 0.))
        .collect();

    let plane_i: Vec<Vec3<u32>> = Plane::subdivide(2, 2)
        .indexed_polygon_iter()
        .triangulate()
        .map(|v| Vec3::new(v.x as u32, v.y as u32, v.z as u32))
        .collect();

    let plane_mesh = Rc::new(RefCell::new(Mesh::new(plane_v, plane_i, None, None, false)));
    let mut plane1 = window.add_mesh(plane_mesh, na::one());

    plane1.set_color(0.0, 1.0, 0.0);
    plane1.set_local_scale(0.1, 0.1, 0.1);
    plane1.set_local_translation(Vec3::new(0.25f32, 0.25, 0.0));
    plane1.prepend_to_local_rotation(&Vec3::new(-0.5f32, 0., 0.));

    let mut sphere_v = Vec::new();
    let sphere_i: Vec<Vec3<u32>> = {
        let mut indexer = LruIndexer::new(8, |_, v| sphere_v.push(v));
        SphereUV::new(32, 16)
            .triangulate()
            .vertex(|(a, b, c)| {
                Vec3::new(a, b, c)
            })
            .vertex(|v| indexer.index(v) as u32)
            .map(|p| Vec3::new(p.x, p.y, p.z) )
            .collect()
    };
    let sphere_mesh = Rc::new(RefCell::new(Mesh::new(sphere_v, sphere_i, None, None, false)));
    let mut sphere0 = window.add_mesh(sphere_mesh, na::one());

    sphere0.set_color(0.0, 0.0, 1.0);
    sphere0.set_local_scale(0.1, 0.1, 0.1);
    sphere0.set_local_translation(Vec3::new(-0.25f32, 0.0, 0.0));
    sphere0.prepend_to_local_rotation(&Vec3::new(-0.5f32, 0., 0.));

    let sphere_v: Vec<Vec3<f32>> = SphereUV::new(32, 16)
        .shared_vertex_iter()
        .map(|(x, y, z)| Vec3::new(x, y, z))
        .collect();

    let sphere_i: Vec<Vec3<u32>> = SphereUV::new(32, 16)
        .indexed_polygon_iter()
        .triangulate()
        .map(|v| Vec3::new(v.x as u32, v.y as u32, v.z as u32))
        .collect();
    let sphere_mesh = Rc::new(RefCell::new(Mesh::new(sphere_v, sphere_i, None, None, false)));
    let mut sphere1 = window.add_mesh(sphere_mesh, na::one());

    sphere1.set_color(0.0, 0.0, 1.0);
    sphere1.set_local_scale(0.1, 0.1, 0.1);
    sphere1.set_local_translation(Vec3::new(-0.25f32, 0.25, 0.0));
    sphere1.prepend_to_local_rotation(&Vec3::new(-0.5f32, 0., 0.));

    window.set_light(light::StickToCamera);

    while window.render() {
        cube0.prepend_to_local_rotation(&Vec3::new(0.0f32, 0.014, 0.0));
        cube1.prepend_to_local_rotation(&Vec3::new(0.0f32, 0.014, 0.0));
        plane0.prepend_to_local_rotation(&Vec3::new(0.0f32, 0.014, 0.0));
        plane1.prepend_to_local_rotation(&Vec3::new(0.0f32, 0.014, 0.0));
        sphere0.prepend_to_local_rotation(&Vec3::new(0.0f32, 0.014, 0.0));
        sphere1.prepend_to_local_rotation(&Vec3::new(0.0f32, 0.014, 0.0))
    }
}
<commit_msg>Updated to match the latest nalgebra and kiss3d changes.<commit_after>extern crate native;
extern crate kiss3d;
extern crate "nalgebra" as na;
extern crate genmesh;

use std::rc::Rc;
use std::cell::RefCell;
use na::{Pnt3, Vec3};
use kiss3d::window::Window;
use kiss3d::resource::Mesh;
use kiss3d::light;

use genmesh::{MapToVertices, Triangulate};
use genmesh::{LruIndexer, Indexer};
use genmesh::generators::{Plane, Cube, SphereUV};
use genmesh::generators::{SharedVertex, IndexedPolygon};

#[start]
fn start(argc: int, argv: *const *const u8) -> int {
    native::start(argc, argv, main)
}

fn main() {
    let mut window = Window::new("Kiss3d: custom_mesh");

    let mut cube_v = Vec::new();
    let cube_i: Vec<Vec3<u32>> = {
        let mut indexer = LruIndexer::new(8, |_, v| cube_v.push(v));
        Cube::new()
            .vertex(|(a, b, c)| Pnt3::new(a, b, c))
            .vertex(|v| indexer.index(v) as u32)
            .triangulate()
            .map(|p| Vec3::new(p.x, p.y, p.z) )
            .collect()
    };
    let cube_mesh = Rc::new(RefCell::new(Mesh::new(cube_v, cube_i, None, None, false)));
    let mut cube0 = window.add_mesh(cube_mesh, na::one());

    cube0.set_color(1.0, 0.0, 0.0);
    cube0.set_local_scale(0.1, 0.1, 0.1);
    cube0.prepend_to_local_rotation(&Vec3::new(-0.5f32, 0., 0.));

    let cube_v: Vec<Pnt3<f32>> = Cube::new()
        .shared_vertex_iter()
        .map(|(x, y, z)| Pnt3::new(x, y, z))
        .collect();

    let cube_i: Vec<Vec3<u32>> = Cube::new()
        .indexed_polygon_iter()
        .triangulate()
        .map(|v| Vec3::new(v.x as u32, v.y as u32, v.z as u32))
        .collect();
    let cube_mesh = Rc::new(RefCell::new(Mesh::new(cube_v, cube_i, None, None, false)));
    let mut cube1 = window.add_mesh(cube_mesh, na::one());

    cube1.set_color(1.0, 0.0, 0.0);
    cube1.set_local_scale(0.1, 0.1, 0.1);
    cube1.set_local_translation(Vec3::new(0.0f32, 0.25, 0.0));
    cube1.prepend_to_local_rotation(&Vec3::new(-0.5f32, 0., 0.));

    let mut plane_v = Vec::new();
    let plane_i: Vec<Vec3<u32>> = {
        let mut indexer = LruIndexer::new(8, |_, v| plane_v.push(v));
        Plane::subdivide(8, 8)
            .triangulate()
            .vertex(|(a, b)| Pnt3::new(a, b, 0.) )
            .vertex(|v| indexer.index(v) as u32)
            .map(|p| Vec3::new(p.x, p.y, p.z) )
            .collect()
    };
    let plane_mesh = Rc::new(RefCell::new(Mesh::new(plane_v, plane_i, None, None, false)));
    let mut plane0 = window.add_mesh(plane_mesh, na::one());

    plane0.set_color(0.0, 1.0, 0.0);
    plane0.set_local_scale(0.1, 0.1, 0.1);
    plane0.set_local_translation(Vec3::new(0.25f32, 0.0, 0.0));
    plane0.prepend_to_local_rotation(&Vec3::new(-0.5f32, 0., 0.));

    let plane_v: Vec<Pnt3<f32>> = Plane::subdivide(2, 2)
        .shared_vertex_iter()
        .map(|(x, y)| Pnt3::new(x, y, 0.))
        .collect();

    let plane_i: Vec<Vec3<u32>> = Plane::subdivide(2, 2)
        .indexed_polygon_iter()
        .triangulate()
        .map(|v| Vec3::new(v.x as u32, v.y as u32, v.z as u32))
        .collect();

    let plane_mesh = Rc::new(RefCell::new(Mesh::new(plane_v, plane_i, None, None, false)));
    let mut plane1 = window.add_mesh(plane_mesh, na::one());

    plane1.set_color(0.0, 1.0, 0.0);
    plane1.set_local_scale(0.1, 0.1, 0.1);
    plane1.set_local_translation(Vec3::new(0.25f32, 0.25, 0.0));
    plane1.prepend_to_local_rotation(&Vec3::new(-0.5f32, 0., 0.));

    let mut sphere_v = Vec::new();
    let sphere_i: Vec<Vec3<u32>> = {
        let mut indexer = LruIndexer::new(8, |_, v| sphere_v.push(v));
        SphereUV::new(32, 16)
            .triangulate()
            .vertex(|(a, b, c)| Pnt3::new(a, b, c) )
            .vertex(|v| indexer.index(v) as u32)
            .map(|p| Vec3::new(p.x, p.y, p.z) )
            .collect()
    };
    let sphere_mesh = Rc::new(RefCell::new(Mesh::new(sphere_v, sphere_i, None, None, false)));
    let mut sphere0 = window.add_mesh(sphere_mesh, na::one());

    sphere0.set_color(0.0, 0.0, 1.0);
    sphere0.set_local_scale(0.1, 0.1, 0.1);
    sphere0.set_local_translation(Vec3::new(-0.25f32, 0.0, 0.0));
    sphere0.prepend_to_local_rotation(&Vec3::new(-0.5f32, 0., 0.));

    let sphere_v: Vec<Pnt3<f32>> = SphereUV::new(32, 16)
        .shared_vertex_iter()
        .map(|(x, y, z)| Pnt3::new(x, y, z))
        .collect();

    let sphere_i: Vec<Vec3<u32>> = SphereUV::new(32, 16)
        .indexed_polygon_iter()
        .triangulate()
        .map(|v| Vec3::new(v.x as u32, v.y as u32, v.z as u32))
        .collect();
    let sphere_mesh = Rc::new(RefCell::new(Mesh::new(sphere_v, sphere_i, None, None, false)));
    let mut sphere1 = window.add_mesh(sphere_mesh, na::one());

    sphere1.set_color(0.0, 0.0, 1.0);
    sphere1.set_local_scale(0.1, 0.1, 0.1);
    sphere1.set_local_translation(Vec3::new(-0.25f32, 0.25, 0.0));
    sphere1.prepend_to_local_rotation(&Vec3::new(-0.5f32, 0., 0.));

    window.set_light(light::StickToCamera);

    while window.render() {
        cube0.prepend_to_local_rotation(&Vec3::new(0.0f32, 0.014, 0.0));
        cube1.prepend_to_local_rotation(&Vec3::new(0.0f32, 0.014, 0.0));
        plane0.prepend_to_local_rotation(&Vec3::new(0.0f32, 0.014, 0.0));
        plane1.prepend_to_local_rotation(&Vec3::new(0.0f32, 0.014, 0.0));
        sphere0.prepend_to_local_rotation(&Vec3::new(0.0f32, 0.014, 0.0));
        sphere1.prepend_to_local_rotation(&Vec3::new(0.0f32, 0.014, 0.0))
    }
}
<|endoftext|>


<commit_before>//! Implementation of [HPP model](https://en.wikipedia.org/wiki/HPP_model).
//! Assumes Von Nuemann's neighborhood.

#![cfg(test)]
use traits::Cell;
use traits::Coord;
use traits::Grid;
use traits::Engine;
use traits::Consumer;
use engine::Sequential;
use grid::nhood::VonNeumannNhood;
use grid::square::SquareGrid;

#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
enum Stage {
    Collision,
    Transport,
}

impl Default for Stage {
    fn default() -> Self {
        Stage::Collision
    }
}

#[derive(Clone, Copy, Debug, PartialEq)]
enum Direction {
    Down,
    Right,
    Left,
    Up,
}

impl Direction {
    fn opposite(&self) -> Self {

        match *self {
            Direction::Up => Direction::Down,
            Direction::Left => Direction::Right,
            Direction::Right => Direction::Left,
            Direction::Down => Direction::Up,
        }
    }

    fn perpendicular(&self) -> Self {

        match *self {
            Direction::Up => Direction::Left,
            Direction::Left => Direction::Down,
            Direction::Right => Direction::Up,
            Direction::Down => Direction::Right,
        }
    }
}

impl From<usize> for Direction {
    fn from(int: usize) -> Self {
        match int {
            0 => Direction::Up,
            1 => Direction::Left,
            2 => Direction::Right,
            3 => Direction::Down,
            i => panic!("No associated variant to number {}.", i),
        }
    }
}

#[derive(Clone, Debug, Default, Serialize, Deserialize)]
struct HPP {
    particles: [bool; 4],
    stage: Stage,
    coord: (i32, i32),
}

impl Cell for HPP {
    type Coord = (i32, i32);

    fn step<'a, I>(&'a self, neighbors: I) -> Self
        where I: Iterator<Item = Option<&'a Self>>
    {

        match self.stage {
            Stage::Collision => self.collision(neighbors),
            Stage::Transport => self.transport(neighbors),
        }
    }

    fn with_coord<C: Coord>(coord: C) -> Self {
        HPP {
            stage: Stage::Collision,
            coord: (coord.x(), coord.y()),
            ..Default::default()
        }
    }

    fn coord(&self) -> &Self::Coord {
        &self.coord
    }

    fn set_coord<C: Coord>(&mut self, coord: &C) {
        self.coord = (coord.x(), coord.y());
    }
}

impl HPP {
    fn collision<'a, I>(&self, neighbors: I) -> Self
        where I: Iterator<Item = Option<&'a Self>>
    {

        let mut new = HPP { stage: Stage::Transport, ..Default::default() };

        let has_head_on = |d: &Direction, op_d: &Direction| {
            self.particle(&d) && self.particle(&op_d) && !self.particle(&d.perpendicular()) &&
            !self.particle(&op_d.perpendicular())
        };

        for (neighbor, direction) in neighbors.zip(self.directions().iter()) {

            match neighbor {

                Some(_) => {
                    let opposite = direction.opposite();

                    let head_on = has_head_on(&direction, &opposite);
                    if head_on {
                        new.set_particle(&direction.perpendicular(), true);
                        new.set_particle(&opposite.perpendicular(), true);
                    } else {
                        let exists = new.particle(&direction) || self.particle(&direction);
                        new.set_particle(&direction, exists);
                    }
                }
                // Rebound
                None => {
                    let opposite = direction.opposite();
                    let head_on = has_head_on(&direction, &opposite);
                    if head_on {
                        new.set_particle(&direction.perpendicular(), true);
                        new.set_particle(&opposite.perpendicular(), true);
                    } else {
                        if self.particle(&direction) {
                            new.set_particle(&opposite, true);
                        }
                    }
                }
            }
        }

        new
    }

    fn transport<'a, I>(&self, neighbors: I) -> Self
        where I: Iterator<Item = Option<&'a Self>>
    {

        let mut new = HPP { stage: Stage::Collision, ..Default::default() };

        for (neighbor, direction) in neighbors.zip(self.directions().iter()) {
            match neighbor {
                Some(neighbor) => {
                    let opposite = direction.opposite();
                    if neighbor.particle(&opposite) {
                        new.set_particle(&opposite, true);
                    }
                }
                None => {
                    if self.particle(&direction) {
                        new.set_particle(&direction, true);
                    }
                }
            }
        }

        new
    }

    pub fn particle(&self, direction: &Direction) -> bool {
        let index = *direction as usize;
        self.particles[index]
    }

    fn set_particle(&mut self, direction: &Direction, exists: bool) {
        let index = *direction as usize;
        self.particles[index] = exists;
    }

    #[inline]
    pub fn directions(&self) -> [Direction; 4] {
        [Direction::Up, Direction::Left, Direction::Right, Direction::Down]
    }
}

fn find_cell<C: Cell>(cells: &Vec<C>, x: i32, y: i32) -> HPP {

    assert!(cells.iter().any(|c| c.coord().x() == x && c.coord().y() == y));

    let found = cells.iter()
        .find(|c| c.coord().x() == x && c.coord().y() == y)
        .unwrap();

    to_cell(found)
}

fn pretty_print<G: Grid>(grid: &G) {
    let dim = grid.dimensions();
    let iter_order =
        [vec![Direction::Down], vec![Direction::Right, Direction::Left], vec![Direction::Up]];

    println!("");

    for y in 0..dim.y() {

        for dirs in iter_order.iter() {
            print!("|");
            for x in 0..dim.x() {
                let cell = find_cell(grid.cells(), x, y);
                for d in dirs.iter() {
                    let to_print = match *d {
                        Direction::Down => {
                            if cell.particle(d) {
                                " v |"
                            } else {
                                "   |"
                            }
                        }
                        Direction::Right => {
                            if cell.particle(d) {
                                "> "
                            } else {
                                "  "
                            }
                        }
                        Direction::Left => {
                            if cell.particle(d) {
                                "<|"
                            } else {
                                " |"
                            }
                        }
                        Direction::Up => {
                            if cell.particle(d) {
                                " ^ |"
                            } else {
                                "   |"
                            }
                        }
                    };
                    print!("{}", to_print);
                }
            }
            println!("");
        }
        for _ in 0..dim.x() {
            print!(" ---");
        }
        println!("");
    }
}

#[derive(Debug)]
struct HPPRulesTestConsumer;

use test_helpers::to_cell;

impl HPPRulesTestConsumer {
    pub fn new() -> Self {
        HPPRulesTestConsumer {}
    }

    fn particles_count<C: Cell>(&self, cells: &Vec<C>, direction: &Direction) -> i32 {

        cells.iter()
            .map(|c| to_cell(c))
            .filter(|c: &HPP| c.particle(direction) == true)
            .count() as i32
    }

    fn test_collision<G: Grid>(&self, grid: &G) {
        println!("Collision");

        let left_particle_count = self.particles_count(&grid.cells(), &Direction::Left);
        assert_eq!(left_particle_count, 0);

        let right_particle_count = self.particles_count(&grid.cells(), &Direction::Right);
        assert_eq!(right_particle_count, 2);

        let up_particles_count = self.particles_count(&grid.cells(), &Direction::Up);
        assert_eq!(up_particles_count, 1);

        let down_particles_count = self.particles_count(&grid.cells(), &Direction::Down);
        assert_eq!(down_particles_count, 1);

        let rebound_to_right = find_cell(&grid.cells(), 0, 1);
        assert_eq!(rebound_to_right.particle(&Direction::Right), true);

        let head_on_up = find_cell(&grid.cells(), 1, 0);
        assert_eq!(head_on_up.particle(&Direction::Up), true);

        let head_on_down = find_cell(&grid.cells(), 1, 0);
        assert_eq!(head_on_down.particle(&Direction::Down), true);
    }

    fn test_transport<G: Grid>(&self, grid: &G) {
        println!("Transport");

        let simple_move_to_right = find_cell(&grid.cells(), 1, 2);
        assert_eq!(simple_move_to_right.particle(&Direction::Right), true);

        let move_to_right_after_rebound = find_cell(&grid.cells(), 1, 2);
        assert_eq!(move_to_right_after_rebound.particle(&Direction::Right),
                   true);

        let move_to_down_after_head_on = find_cell(&grid.cells(), 1, 1);
        assert_eq!(move_to_down_after_head_on.particle(&Direction::Down), true);

        let fixed_to_up_after_head_on = find_cell(&grid.cells(), 1, 0);
        assert_eq!(fixed_to_up_after_head_on.particle(&Direction::Up), true);
    }
}

impl Consumer for HPPRulesTestConsumer {
    type Cell = HPP;

    fn consume<G: Grid>(&mut self, grid: &mut G) {
        assert_eq!(grid.cells().len(), 9);

        pretty_print(grid);

        // We are testing previous state.
        let first: HPP = to_cell(&grid.cells()[0]);

        match first.stage {
            Stage::Collision => self.test_transport(grid),
            Stage::Transport => self.test_collision(grid),
        }
    }
}

#[test]
fn test_rules() {
    // initial          collision        transport
    // | * |> <| * |    | * |^ v| * |    | * |  v| * |
    // |  <| * | * | => |>  | * | * | => | * |> v| * |
    // |>  | * | * |    |>  | * | * |    | * |>  | * |
    // 3x3 grid with 4 particles. There should be
    // one rebound, head-on collision and simple move.

    let left_particle = [false, false, true, false];
    let right_particle = [false, true, false, false];
    let about_to_collide = [false, true, true, false];

    let cells = vec![
        HPP { stage: Stage::Collision, particles: about_to_collide, coord: (1, 0) },
        HPP { stage: Stage::Collision, particles: left_particle, coord: (0, 1) },
        HPP { stage: Stage::Collision, particles: right_particle, coord: (0, 2) },
    ];

    let nhood = VonNeumannNhood::new();
    let mut grid: SquareGrid<HPP, _> = SquareGrid::new(3, 3, nhood);
    grid.set_cells(cells);

    pretty_print(&grid);

    let right_particles_count = grid.cells()
        .iter()
        .map(|c| to_cell(c))
        .filter(|c: &HPP| c.particle(&Direction::Right) == true)
        .count();
    assert_eq!(right_particles_count, 2);

    let consumer = HPPRulesTestConsumer::new();
    let mut engine = Sequential::new(grid, consumer);
    engine.run_times(2);
}

struct HPPSpreadTestConsumer {
    cur_y: i32,
    cur_direction: Direction,
}

impl HPPSpreadTestConsumer {
    pub fn new() -> Self {
        HPPSpreadTestConsumer {
            cur_y: 0,
            cur_direction: Direction::Down,
        }
    }

    fn particles_count<C: Cell>(&self, cells: &Vec<C>, direction: &Direction) -> i32 {

        cells.iter()
            .map(|c| to_cell(c))
            .filter(|c: &HPP| c.particle(direction) == true)
            .count() as i32
    }

    fn test_collision<G: Grid>(&mut self, grid: &G) {
        println!("Collision");

        if self.cur_y == 0 {
            self.cur_direction = Direction::Down;
        }

        let particles_count = self.particles_count(&grid.cells(), &self.cur_direction);
        assert_eq!(particles_count, 5);

        if self.cur_direction == Direction::Down {
            self.cur_y += 1;
        } else {
            self.cur_y -= 1;
        }
    }

    fn test_transport<G: Grid>(&mut self, grid: &G) {
        println!("Transport");

        let particles_count = self.particles_count(&grid.cells(), &self.cur_direction);
        assert_eq!(particles_count, 5);

        assert!(grid.cells()
            .iter()
            .map(|c| to_cell(c))
            .filter(|c: &HPP| c.coord().y() == self.cur_y)
            .all(|c| c.particle(&self.cur_direction) == true));

        if self.cur_y == 4 {
            self.cur_direction = Direction::Up;
        }
    }
}

impl Consumer for HPPSpreadTestConsumer {
    type Cell = HPP;

    fn consume<G: Grid>(&mut self, grid: &mut G) {
        assert_eq!(grid.cells().len(), 25);

        pretty_print(grid);

        // We are testing previous state.
        let first: HPP = to_cell(&grid.cells()[0]);

        match first.stage {
            Stage::Collision => self.test_transport(grid),
            Stage::Transport => self.test_collision(grid),
        }
    }
}

#[test]
fn test_spread() {
    // initial          later
    // | v v v v v |    | * * * * * |
    // | * * * * * |    | v v v v v |
    // | * * * * * | => | * * * * * | => (so on)
    // | * * * * * |    | * * * * * |
    // | * * * * * |    | * * * * * |
    // 5x5 grid with 5 particles. Particles should move
    // to lower border then rebound, then move to upper and so on.

    let down_particle = [false, false, false, true];

    let mut cells = Vec::new();
    for x in 0..5 {
        cells.push(HPP {
            stage: Stage::Collision,
            particles: down_particle,
            coord: (x, 0),
        });
    }

    let nhood = VonNeumannNhood::new();
    let mut grid: SquareGrid<HPP, _> = SquareGrid::new(5, 5, nhood);
    grid.set_cells(cells);

    let consumer = HPPSpreadTestConsumer::new();
    let mut engine = Sequential::new(grid, consumer);
    // 2 phases * 10 full cycles = 20 times.
    engine.run_times(20);
}
<commit_msg>Added offset.<commit_after>//! Implementation of [HPP model](https://en.wikipedia.org/wiki/HPP_model).
//! Assumes Von Nuemann's neighborhood.

#![cfg(test)]

use traits::Cell;
use traits::Coord;
use traits::Grid;
use traits::Engine;
use traits::Consumer;
use engine::Sequential;
use grid::nhood::VonNeumannNhood;
use grid::square::SquareGrid;

#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
enum Stage {
    Collision,
    Transport,
}

impl Default for Stage {
    fn default() -> Self {
        Stage::Collision
    }
}

#[derive(Clone, Copy, Debug, PartialEq)]
enum Direction {
    Down,
    Right,
    Left,
    Up,
}

impl Direction {
    fn opposite(&self) -> Self {

        match *self {
            Direction::Up => Direction::Down,
            Direction::Left => Direction::Right,
            Direction::Right => Direction::Left,
            Direction::Down => Direction::Up,
        }
    }

    fn perpendicular(&self) -> Self {

        match *self {
            Direction::Up => Direction::Left,
            Direction::Left => Direction::Down,
            Direction::Right => Direction::Up,
            Direction::Down => Direction::Right,
        }
    }
}

impl From<usize> for Direction {
    fn from(int: usize) -> Self {
        match int {
            0 => Direction::Up,
            1 => Direction::Left,
            2 => Direction::Right,
            3 => Direction::Down,
            i => panic!("No associated variant to number {}.", i),
        }
    }
}

#[derive(Clone, Debug, Default, Serialize, Deserialize)]
struct HPP {
    particles: [bool; 4],
    stage: Stage,
    coord: (i32, i32),
}

impl Cell for HPP {
    type Coord = (i32, i32);

    fn step<'a, I>(&'a self, neighbors: I) -> Self
        where I: Iterator<Item = Option<&'a Self>>
    {

        match self.stage {
            Stage::Collision => self.collision(neighbors),
            Stage::Transport => self.transport(neighbors),
        }
    }

    fn with_coord<C: Coord>(coord: C) -> Self {
        HPP {
            stage: Stage::Collision,
            coord: (coord.x(), coord.y()),
            ..Default::default()
        }
    }

    fn coord(&self) -> &Self::Coord {
        &self.coord
    }

    fn set_coord<C: Coord>(&mut self, coord: &C) {
        self.coord = (coord.x(), coord.y());
    }
}

impl HPP {
    fn collision<'a, I>(&self, neighbors: I) -> Self
        where I: Iterator<Item = Option<&'a Self>>
    {

        let mut new = HPP { stage: Stage::Transport, ..Default::default() };

        let has_head_on = |d: &Direction, op_d: &Direction| {
            self.particle(&d) && self.particle(&op_d) && !self.particle(&d.perpendicular()) &&
            !self.particle(&op_d.perpendicular())
        };

        for (neighbor, direction) in neighbors.zip(self.directions().iter()) {

            match neighbor {

                Some(_) => {
                    let opposite = direction.opposite();

                    let head_on = has_head_on(&direction, &opposite);
                    if head_on {
                        new.set_particle(&direction.perpendicular(), true);
                        new.set_particle(&opposite.perpendicular(), true);
                    } else {
                        let exists = new.particle(&direction) || self.particle(&direction);
                        new.set_particle(&direction, exists);
                    }
                }
                // Rebound
                None => {
                    let opposite = direction.opposite();
                    let head_on = has_head_on(&direction, &opposite);
                    if head_on {
                        new.set_particle(&direction.perpendicular(), true);
                        new.set_particle(&opposite.perpendicular(), true);
                    } else {
                        if self.particle(&direction) {
                            new.set_particle(&opposite, true);
                        }
                    }
                }
            }
        }

        new
    }

    fn transport<'a, I>(&self, neighbors: I) -> Self
        where I: Iterator<Item = Option<&'a Self>>
    {

        let mut new = HPP { stage: Stage::Collision, ..Default::default() };

        for (neighbor, direction) in neighbors.zip(self.directions().iter()) {
            match neighbor {
                Some(neighbor) => {
                    let opposite = direction.opposite();
                    if neighbor.particle(&opposite) {
                        new.set_particle(&opposite, true);
                    }
                }
                None => {
                    if self.particle(&direction) {
                        new.set_particle(&direction, true);
                    }
                }
            }
        }

        new
    }

    pub fn particle(&self, direction: &Direction) -> bool {
        let index = *direction as usize;
        self.particles[index]
    }

    fn set_particle(&mut self, direction: &Direction, exists: bool) {
        let index = *direction as usize;
        self.particles[index] = exists;
    }

    #[inline]
    pub fn directions(&self) -> [Direction; 4] {
        [Direction::Up, Direction::Left, Direction::Right, Direction::Down]
    }
}

fn find_cell<C: Cell>(cells: &Vec<C>, x: i32, y: i32) -> HPP {

    assert!(cells.iter().any(|c| c.coord().x() == x && c.coord().y() == y));

    let found = cells.iter()
        .find(|c| c.coord().x() == x && c.coord().y() == y)
        .unwrap();

    to_cell(found)
}

fn pretty_print<G: Grid>(grid: &G) {
    let dim = grid.dimensions();
    let iter_order =
        [vec![Direction::Down], vec![Direction::Right, Direction::Left], vec![Direction::Up]];

    println!("");

    for y in 0..dim.y() {

        for dirs in iter_order.iter() {
            print!("|");
            for x in 0..dim.x() {
                let cell = find_cell(grid.cells(), x, y);
                for d in dirs.iter() {
                    let to_print = match *d {
                        Direction::Down => {
                            if cell.particle(d) {
                                " v |"
                            } else {
                                "   |"
                            }
                        }
                        Direction::Right => {
                            if cell.particle(d) {
                                "> "
                            } else {
                                "  "
                            }
                        }
                        Direction::Left => {
                            if cell.particle(d) {
                                "<|"
                            } else {
                                " |"
                            }
                        }
                        Direction::Up => {
                            if cell.particle(d) {
                                " ^ |"
                            } else {
                                "   |"
                            }
                        }
                    };
                    print!("{}", to_print);
                }
            }
            println!("");
        }
        for _ in 0..dim.x() {
            print!(" ---");
        }
        println!("");
    }
}

#[derive(Debug)]
struct HPPRulesTestConsumer;

use test_helpers::to_cell;

impl HPPRulesTestConsumer {
    pub fn new() -> Self {
        HPPRulesTestConsumer {}
    }

    fn particles_count<C: Cell>(&self, cells: &Vec<C>, direction: &Direction) -> i32 {

        cells.iter()
            .map(|c| to_cell(c))
            .filter(|c: &HPP| c.particle(direction) == true)
            .count() as i32
    }

    fn test_collision<G: Grid>(&self, grid: &G) {
        println!("Collision");

        let left_particle_count = self.particles_count(&grid.cells(), &Direction::Left);
        assert_eq!(left_particle_count, 0);

        let right_particle_count = self.particles_count(&grid.cells(), &Direction::Right);
        assert_eq!(right_particle_count, 2);

        let up_particles_count = self.particles_count(&grid.cells(), &Direction::Up);
        assert_eq!(up_particles_count, 1);

        let down_particles_count = self.particles_count(&grid.cells(), &Direction::Down);
        assert_eq!(down_particles_count, 1);

        let rebound_to_right = find_cell(&grid.cells(), 0, 1);
        assert_eq!(rebound_to_right.particle(&Direction::Right), true);

        let head_on_up = find_cell(&grid.cells(), 1, 0);
        assert_eq!(head_on_up.particle(&Direction::Up), true);

        let head_on_down = find_cell(&grid.cells(), 1, 0);
        assert_eq!(head_on_down.particle(&Direction::Down), true);
    }

    fn test_transport<G: Grid>(&self, grid: &G) {
        println!("Transport");

        let simple_move_to_right = find_cell(&grid.cells(), 1, 2);
        assert_eq!(simple_move_to_right.particle(&Direction::Right), true);

        let move_to_right_after_rebound = find_cell(&grid.cells(), 1, 2);
        assert_eq!(move_to_right_after_rebound.particle(&Direction::Right),
                   true);

        let move_to_down_after_head_on = find_cell(&grid.cells(), 1, 1);
        assert_eq!(move_to_down_after_head_on.particle(&Direction::Down), true);

        let fixed_to_up_after_head_on = find_cell(&grid.cells(), 1, 0);
        assert_eq!(fixed_to_up_after_head_on.particle(&Direction::Up), true);
    }
}

impl Consumer for HPPRulesTestConsumer {
    type Cell = HPP;

    fn consume<G: Grid>(&mut self, grid: &mut G) {
        assert_eq!(grid.cells().len(), 9);

        pretty_print(grid);

        // We are testing previous state.
        let first: HPP = to_cell(&grid.cells()[0]);

        match first.stage {
            Stage::Collision => self.test_transport(grid),
            Stage::Transport => self.test_collision(grid),
        }
    }
}

#[test]
fn test_rules() {
    // initial          collision        transport
    // | * |> <| * |    | * |^ v| * |    | * |  v| * |
    // |  <| * | * | => |>  | * | * | => | * |> v| * |
    // |>  | * | * |    |>  | * | * |    | * |>  | * |
    // 3x3 grid with 4 particles. There should be
    // one rebound, head-on collision and simple move.

    let left_particle = [false, false, true, false];
    let right_particle = [false, true, false, false];
    let about_to_collide = [false, true, true, false];

    let cells = vec![
        HPP { stage: Stage::Collision, particles: about_to_collide, coord: (1, 0) },
        HPP { stage: Stage::Collision, particles: left_particle, coord: (0, 1) },
        HPP { stage: Stage::Collision, particles: right_particle, coord: (0, 2) },
    ];

    let nhood = VonNeumannNhood::new();
    let mut grid: SquareGrid<HPP, _> = SquareGrid::new(3, 3, nhood);
    grid.set_cells(cells);

    pretty_print(&grid);

    let right_particles_count = grid.cells()
        .iter()
        .map(|c| to_cell(c))
        .filter(|c: &HPP| c.particle(&Direction::Right) == true)
        .count();
    assert_eq!(right_particles_count, 2);

    let consumer = HPPRulesTestConsumer::new();
    let mut engine = Sequential::new(grid, consumer);
    engine.run_times(2);
}

struct HPPSpreadTestConsumer {
    cur_y: i32,
    cur_direction: Direction,
}

impl HPPSpreadTestConsumer {
    pub fn new() -> Self {
        HPPSpreadTestConsumer {
            cur_y: 0,
            cur_direction: Direction::Down,
        }
    }

    fn particles_count<C: Cell>(&self, cells: &Vec<C>, direction: &Direction) -> i32 {

        cells.iter()
            .map(|c| to_cell(c))
            .filter(|c: &HPP| c.particle(direction) == true)
            .count() as i32
    }

    fn test_collision<G: Grid>(&mut self, grid: &G) {
        println!("Collision");

        if self.cur_y == 0 {
            self.cur_direction = Direction::Down;
        }

        let particles_count = self.particles_count(&grid.cells(), &self.cur_direction);
        assert_eq!(particles_count, 5);

        if self.cur_direction == Direction::Down {
            self.cur_y += 1;
        } else {
            self.cur_y -= 1;
        }
    }

    fn test_transport<G: Grid>(&mut self, grid: &G) {
        println!("Transport");

        let particles_count = self.particles_count(&grid.cells(), &self.cur_direction);
        assert_eq!(particles_count, 5);

        assert!(grid.cells()
            .iter()
            .map(|c| to_cell(c))
            .filter(|c: &HPP| c.coord().y() == self.cur_y)
            .all(|c| c.particle(&self.cur_direction) == true));

        if self.cur_y == 4 {
            self.cur_direction = Direction::Up;
        }
    }
}

impl Consumer for HPPSpreadTestConsumer {
    type Cell = HPP;

    fn consume<G: Grid>(&mut self, grid: &mut G) {
        assert_eq!(grid.cells().len(), 25);

        pretty_print(grid);

        // We are testing previous state.
        let first: HPP = to_cell(&grid.cells()[0]);

        match first.stage {
            Stage::Collision => self.test_transport(grid),
            Stage::Transport => self.test_collision(grid),
        }
    }
}

#[test]
fn test_spread() {
    // initial          later
    // | v v v v v |    | * * * * * |
    // | * * * * * |    | v v v v v |
    // | * * * * * | => | * * * * * | => (so on)
    // | * * * * * |    | * * * * * |
    // | * * * * * |    | * * * * * |
    // 5x5 grid with 5 particles. Particles should move
    // to lower border then rebound, then move to upper and so on.

    let down_particle = [false, false, false, true];

    let mut cells = Vec::new();
    for x in 0..5 {
        cells.push(HPP {
            stage: Stage::Collision,
            particles: down_particle,
            coord: (x, 0),
        });
    }

    let nhood = VonNeumannNhood::new();
    let mut grid: SquareGrid<HPP, _> = SquareGrid::new(5, 5, nhood);
    grid.set_cells(cells);

    let consumer = HPPSpreadTestConsumer::new();
    let mut engine = Sequential::new(grid, consumer);
    // 2 phases * 10 full cycles = 20 times.
    engine.run_times(20);
}
<|endoftext|>


<commit_before>#[crate_id(name="dirname", vers="1.0.0", author="Derek Chiang")];

/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Derek Chiang <derekchiang93@gmail.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

extern mod extra;

use std::os;
use std::io::{print, stderr};
use extra::getopts::groups;

static VERSION: &'static str = "1.0.0";

fn main() {
    let args = os::args();
    let program = args[0].clone();
    let opts = ~[
        groups::optflag("z", "zero", "separate output with NUL rather than newline"),
        groups::optflag("", "help", "display this help and exit"),
        groups::optflag("", "version", "output version information and exit"),
    ];

    let matches = match groups::getopts(args.tail(), opts) {
        Ok(m) => m,
        Err(f) => {
            writeln!(&mut stderr() as &mut Writer,
                "Invalid options\n{}", f.to_err_msg());
            os::set_exit_status(1);
            return
        }
    };

    if matches.opt_present("help") {
        println!("dirname {:s} - strip last component from file name", VERSION);
        println!("");
        println!("Usage:");
        println!("  {0:s} [OPTION] NAME...", program);
        println!("");
        print(groups::usage("Output each NAME with its last non-slash component and trailing slashes
removed; if NAME contains no  /'s,  output  '.'  (meaning  the  current
directory).", opts));
        return;
    }

    if matches.opt_present("version") {
        return println!("dirname version: {:s}", VERSION);
    }

    let separator = match matches.opt_present("zero") {
        true => "\0",
        false => "\n"
    };

    if !matches.free.is_empty() {
        for path in matches.free.iter() {
            let p = std::path::Path::new(path.clone());
            print(std::str::from_utf8(p.dirname()));
            print(separator);
        }
    } else {
        println!("{0:s}: missing operand", program);
        println!("Try '{0:s} --help' for more information.", program);
    }
}
<commit_msg>dirname fix according from_utf8 return option now<commit_after>#[crate_id(name="dirname", vers="1.0.0", author="Derek Chiang")];

/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Derek Chiang <derekchiang93@gmail.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

extern mod extra;

use std::os;
use std::io::{print, stderr};
use extra::getopts::groups;

static VERSION: &'static str = "1.0.0";

fn main() {
    let args = os::args();
    let program = args[0].clone();
    let opts = ~[
        groups::optflag("z", "zero", "separate output with NUL rather than newline"),
        groups::optflag("", "help", "display this help and exit"),
        groups::optflag("", "version", "output version information and exit"),
    ];

    let matches = match groups::getopts(args.tail(), opts) {
        Ok(m) => m,
        Err(f) => {
            writeln!(&mut stderr() as &mut Writer,
                "Invalid options\n{}", f.to_err_msg());
            os::set_exit_status(1);
            return
        }
    };

    if matches.opt_present("help") {
        println!("dirname {:s} - strip last component from file name", VERSION);
        println!("");
        println!("Usage:");
        println!("  {0:s} [OPTION] NAME...", program);
        println!("");
        print(groups::usage("Output each NAME with its last non-slash component and trailing slashes
removed; if NAME contains no  /'s,  output  '.'  (meaning  the  current
directory).", opts));
        return;
    }

    if matches.opt_present("version") {
        return println!("dirname version: {:s}", VERSION);
    }

    let separator = match matches.opt_present("zero") {
        true => "\0",
        false => "\n"
    };

    if !matches.free.is_empty() {
        for path in matches.free.iter() {
            let p = std::path::Path::new(path.clone());
            let d = std::str::from_utf8(p.dirname());
            if d.is_some() {
                print(d.unwrap());
            }
            print(separator);
        }
    } else {
        println!("{0:s}: missing operand", program);
        println!("Try '{0:s} --help' for more information.", program);
    }
}
<|endoftext|>


<commit_before>use num::{Num, NumCast};
use std::ops::{Div, Mul};

use geometry::{self, Duplet, Triplet};

pub trait Normalize {
    fn normalize(self) -> Self;
}

pub trait Average: Sized {
    fn average<I>(values: I) -> Self
    where
        I: IntoIterator<Item = Self>;
}

pub trait Interpolate<T = Self>: Sized {
    type Output;

    fn lerp(self, other: T, f: f64) -> Self::Output;

    fn midpoint(self, other: T) -> Self::Output {
        self.lerp(other, 0.5)
    }
}

pub trait Dot<T = Self> {
    type Output;

    fn dot(self, other: T) -> Self::Output;
}

pub trait Cross<T = Self> {
    type Output;

    fn cross(self, other: T) -> Self::Output;
}

pub trait Project<T = Self> {
    type Output;

    fn project(self, other: T) -> Self::Output;
}

impl<T> Project<T> for T
where
    T: Dot + Clone + Mul<<<Self as Dot>::Output as Div>::Output, Output = Self>,
    <T as Dot>::Output: Div,
{
    type Output = T;

    fn project(self, other: T) -> Self::Output {
        let n = other.dot(self.clone());
        let d = self.clone().dot(self.clone());
        self * (n / d)
    }
}

impl<T> Interpolate for Duplet<T>
where
    T: Copy + Num + NumCast,
{
    type Output = Self;

    fn lerp(self, other: Self, f: f64) -> Self::Output {
        Duplet(
            geometry::lerp(self.0, other.0, f),
            geometry::lerp(self.1, other.1, f),
        )
    }
}

impl<T> Interpolate for Triplet<T>
where
    T: Copy + Num + NumCast,
{
    type Output = Self;

    fn lerp(self, other: Self, f: f64) -> Self::Output {
        Triplet(
            geometry::lerp(self.0, other.0, f),
            geometry::lerp(self.1, other.1, f),
            geometry::lerp(self.2, other.2, f),
        )
    }
}

#[cfg(feature = "geometry-cgmath")]
mod feature_geometry_cgmath {
    use cgmath::{ApproxEq, BaseFloat, BaseNum, EuclideanSpace, InnerSpace, Point2, Point3,
                 Vector2, Vector3};
    use num::NumCast;
    use std::ops::{AddAssign, MulAssign};

    use geometry;
    use geometry::ops::*;

    impl<T> Normalize for Vector2<T>
    where
        T: ApproxEq + BaseFloat + BaseNum,
    {
        fn normalize(self) -> Self {
            <Self as InnerSpace>::normalize(self)
        }
    }

    impl<T> Normalize for Vector3<T>
    where
        T: ApproxEq + BaseFloat + BaseNum,
    {
        fn normalize(self) -> Self {
            <Self as InnerSpace>::normalize(self)
        }
    }

    impl<T> Average for Point3<T>
    where
        T: AddAssign + BaseNum + MulAssign + NumCast,
    {
        fn average<I>(values: I) -> Self
        where
            I: IntoIterator<Item = Self>,
        {
            let values = values.into_iter().collect::<Vec<_>>();
            let n = <T as NumCast>::from(values.len()).unwrap();
            let sum = {
                let mut sum = Point3::origin();
                for point in values {
                    sum += Vector3::<T>::new(point.x, point.y, point.z);
                }
                sum
            };
            sum * (T::one() / n)
        }
    }

    impl<T> Interpolate for Point2<T>
    where
        T: BaseNum + NumCast,
    {
        type Output = Self;

        fn lerp(self, other: Self, f: f64) -> Self::Output {
            Point2::new(
                geometry::lerp(self.x, other.x, f),
                geometry::lerp(self.y, other.y, f),
            )
        }
    }

    impl<T> Interpolate for Point3<T>
    where
        T: BaseNum + NumCast,
    {
        type Output = Self;

        fn lerp(self, other: Self, f: f64) -> Self::Output {
            Point3::new(
                geometry::lerp(self.x, other.x, f),
                geometry::lerp(self.y, other.y, f),
                geometry::lerp(self.z, other.z, f),
            )
        }
    }

    impl<T> Interpolate for Vector2<T>
    where
        T: BaseNum + NumCast,
    {
        type Output = Self;

        fn lerp(self, other: Self, f: f64) -> Self::Output {
            Vector2::new(
                geometry::lerp(self.x, other.x, f),
                geometry::lerp(self.y, other.y, f),
            )
        }
    }

    impl<T> Interpolate for Vector3<T>
    where
        T: BaseNum + NumCast,
    {
        type Output = Self;

        fn lerp(self, other: Self, f: f64) -> Self::Output {
            Vector3::new(
                geometry::lerp(self.x, other.x, f),
                geometry::lerp(self.y, other.y, f),
                geometry::lerp(self.z, other.z, f),
            )
        }
    }

    impl<T> Dot for Vector2<T>
    where
        T: BaseFloat + BaseNum,
    {
        type Output = T;

        fn dot(self, other: Self) -> Self::Output {
            <Self as InnerSpace>::dot(self, other)
        }
    }

    impl<T> Dot for Vector3<T>
    where
        T: BaseFloat + BaseNum,
    {
        type Output = T;

        fn dot(self, other: Self) -> Self::Output {
            <Self as InnerSpace>::dot(self, other)
        }
    }

    impl<T> Cross for Vector3<T>
    where
        T: BaseFloat + BaseNum,
    {
        type Output = Self;

        fn cross(self, other: Self) -> Self::Output {
            Self::cross(self, other)
        }
    }
}

#[cfg(feature = "geometry-nalgebra")]
mod feature_geometry_nalgebra {
    use alga::general::Real;
    use nalgebra::{Point2, Point3, Scalar, Vector2, Vector3};
    use nalgebra::core::Matrix;
    use num::{Float, Num, NumCast};
    use std::ops::{AddAssign, MulAssign};

    use geometry;
    use geometry::ops::*;

    impl<T> Normalize for Vector2<T>
    where
        T: Float + Real + Scalar,
    {
        fn normalize(self) -> Self {
            Matrix::normalize(&self)
        }
    }

    impl<T> Normalize for Vector3<T>
    where
        T: Float + Real + Scalar,
    {
        fn normalize(self) -> Self {
            Matrix::normalize(&self)
        }
    }

    // TODO: Implement `Average` for points and vectors of arbitrary dimension.
    impl<T> Average for Point3<T>
    where
        T: AddAssign + MulAssign + Num + NumCast + Scalar,
    {
        fn average<I>(values: I) -> Self
        where
            I: IntoIterator<Item = Self>,
        {
            let values = values.into_iter().collect::<Vec<_>>();
            let n = <T as NumCast>::from(values.len()).unwrap();
            let sum = {
                let mut sum = Point3::origin();
                for point in values {
                    sum += Vector3::<T>::new(point.x, point.y, point.z);
                }
                sum
            };
            sum * (T::one() / n)
        }
    }

    impl<T> Interpolate for Point2<T>
    where
        T: Num + NumCast + Scalar,
    {
        type Output = Self;

        fn lerp(self, other: Self, f: f64) -> Self::Output {
            Point2::new(
                geometry::lerp(self.x, other.x, f),
                geometry::lerp(self.y, other.y, f),
            )
        }
    }

    impl<T> Interpolate for Point3<T>
    where
        T: Num + NumCast + Scalar,
    {
        type Output = Self;

        fn lerp(self, other: Self, f: f64) -> Self::Output {
            Point3::new(
                geometry::lerp(self.x, other.x, f),
                geometry::lerp(self.y, other.y, f),
                geometry::lerp(self.z, other.z, f),
            )
        }
    }

    impl<T> Interpolate for Vector2<T>
    where
        T: Num + NumCast + Scalar,
    {
        type Output = Self;

        fn lerp(self, other: Self, f: f64) -> Self::Output {
            Vector2::new(
                geometry::lerp(self.x, other.x, f),
                geometry::lerp(self.y, other.y, f),
            )
        }
    }

    impl<T> Interpolate for Vector3<T>
    where
        T: Num + NumCast + Scalar,
    {
        type Output = Self;

        fn lerp(self, other: Self, f: f64) -> Self::Output {
            Vector3::new(
                geometry::lerp(self.x, other.x, f),
                geometry::lerp(self.y, other.y, f),
                geometry::lerp(self.z, other.z, f),
            )
        }
    }

    impl<T> Dot for Vector2<T>
    where
        T: AddAssign + Float + MulAssign + Scalar,
    {
        type Output = T;

        fn dot(self, other: Self) -> Self::Output {
            Matrix::dot(&self, &other)
        }
    }

    impl<T> Dot for Vector3<T>
    where
        T: AddAssign + Float + MulAssign + Scalar,
    {
        type Output = T;

        fn dot(self, other: Self) -> Self::Output {
            Matrix::dot(&self, &other)
        }
    }

    impl<T> Cross for Vector3<T>
    where
        T: Float + Real + Scalar,
    {
        type Output = Self;

        fn cross(self, other: Self) -> Self::Output {
            Matrix::cross(&self, &other)
        }
    }
}
<commit_msg>Implement `Average` for 2D point types.<commit_after>use num::{Num, NumCast};
use std::ops::{Div, Mul};

use geometry::{self, Duplet, Triplet};

pub trait Normalize {
    fn normalize(self) -> Self;
}

pub trait Average: Sized {
    fn average<I>(values: I) -> Self
    where
        I: IntoIterator<Item = Self>;
}

pub trait Interpolate<T = Self>: Sized {
    type Output;

    fn lerp(self, other: T, f: f64) -> Self::Output;

    fn midpoint(self, other: T) -> Self::Output {
        self.lerp(other, 0.5)
    }
}

pub trait Dot<T = Self> {
    type Output;

    fn dot(self, other: T) -> Self::Output;
}

pub trait Cross<T = Self> {
    type Output;

    fn cross(self, other: T) -> Self::Output;
}

pub trait Project<T = Self> {
    type Output;

    fn project(self, other: T) -> Self::Output;
}

impl<T> Project<T> for T
where
    T: Dot + Clone + Mul<<<Self as Dot>::Output as Div>::Output, Output = Self>,
    <T as Dot>::Output: Div,
{
    type Output = T;

    fn project(self, other: T) -> Self::Output {
        let n = other.dot(self.clone());
        let d = self.clone().dot(self.clone());
        self * (n / d)
    }
}

impl<T> Interpolate for Duplet<T>
where
    T: Copy + Num + NumCast,
{
    type Output = Self;

    fn lerp(self, other: Self, f: f64) -> Self::Output {
        Duplet(
            geometry::lerp(self.0, other.0, f),
            geometry::lerp(self.1, other.1, f),
        )
    }
}

impl<T> Interpolate for Triplet<T>
where
    T: Copy + Num + NumCast,
{
    type Output = Self;

    fn lerp(self, other: Self, f: f64) -> Self::Output {
        Triplet(
            geometry::lerp(self.0, other.0, f),
            geometry::lerp(self.1, other.1, f),
            geometry::lerp(self.2, other.2, f),
        )
    }
}

#[cfg(feature = "geometry-cgmath")]
mod feature_geometry_cgmath {
    use cgmath::{ApproxEq, BaseFloat, BaseNum, EuclideanSpace, InnerSpace, Point2, Point3,
                 Vector2, Vector3};
    use num::NumCast;
    use std::ops::{AddAssign, MulAssign};

    use geometry;
    use geometry::ops::*;

    impl<T> Normalize for Vector2<T>
    where
        T: ApproxEq + BaseFloat + BaseNum,
    {
        fn normalize(self) -> Self {
            <Self as InnerSpace>::normalize(self)
        }
    }

    impl<T> Normalize for Vector3<T>
    where
        T: ApproxEq + BaseFloat + BaseNum,
    {
        fn normalize(self) -> Self {
            <Self as InnerSpace>::normalize(self)
        }
    }

    impl<T> Average for Point2<T>
    where
        T: AddAssign + BaseNum + MulAssign + NumCast,
    {
        fn average<I>(values: I) -> Self
        where
            I: IntoIterator<Item = Self>,
        {
            let values = values.into_iter().collect::<Vec<_>>();
            let n = <T as NumCast>::from(values.len()).unwrap();
            let sum = {
                let mut sum = Point2::origin();
                for point in values {
                    sum += Vector2::<T>::new(point.x, point.y);
                }
                sum
            };
            sum * (T::one() / n)
        }
    }

    impl<T> Average for Point3<T>
    where
        T: AddAssign + BaseNum + MulAssign + NumCast,
    {
        fn average<I>(values: I) -> Self
        where
            I: IntoIterator<Item = Self>,
        {
            let values = values.into_iter().collect::<Vec<_>>();
            let n = <T as NumCast>::from(values.len()).unwrap();
            let sum = {
                let mut sum = Point3::origin();
                for point in values {
                    sum += Vector3::<T>::new(point.x, point.y, point.z);
                }
                sum
            };
            sum * (T::one() / n)
        }
    }

    impl<T> Interpolate for Point2<T>
    where
        T: BaseNum + NumCast,
    {
        type Output = Self;

        fn lerp(self, other: Self, f: f64) -> Self::Output {
            Point2::new(
                geometry::lerp(self.x, other.x, f),
                geometry::lerp(self.y, other.y, f),
            )
        }
    }

    impl<T> Interpolate for Point3<T>
    where
        T: BaseNum + NumCast,
    {
        type Output = Self;

        fn lerp(self, other: Self, f: f64) -> Self::Output {
            Point3::new(
                geometry::lerp(self.x, other.x, f),
                geometry::lerp(self.y, other.y, f),
                geometry::lerp(self.z, other.z, f),
            )
        }
    }

    impl<T> Interpolate for Vector2<T>
    where
        T: BaseNum + NumCast,
    {
        type Output = Self;

        fn lerp(self, other: Self, f: f64) -> Self::Output {
            Vector2::new(
                geometry::lerp(self.x, other.x, f),
                geometry::lerp(self.y, other.y, f),
            )
        }
    }

    impl<T> Interpolate for Vector3<T>
    where
        T: BaseNum + NumCast,
    {
        type Output = Self;

        fn lerp(self, other: Self, f: f64) -> Self::Output {
            Vector3::new(
                geometry::lerp(self.x, other.x, f),
                geometry::lerp(self.y, other.y, f),
                geometry::lerp(self.z, other.z, f),
            )
        }
    }

    impl<T> Dot for Vector2<T>
    where
        T: BaseFloat + BaseNum,
    {
        type Output = T;

        fn dot(self, other: Self) -> Self::Output {
            <Self as InnerSpace>::dot(self, other)
        }
    }

    impl<T> Dot for Vector3<T>
    where
        T: BaseFloat + BaseNum,
    {
        type Output = T;

        fn dot(self, other: Self) -> Self::Output {
            <Self as InnerSpace>::dot(self, other)
        }
    }

    impl<T> Cross for Vector3<T>
    where
        T: BaseFloat + BaseNum,
    {
        type Output = Self;

        fn cross(self, other: Self) -> Self::Output {
            Self::cross(self, other)
        }
    }
}

#[cfg(feature = "geometry-nalgebra")]
mod feature_geometry_nalgebra {
    use alga::general::Real;
    use nalgebra::{Point2, Point3, Scalar, Vector2, Vector3};
    use nalgebra::core::Matrix;
    use num::{Float, Num, NumCast};
    use std::ops::{AddAssign, MulAssign};

    use geometry;
    use geometry::ops::*;

    impl<T> Normalize for Vector2<T>
    where
        T: Float + Real + Scalar,
    {
        fn normalize(self) -> Self {
            Matrix::normalize(&self)
        }
    }

    impl<T> Normalize for Vector3<T>
    where
        T: Float + Real + Scalar,
    {
        fn normalize(self) -> Self {
            Matrix::normalize(&self)
        }
    }

    // TODO: Implement `Average` for points and vectors of arbitrary dimension.
    impl<T> Average for Point2<T>
    where
        T: AddAssign + MulAssign + Num + NumCast + Scalar,
    {
        fn average<I>(values: I) -> Self
        where
            I: IntoIterator<Item = Self>,
        {
            let values = values.into_iter().collect::<Vec<_>>();
            let n = <T as NumCast>::from(values.len()).unwrap();
            let sum = {
                let mut sum = Point2::origin();
                for point in values {
                    sum += Vector2::<T>::new(point.x, point.y);
                }
                sum
            };
            sum * (T::one() / n)
        }
    }

    impl<T> Average for Point3<T>
    where
        T: AddAssign + MulAssign + Num + NumCast + Scalar,
    {
        fn average<I>(values: I) -> Self
        where
            I: IntoIterator<Item = Self>,
        {
            let values = values.into_iter().collect::<Vec<_>>();
            let n = <T as NumCast>::from(values.len()).unwrap();
            let sum = {
                let mut sum = Point3::origin();
                for point in values {
                    sum += Vector3::<T>::new(point.x, point.y, point.z);
                }
                sum
            };
            sum * (T::one() / n)
        }
    }

    impl<T> Interpolate for Point2<T>
    where
        T: Num + NumCast + Scalar,
    {
        type Output = Self;

        fn lerp(self, other: Self, f: f64) -> Self::Output {
            Point2::new(
                geometry::lerp(self.x, other.x, f),
                geometry::lerp(self.y, other.y, f),
            )
        }
    }

    impl<T> Interpolate for Point3<T>
    where
        T: Num + NumCast + Scalar,
    {
        type Output = Self;

        fn lerp(self, other: Self, f: f64) -> Self::Output {
            Point3::new(
                geometry::lerp(self.x, other.x, f),
                geometry::lerp(self.y, other.y, f),
                geometry::lerp(self.z, other.z, f),
            )
        }
    }

    impl<T> Interpolate for Vector2<T>
    where
        T: Num + NumCast + Scalar,
    {
        type Output = Self;

        fn lerp(self, other: Self, f: f64) -> Self::Output {
            Vector2::new(
                geometry::lerp(self.x, other.x, f),
                geometry::lerp(self.y, other.y, f),
            )
        }
    }

    impl<T> Interpolate for Vector3<T>
    where
        T: Num + NumCast + Scalar,
    {
        type Output = Self;

        fn lerp(self, other: Self, f: f64) -> Self::Output {
            Vector3::new(
                geometry::lerp(self.x, other.x, f),
                geometry::lerp(self.y, other.y, f),
                geometry::lerp(self.z, other.z, f),
            )
        }
    }

    impl<T> Dot for Vector2<T>
    where
        T: AddAssign + Float + MulAssign + Scalar,
    {
        type Output = T;

        fn dot(self, other: Self) -> Self::Output {
            Matrix::dot(&self, &other)
        }
    }

    impl<T> Dot for Vector3<T>
    where
        T: AddAssign + Float + MulAssign + Scalar,
    {
        type Output = T;

        fn dot(self, other: Self) -> Self::Output {
            Matrix::dot(&self, &other)
        }
    }

    impl<T> Cross for Vector3<T>
    where
        T: Float + Real + Scalar,
    {
        type Output = Self;

        fn cross(self, other: Self) -> Self::Output {
            Matrix::cross(&self, &other)
        }
    }
}
<|endoftext|>


<commit_before>use std::sync::atomic::{AtomicBool, Ordering};
use std::cmp::max;

use game::{Position, Move, Score, ScoreUnit, NumPlies};
use types::{Data};

use transposition_table::TranspositionTable;

#[derive(Copy, Clone, Debug)]
pub enum Bound {
    Exact(Score),
    Lower(Score),
    Upper(Score),
}
impl Bound {
    pub fn as_score(self) -> Score {
        match self {
            Bound::Exact(x) => x,
            Bound::Lower(x) => x,
            Bound::Upper(x) => x,
        }
    }
    pub fn is_exact(self) -> bool {
        if let Bound::Exact(_) = self { true } else { false }
    }
    pub fn is_lower(self) -> bool {
        if let Bound::Lower(_) = self { true } else { false }
    }
    pub fn is_upper(self) -> bool {
        if let Bound::Upper(_) = self { true } else { false }
    }
}

// TODO put more parameters here
#[derive(Clone)]
pub struct Param {
    pub draw_val: ScoreUnit,
    pub depth: Option<NumPlies>,
}

pub fn negamax(pos: &mut Position,
               alpha: Option<Score>,
               beta: Option<Score>,
               param: Param,
               table: &mut TranspositionTable,
               is_killed: &AtomicBool) -> (Bound, Data) {
    negamax_generic(pos, alpha, beta, param, table, is_killed,
                    &mut |x| Box::new(x.legal_iter()),
                    &mut |x, draw_val, inner_alpha, inner_beta, table| {
                        let quiescence_param = Param {
                            draw_val: draw_val,
                            depth: None,
                        };
                        quiescence(x, inner_alpha, inner_beta, quiescence_param, table, is_killed)
                    },
                    &mut |_, _| None)
}

fn quiescence(pos: &mut Position,
              alpha: Option<Score>,
              beta: Option<Score>,
              param: Param,
              table: &mut TranspositionTable,
              is_killed: &AtomicBool) -> (Bound, Data) {
    negamax_generic(pos, alpha, beta, param, table, is_killed,
                    &mut |x| Box::new(x.legal_noisy_iter()),
                    &mut |x, draw_val, _, _, _| (Bound::Exact(x.eval(draw_val)), Data::one_node()),
                    &mut |x, draw_val| Some(x.eval(draw_val)))
}

// TODO somehow eliminate the Box
fn negamax_generic<F, G, H>(pos: &mut Position,
                            alpha: Option<Score>,
                            beta: Option<Score>,
                            param: Param,
                            table: &mut TranspositionTable,
                            is_killed: &AtomicBool,
                            move_gen_fn: &mut F,
                            eval_fn: &mut G,
                            stand_pat_fn: &mut H) -> (Bound, Data) where
for<'a> F: FnMut(&'a Position) -> Box<Iterator<Item = Move> + 'a>,
for<'b> G: FnMut(&'b mut Position, ScoreUnit, Option<Score>, Option<Score>,
                 &mut TranspositionTable) -> (Bound, Data),
for<'c> H: FnMut(&'c mut Position, ScoreUnit) -> Option<Score> {
    if is_killed.load(Ordering::Relaxed) {
        return (Bound::Exact(Score::Value(ScoreUnit(0))), Data::one_node());
    }
    if param.depth == Some(NumPlies(0)) {
        let ans = eval_fn(pos, param.draw_val, alpha, beta, table);
        table.set(pos, NumPlies(0), ans.0);
        return ans;
    }

    if let Some(data_ref) = table.get(pos) {
        if data_ref.depth >= param.depth.unwrap_or(NumPlies(0)) {
            let table_bound = data_ref.bound;
            let lower_than_alpha = alpha.is_some() &&
                                   !table_bound.is_lower() &&
                                   table_bound.as_score() <= alpha.unwrap();
            if lower_than_alpha { return (Bound::Upper(alpha.unwrap()), Data::one_node()); }
            let higher_than_beta = beta.is_some() &&
                                   !table_bound.is_upper() &&
                                   table_bound.as_score() >= beta.unwrap();
            if higher_than_beta { return (Bound::Lower(beta.unwrap()), Data::one_node()); }
            if table_bound.is_exact() { return (table_bound, Data::one_node()); }
        }
    }

    let (has_legal, score_opt, data): (bool, Option<Score>, Data) = (|| {
        let temp = pos.clone();
        let move_iter = move_gen_fn(&temp);

        let mut has_legal = false;
        let mut prev_score_opt: Option<Score> = alpha;

        if let Some(stand_pat_score) = stand_pat_fn(pos, param.draw_val) {
            let new_score = match prev_score_opt {
                None => stand_pat_score,
                Some(prev_score) => max(prev_score, stand_pat_score),
            };

            has_legal = true;
            prev_score_opt = Some(new_score);

            if let Some(beta_val) = beta {
                if new_score >= beta_val {
                    return (true, beta, Data::one_node());
                }
            }
        }

        let mut prev_data = Data::one_node();

        for curr_move in move_iter {

            let new_alpha = beta.map(|x| x.decrement());
            let new_beta = prev_score_opt.map(|x| x.decrement());
            let new_param = Param {
                draw_val: -param.draw_val,
                depth: param.depth.map(|x| NumPlies(x.0 - 1))
            };
            let (temp_bound, temp_data) = pos.with_move(&curr_move, |new_pos|
                negamax_generic(new_pos,
                                new_alpha,
                                new_beta,
                                new_param,
                                table,
                                is_killed,
                                move_gen_fn,
                                eval_fn,
                                stand_pat_fn));
            let curr_score = temp_bound.as_score().increment();
            let curr_data = temp_data.increment();

            let new_score = match prev_score_opt {
                None => curr_score,
                Some(prev_score) => max(prev_score, curr_score),
            };
            let new_data = prev_data.combine(curr_data);

            has_legal = true;
            prev_score_opt = Some(new_score);
            prev_data = new_data;

            if let Some(beta_val) = beta {
                if new_score >= beta_val {
                    prev_score_opt = beta;
                    break;
                }
            }
        }

        (has_legal, prev_score_opt, prev_data)
    })();

    if has_legal {
        let score = score_opt.unwrap();
        let bound = {
            if alpha.is_some() && score <= alpha.unwrap() {
                Bound::Upper(alpha.unwrap())
            } else if beta.is_some() && score >= beta.unwrap() {
                Bound::Lower(beta.unwrap())
            } else {
                Bound::Exact(score)
            }
        };
        table.set(pos, param.depth.unwrap_or(NumPlies(0)), bound);
        (bound, data)
    } else {
        let ans = eval_fn(pos, param.draw_val, alpha, beta, table);
        table.set(pos, param.depth.unwrap_or(NumPlies(0)), ans.0);
        ans
    }
}
<commit_msg>Check table before checking zero depth<commit_after>use std::sync::atomic::{AtomicBool, Ordering};
use std::cmp::max;

use game::{Position, Move, Score, ScoreUnit, NumPlies};
use types::{Data};

use transposition_table::TranspositionTable;

#[derive(Copy, Clone, Debug)]
pub enum Bound {
    Exact(Score),
    Lower(Score),
    Upper(Score),
}
impl Bound {
    pub fn as_score(self) -> Score {
        match self {
            Bound::Exact(x) => x,
            Bound::Lower(x) => x,
            Bound::Upper(x) => x,
        }
    }
    pub fn is_exact(self) -> bool {
        if let Bound::Exact(_) = self { true } else { false }
    }
    pub fn is_lower(self) -> bool {
        if let Bound::Lower(_) = self { true } else { false }
    }
    pub fn is_upper(self) -> bool {
        if let Bound::Upper(_) = self { true } else { false }
    }
}

// TODO put more parameters here
#[derive(Clone)]
pub struct Param {
    pub draw_val: ScoreUnit,
    pub depth: Option<NumPlies>,
}

pub fn negamax(pos: &mut Position,
               alpha: Option<Score>,
               beta: Option<Score>,
               param: Param,
               table: &mut TranspositionTable,
               is_killed: &AtomicBool) -> (Bound, Data) {
    negamax_generic(pos, alpha, beta, param, table, is_killed,
                    &mut |x| Box::new(x.legal_iter()),
                    &mut |x, draw_val, inner_alpha, inner_beta, table| {
                        let quiescence_param = Param {
                            draw_val: draw_val,
                            depth: None,
                        };
                        quiescence(x, inner_alpha, inner_beta, quiescence_param, table, is_killed)
                    },
                    &mut |_, _| None)
}

fn quiescence(pos: &mut Position,
              alpha: Option<Score>,
              beta: Option<Score>,
              param: Param,
              table: &mut TranspositionTable,
              is_killed: &AtomicBool) -> (Bound, Data) {
    negamax_generic(pos, alpha, beta, param, table, is_killed,
                    &mut |x| Box::new(x.legal_noisy_iter()),
                    &mut |x, draw_val, _, _, _| (Bound::Exact(x.eval(draw_val)), Data::one_node()),
                    &mut |x, draw_val| Some(x.eval(draw_val)))
}

// TODO somehow eliminate the Box
fn negamax_generic<F, G, H>(pos: &mut Position,
                            alpha: Option<Score>,
                            beta: Option<Score>,
                            param: Param,
                            table: &mut TranspositionTable,
                            is_killed: &AtomicBool,
                            move_gen_fn: &mut F,
                            eval_fn: &mut G,
                            stand_pat_fn: &mut H) -> (Bound, Data) where
for<'a> F: FnMut(&'a Position) -> Box<Iterator<Item = Move> + 'a>,
for<'b> G: FnMut(&'b mut Position, ScoreUnit, Option<Score>, Option<Score>,
                 &mut TranspositionTable) -> (Bound, Data),
for<'c> H: FnMut(&'c mut Position, ScoreUnit) -> Option<Score> {
    if is_killed.load(Ordering::Relaxed) {
        return (Bound::Exact(Score::Value(ScoreUnit(0))), Data::one_node());
    }

    if let Some(data_ref) = table.get(pos) {
        if data_ref.depth >= param.depth.unwrap_or(NumPlies(0)) {
            let table_bound = data_ref.bound;
            let lower_than_alpha = alpha.is_some() &&
                                   !table_bound.is_lower() &&
                                   table_bound.as_score() <= alpha.unwrap();
            if lower_than_alpha { return (Bound::Upper(alpha.unwrap()), Data::one_node()); }
            let higher_than_beta = beta.is_some() &&
                                   !table_bound.is_upper() &&
                                   table_bound.as_score() >= beta.unwrap();
            if higher_than_beta { return (Bound::Lower(beta.unwrap()), Data::one_node()); }
            if table_bound.is_exact() { return (table_bound, Data::one_node()); }
        }
    }

    if param.depth == Some(NumPlies(0)) {
        let ans = eval_fn(pos, param.draw_val, alpha, beta, table);
        table.set(pos, NumPlies(0), ans.0);
        return ans;
    }

    let (has_legal, score_opt, data): (bool, Option<Score>, Data) = (|| {
        let temp = pos.clone();
        let move_iter = move_gen_fn(&temp);

        let mut has_legal = false;
        let mut prev_score_opt: Option<Score> = alpha;

        if let Some(stand_pat_score) = stand_pat_fn(pos, param.draw_val) {
            let new_score = match prev_score_opt {
                None => stand_pat_score,
                Some(prev_score) => max(prev_score, stand_pat_score),
            };

            has_legal = true;
            prev_score_opt = Some(new_score);

            if let Some(beta_val) = beta {
                if new_score >= beta_val {
                    return (true, beta, Data::one_node());
                }
            }
        }

        let mut prev_data = Data::one_node();

        for curr_move in move_iter {

            let new_alpha = beta.map(|x| x.decrement());
            let new_beta = prev_score_opt.map(|x| x.decrement());
            let new_param = Param {
                draw_val: -param.draw_val,
                depth: param.depth.map(|x| NumPlies(x.0 - 1))
            };
            let (temp_bound, temp_data) = pos.with_move(&curr_move, |new_pos|
                negamax_generic(new_pos,
                                new_alpha,
                                new_beta,
                                new_param,
                                table,
                                is_killed,
                                move_gen_fn,
                                eval_fn,
                                stand_pat_fn));
            let curr_score = temp_bound.as_score().increment();
            let curr_data = temp_data.increment();

            let new_score = match prev_score_opt {
                None => curr_score,
                Some(prev_score) => max(prev_score, curr_score),
            };
            let new_data = prev_data.combine(curr_data);

            has_legal = true;
            prev_score_opt = Some(new_score);
            prev_data = new_data;

            if let Some(beta_val) = beta {
                if new_score >= beta_val {
                    prev_score_opt = beta;
                    break;
                }
            }
        }

        (has_legal, prev_score_opt, prev_data)
    })();

    if has_legal {
        let score = score_opt.unwrap();
        let bound = {
            if alpha.is_some() && score <= alpha.unwrap() {
                Bound::Upper(alpha.unwrap())
            } else if beta.is_some() && score >= beta.unwrap() {
                Bound::Lower(beta.unwrap())
            } else {
                Bound::Exact(score)
            }
        };
        table.set(pos, param.depth.unwrap_or(NumPlies(0)), bound);
        (bound, data)
    } else {
        let ans = eval_fn(pos, param.draw_val, alpha, beta, table);
        table.set(pos, param.depth.unwrap_or(NumPlies(0)), ans.0);
        ans
    }
}
<|endoftext|>


<commit_before>use std::any::Any;
use std::fs::{self, File, Metadata};
use std::io::{self, Write, Error, ErrorKind};
use std::marker::PhantomData;
use std::net::Shutdown;
use std::path::{Path, PathBuf};
use std::process::Command;

use time;
use conduit_mime_types::Types;

use super::{Request, Response};

pub struct FileKind;
pub struct DirectoryKind;

pub trait Handler {
    fn handle(&self, req: &mut Request, res: &mut Response);
}

pub struct ServerHandler<K: Any = FileKind> {
    root: PathBuf,
    mimetypes: Types,
    _kind: PhantomData<K>,
}

impl<K: Any> ServerHandler<K> {
    pub fn new(root: PathBuf) -> ServerHandler<K> {
        let mimetypes = match Types::new() {
            Ok(types) => types,
            Err(error) => panic!(error),
        };

        ServerHandler {
            root: root.to_owned(),
            mimetypes: mimetypes,
            _kind: PhantomData
        }
    }

    fn get_resource_and_metadata(&self, req: &Request)
            -> Result<(PathBuf, Metadata), Error> {

        let path = req.path();
        let path = &path[1..path.len()];

        let resource = self.root.join(path);
        let metadata = try!(fs::metadata(&resource));

        Ok((resource, metadata))
    }

    fn send_file(&self, resource: PathBuf, metadata: Metadata, res: &mut Response) {
        let mut f = File::open(&resource).unwrap();
        let mime = self.mimetypes.mime_for_path(Path::new(&resource));

        let date = time::now_utc();

        res.with_header("Date", format!("{}", date.rfc822()).as_ref());
        res.with_header("Connection", "close");
        res.with_header("Content-Type", mime);
        res.with_header("Content-Length", &metadata.len().to_string());

        let res = res.start().unwrap();
        io::copy(&mut f, res).unwrap();

        // let mut buf: [u8; 4096] = [0; 4096];
        // loop {
        //     match f.read(&mut buf) {
        //         Ok(bytes_read) => {
        //             if bytes_read == 0 {
        //                 break;
        //             }
        //             res.write(&buf[0..bytes_read]).unwrap();
        //         },
        //         Err(e) => panic!(e)
        //     }
        // }
    }

    fn send_not_found(&self, res: &mut Response) {
        res.with_status(404, "Not Found");
        let res = res.start().unwrap();
        res.write("404 - Not Found".as_bytes()).unwrap();
        res.flush().ok().expect("Failed to send error response");
    }

    fn send_error(&self, res: &mut Response) {
        res.with_status(404, "Not Found");
        let res = res.start().unwrap();
        res.write("404 - Not Found".as_bytes()).unwrap();
        res.flush().ok().expect("Failed to send error response");
    }
}

impl Handler for ServerHandler<FileKind> {
    fn handle(&self, req: &mut Request, res: &mut Response) {
        let (resource, metadata) = match self.get_resource_and_metadata(req) {
            Ok(result) => result,
            Err(e) => {
                if e.kind() == ErrorKind::NotFound {
                    self.send_not_found(res);
                } else {
                    self.send_error(res);
                }
                return;
            }
        };

        if !metadata.is_file() {
            self.send_not_found(res);
            return;
        }

        self.send_file(resource, metadata, res);
    }
}

impl Handler for ServerHandler<DirectoryKind> {
    fn handle(&self, req: &mut Request, res: &mut Response) {
        let (resource, metadata) = match self.get_resource_and_metadata(req) {
            Ok(result) => result,
            Err(e) => {
                if e.kind() == ErrorKind::NotFound {
                    self.send_not_found(res);
                } else {
                    self.send_error(res);
                }
                return;
            }
        };

        if metadata.is_file() {
            self.send_file(resource, metadata, res);
            return;
        }

        let output = Command::new("ls")
            .arg(&resource)
            .output()
            .unwrap_or_else(|e| panic!(format!("Failed to list dir: {}", e)));

        let s: String;
        if output.status.success() {
            s = String::from_utf8_lossy(&output.stdout).as_ref().to_owned();
        }
        else {
            s = String::from_utf8_lossy(&output.stderr).as_ref().to_owned();
            panic!("rustc failed and stderr was:\n{}", s);
        }

        let mut path = req.path();
        if path.len() == 1 && path == "/" {
            path = "";
        }

        let res = res.start().unwrap();
        res.write("
".as_bytes()).unwrap();
        for name in s.split('\n') {
            if name.len() == 0 { continue }
            let mut name = name.to_owned();

            let metadata = fs::metadata(Path::new(&resource).join(&name)).unwrap();

            if metadata.is_dir() {
                name = format!("{}/", name);
            }

            res.write(format!("
{1}
", path, name).as_bytes()).unwrap();
        }
        res.write("
".as_bytes()).unwrap();
        res.flush().unwrap();
    }
}
<commit_msg>removed unnecessary import<commit_after>use std::any::Any;
use std::fs::{self, File, Metadata};
use std::io::{self, Write, Error, ErrorKind};
use std::marker::PhantomData;
use std::path::{Path, PathBuf};
use std::process::Command;

use time;
use conduit_mime_types::Types;

use super::{Request, Response};

pub struct FileKind;
pub struct DirectoryKind;

pub trait Handler {
    fn handle(&self, req: &mut Request, res: &mut Response);
}

pub struct ServerHandler<K: Any = FileKind> {
    root: PathBuf,
    mimetypes: Types,
    _kind: PhantomData<K>,
}

impl<K: Any> ServerHandler<K> {
    pub fn new(root: PathBuf) -> ServerHandler<K> {
        let mimetypes = match Types::new() {
            Ok(types) => types,
            Err(error) => panic!(error),
        };

        ServerHandler {
            root: root.to_owned(),
            mimetypes: mimetypes,
            _kind: PhantomData
        }
    }

    fn get_resource_and_metadata(&self, req: &Request)
            -> Result<(PathBuf, Metadata), Error> {

        let path = req.path();
        let path = &path[1..path.len()];

        let resource = self.root.join(path);
        let metadata = try!(fs::metadata(&resource));

        Ok((resource, metadata))
    }

    fn send_file(&self, resource: PathBuf, metadata: Metadata, res: &mut Response) {
        let mut f = File::open(&resource).unwrap();
        let mime = self.mimetypes.mime_for_path(Path::new(&resource));

        let date = time::now_utc();

        res.with_header("Date", format!("{}", date.rfc822()).as_ref());
        res.with_header("Connection", "close");
        res.with_header("Content-Type", mime);
        res.with_header("Content-Length", &metadata.len().to_string());

        let res = res.start().unwrap();
        io::copy(&mut f, res).unwrap();

        // let mut buf: [u8; 4096] = [0; 4096];
        // loop {
        //     match f.read(&mut buf) {
        //         Ok(bytes_read) => {
        //             if bytes_read == 0 {
        //                 break;
        //             }
        //             res.write(&buf[0..bytes_read]).unwrap();
        //         },
        //         Err(e) => panic!(e)
        //     }
        // }
    }

    fn send_not_found(&self, res: &mut Response) {
        res.with_status(404, "Not Found");
        let res = res.start().unwrap();
        res.write("404 - Not Found".as_bytes()).unwrap();
        res.flush().ok().expect("Failed to send error response");
    }

    fn send_error(&self, res: &mut Response) {
        res.with_status(404, "Not Found");
        let res = res.start().unwrap();
        res.write("404 - Not Found".as_bytes()).unwrap();
        res.flush().ok().expect("Failed to send error response");
    }
}

impl Handler for ServerHandler<FileKind> {
    fn handle(&self, req: &mut Request, res: &mut Response) {
        let (resource, metadata) = match self.get_resource_and_metadata(req) {
            Ok(result) => result,
            Err(e) => {
                if e.kind() == ErrorKind::NotFound {
                    self.send_not_found(res);
                } else {
                    self.send_error(res);
                }
                return;
            }
        };

        if !metadata.is_file() {
            self.send_not_found(res);
            return;
        }

        self.send_file(resource, metadata, res);
    }
}

impl Handler for ServerHandler<DirectoryKind> {
    fn handle(&self, req: &mut Request, res: &mut Response) {
        let (resource, metadata) = match self.get_resource_and_metadata(req) {
            Ok(result) => result,
            Err(e) => {
                if e.kind() == ErrorKind::NotFound {
                    self.send_not_found(res);
                } else {
                    self.send_error(res);
                }
                return;
            }
        };

        if metadata.is_file() {
            self.send_file(resource, metadata, res);
            return;
        }

        let output = Command::new("ls")
            .arg(&resource)
            .output()
            .unwrap_or_else(|e| panic!(format!("Failed to list dir: {}", e)));

        let s: String;
        if output.status.success() {
            s = String::from_utf8_lossy(&output.stdout).as_ref().to_owned();
        }
        else {
            s = String::from_utf8_lossy(&output.stderr).as_ref().to_owned();
            panic!("rustc failed and stderr was:\n{}", s);
        }

        let mut path = req.path();
        if path.len() == 1 && path == "/" {
            path = "";
        }

        let res = res.start().unwrap();
        res.write("
".as_bytes()).unwrap();
        for name in s.split('\n') {
            if name.len() == 0 { continue }
            let mut name = name.to_owned();

            let metadata = fs::metadata(Path::new(&resource).join(&name)).unwrap();

            if metadata.is_dir() {
                name = format!("{}/", name);
            }

            res.write(format!("
{1}
", path, name).as_bytes()).unwrap();
        }
        res.write("
".as_bytes()).unwrap();
        res.flush().unwrap();
    }
}
<|endoftext|>


<commit_before>// Copyright 2017 Serde Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![doc(html_root_url = "https://docs.rs/serde_test/0.9.13")]

#[macro_use]
extern crate serde;

mod assert;
pub use assert::{assert_tokens, assert_ser_tokens, assert_ser_tokens_error, assert_de_tokens,
                 assert_de_tokens_error};

mod ser;
pub use ser::Serializer;

mod de;
pub use de::Deserializer;

mod token;
pub use token::Token;

mod error;
pub use error::Error;
<commit_msg>Keep serde_test serializer and deserializer private<commit_after>// Copyright 2017 Serde Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![doc(html_root_url = "https://docs.rs/serde_test/0.9.13")]

#[macro_use]
extern crate serde;

mod assert;
pub use assert::{assert_tokens, assert_ser_tokens, assert_ser_tokens_error, assert_de_tokens,
                 assert_de_tokens_error};

mod ser;
mod de;

mod token;
pub use token::Token;

mod error;
pub use error::Error;
<|endoftext|>