<commit_before>#![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;

/// Implementation of [HPP model](https://en.wikipedia.org/wiki/HPP_model).
/// Assumes Von Nuemann's neighborhood.
#[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 {
    Up,
    Left,
    Right,
    Down,
}

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,
        }
    }
}

#[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() };

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

            match neighbor {

                Some(neighbor) => {
                    let opposite = direction.opposite();
                    let head_on = self.particle(&direction) && neighbor.particle(&opposite) &&
                                  !self.particle(&direction.perpendicular()) &&
                                  !neighbor.particle(&opposite.perpendicular());

                    if head_on {
                        new.set_particle(&direction.perpendicular(), self.particle(&direction));
                    } else {
                        let particle = new.particle(&direction) || self.particle(&direction);
                        new.set_particle(&direction, particle);
                    }
                }
                // Rebound
                None => {
                    if self.particle(&direction) {
                        let opposite = direction.opposite();
                        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, neighbor.particle(&opposite));
                    }
                }
                None => {
                    if self.particle(&direction) {
                        new.set_particle(&direction, true);
                    }
                }
            }
        }

        new
    }

    pub fn particle(&self, direction: &Direction) -> bool {

        match *direction {
            Direction::Up => self.particles[0],
            Direction::Left => self.particles[1],
            Direction::Right => self.particles[2],
            Direction::Down => self.particles[3],
        }
    }

    fn set_particle(&mut self, direction: &Direction, exists: bool) {

        match *direction {
            Direction::Up => self.particles[0] = exists,
            Direction::Left => self.particles[1] = exists,
            Direction::Right => self.particles[2] = exists,
            Direction::Down => self.particles[3] = exists,
        }
    }

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

#[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 find_cell<C: Cell>(&self, 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 test_collision<G: Grid>(&self, grid: &G) {

        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 = self.find_cell(&grid.cells(), 0, 1);
        assert_eq!(rebound_to_right.particle(&Direction::Right), true);

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

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

    fn test_transport<G: Grid>(&self, grid: &G) {

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

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

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

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

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

        for y in 0..3 {
            print!("|");

            for x in 0..3 {
                let cell = self.find_cell(grid.cells(), x, y);
                let directions = cell.directions();
                let maybe_particle = directions.iter().find(|d| cell.particle(d));

                let to_print = match maybe_particle {
                    Some(&Direction::Up) => " ^ |",
                    Some(&Direction::Left) => " < |",
                    Some(&Direction::Right) => " > |",
                    Some(&Direction::Down) => " v |",
                    None => " * |",
                };
                print!("{}", to_print);
            }

            println!("");
        }
    }
}

impl Consumer for HPPRulesTestConsumer {
    type Cell = HPP;

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

        self.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 |
    // | > * * |    | > * * |    | * > * |
    // 3x3 grid with 4 particles. There should be
    // one rebound, head-on collision and simple move.

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

    let cells = vec![
        HPP { stage: Stage::Collision, particles: right_particle, coord: (1, 0) },
        HPP { stage: Stage::Collision, particles: left_particle, coord: (2, 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);

    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 find_cell<C: Cell>(&self, 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>(&self, grid: &G) {
        println!("");

        for y in 0..5 {
            print!("|");

            for x in 0..5 {
                let cell = self.find_cell(grid.cells(), x, y);
                let directions = cell.directions();
                let maybe_particle = directions.iter().find(|d| cell.particle(d));

                let to_print = match maybe_particle {
                    Some(&Direction::Up) => " ^ |",
                    Some(&Direction::Left) => " < |",
                    Some(&Direction::Right) => " > |",
                    Some(&Direction::Down) => " v |",
                    None => " * |",
                };
                print!("{}", to_print);
            }

            println!("");
        }
    }

    fn test_collision<G: Grid>(&mut self, grid: &G) {

        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) {

        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);

        self.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>From usize for Direction.<commit_after>#![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;

/// Implementation of [HPP model](https://en.wikipedia.org/wiki/HPP_model).
/// Assumes Von Nuemann's neighborhood.
#[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 {
    Up,
    Left,
    Right,
    Down,
}

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() };

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

            match neighbor {

                Some(neighbor) => {
                    let opposite = direction.opposite();
                    let head_on = self.particle(&direction) && neighbor.particle(&opposite) &&
                                  !self.particle(&direction.perpendicular()) &&
                                  !neighbor.particle(&opposite.perpendicular());

                    if head_on {
                        new.set_particle(&direction.perpendicular(), self.particle(&direction));
                    } else {
                        let particle = new.particle(&direction) || self.particle(&direction);
                        new.set_particle(&direction, particle);
                    }
                }
                // Rebound
                None => {
                    if self.particle(&direction) {
                        let opposite = direction.opposite();
                        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, neighbor.particle(&opposite));
                    }
                }
                None => {
                    if self.particle(&direction) {
                        new.set_particle(&direction, true);
                    }
                }
            }
        }

        new
    }

    pub fn particle(&self, direction: &Direction) -> bool {

        match *direction {
            Direction::Up => self.particles[0],
            Direction::Left => self.particles[1],
            Direction::Right => self.particles[2],
            Direction::Down => self.particles[3],
        }
    }

    fn set_particle(&mut self, direction: &Direction, exists: bool) {

        match *direction {
            Direction::Up => self.particles[0] = exists,
            Direction::Left => self.particles[1] = exists,
            Direction::Right => self.particles[2] = exists,
            Direction::Down => self.particles[3] = exists,
        }
    }

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

#[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 find_cell<C: Cell>(&self, 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 test_collision<G: Grid>(&self, grid: &G) {

        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 = self.find_cell(&grid.cells(), 0, 1);
        assert_eq!(rebound_to_right.particle(&Direction::Right), true);

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

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

    fn test_transport<G: Grid>(&self, grid: &G) {

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

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

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

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

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

        for y in 0..3 {
            print!("|");

            for x in 0..3 {
                let cell = self.find_cell(grid.cells(), x, y);
                let directions = cell.directions();
                let maybe_particle = directions.iter().find(|d| cell.particle(d));

                let to_print = match maybe_particle {
                    Some(&Direction::Up) => " ^ |",
                    Some(&Direction::Left) => " < |",
                    Some(&Direction::Right) => " > |",
                    Some(&Direction::Down) => " v |",
                    None => " * |",
                };
                print!("{}", to_print);
            }

            println!("");
        }
    }
}

impl Consumer for HPPRulesTestConsumer {
    type Cell = HPP;

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

        self.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 |
    // | > * * |    | > * * |    | * > * |
    // 3x3 grid with 4 particles. There should be
    // one rebound, head-on collision and simple move.

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

    let cells = vec![
        HPP { stage: Stage::Collision, particles: right_particle, coord: (1, 0) },
        HPP { stage: Stage::Collision, particles: left_particle, coord: (2, 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);

    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 find_cell<C: Cell>(&self, 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>(&self, grid: &G) {
        println!("");

        for y in 0..5 {
            print!("|");

            for x in 0..5 {
                let cell = self.find_cell(grid.cells(), x, y);
                let directions = cell.directions();
                let maybe_particle = directions.iter().find(|d| cell.particle(d));

                let to_print = match maybe_particle {
                    Some(&Direction::Up) => " ^ |",
                    Some(&Direction::Left) => " < |",
                    Some(&Direction::Right) => " > |",
                    Some(&Direction::Down) => " v |",
                    None => " * |",
                };
                print!("{}", to_print);
            }

            println!("");
        }
    }

    fn test_collision<G: Grid>(&mut self, grid: &G) {

        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) {

        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);

        self.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>use std::sync::{Barrier, RwLock, Arc, RwLockWriteGuard};
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::atomic::Ordering as AtOrd;
extern crate rand;
use rand::{ThreadRng, Rng};
use rand::distributions::{IndependentSample, Range};

extern crate gr;
use gr::{GI, width_box, split_box, midpoint_box, eps_tol};

extern crate gelpia_utils;
use gelpia_utils::{Quple, INF, NINF, Flt, Parameters};

extern crate function;
use function::FuncObj;

#[derive(Clone)]
pub struct Individual {
    pub solution: Vec<GI>,
    pub fitness: Flt,
}

pub fn ea(x_e: Vec<GI>,
          param: Parameters,
          population: Arc<RwLock<Vec<Individual>>>,
          f_bestag: Arc<RwLock<Flt>>,
          x_bestbb: Arc<RwLock<Vec<GI>>>,
          b1: Arc<Barrier>,
          b2: Arc<Barrier>,
          stop: Arc<AtomicBool>,
          sync: Arc<AtomicBool>,
          fo_c: FuncObj) -> (Flt, Vec<GI>, bool) {
    // Constant function
    if x_e.len() == 0 {
        return (0, x_e, true);
    }
    let input = ea_core(&x_e, &param, &stop, &sync, &b1, &b2, &f_bestag,
                        &x_bestbb, population, &fo_c);
    let ans = fo_c.call(&input).upper();

    (ans, input, true)
}

fn ea_core(x_e: &Vec<GI>, param: &Parameters, stop: &Arc<AtomicBool>,
           sync: &Arc<AtomicBool>, b1: &Arc<Barrier>, b2: &Arc<Barrier>,
           f_bestag: &Arc<RwLock<Flt>>,
           x_bestbb: &Arc<RwLock<Vec<GI>>>,
           population: Arc<RwLock<Vec<Individual>>>, fo_c: &FuncObj)
           -> (Vec<GI>) {
    let mut rng = rand::thread_rng();
    let dimension = Range::new(0, x_e.len());
    let mut ranges = Vec::new();
    for g in x_e {
        ranges.push(Range::new(g.lower(), g.upper()));
    }

    while !stop.load(AtOrd::Acquire) {
        if sync.load(AtOrd::Acquire) {
            b1.wait();
            b2.wait();
        }
        let ref mut population = *population.write().unwrap();
        sample(param.population, population, fo_c, &ranges, &mut rng);

        population.sort_by(|a, b| b.fitness.partial_cmp(&a.fitness).unwrap());

        for iteration in 0..100 {
            population.truncate(param.elitism);

            for _ in 0..param.selection {
                population.push(rand_individual(fo_c, &ranges, &mut rng));
            }

            next_generation(param.population, population, fo_c, param.mutation,
                            param.crossover, &dimension, &ranges, &mut rng);
            population.sort_by(|a, b| b.fitness.partial_cmp(&a.fitness).unwrap());

            // Report fittest of the fit.
            {
                let mut fbest = f_bestag.write().unwrap();

                *fbest =
                    if *fbest < population[0].fitness { population[0].fitness }
                else { *fbest };
            }

            // Kill worst of the worst
            let mut ftg = Vec::new();
            {
                let bestbb = x_bestbb.read().unwrap();
                // From The Gods
                for i in 0..bestbb.len() {
                    ftg.push(Range::new(bestbb[i].lower(), bestbb[i].upper()));
                }
            }
            let worst_ind = population.len() - 1;
            population[worst_ind] = rand_individual(fo_c,
                                                    &ftg,
                                                    &mut rng);
            population.sort_by(|a, b| b.fitness.partial_cmp(&a.fitness).unwrap());
        }
    }
    let ref population = *population.read().unwrap();
    let result = population[0].solution.clone();

    result
}

fn sample(population_size: usize, population: &mut Vec<Individual>,
          fo_c: &FuncObj, ranges: &Vec<Range<f64>>, rng: &mut ThreadRng)
          -> () {
    for _ in 0..population_size-population.len() {
        population.push(rand_individual(fo_c, ranges, rng));
    }

    ()
}

fn rand_individual(fo_c: &FuncObj, ranges: &Vec<Range<f64>>, rng: &mut ThreadRng)
                   -> (Individual) {
    let mut new_sol = Vec::new();
    for r in ranges {
        new_sol.push(GI::new_p(r.ind_sample(rng)));
    }
    let fitness = fo_c.call(&new_sol).lower();

    Individual{solution:new_sol, fitness:fitness}
}

fn next_generation(population_size:usize, population: &mut Vec<Individual>,
                   fo_c: &FuncObj, mut_rate: f64, crossover: f64,
                   dimension: &Range<usize>, ranges: &Vec<Range<f64>>,
                   rng: &mut ThreadRng)
                   -> () {

    let elites = population.clone();

    for _ in 0..population_size-population.len() {
        if rng.gen::<f64>() < crossover {
            population.push(breed(rng.choose(&elites).unwrap(),
                                  rng.choose(&elites).unwrap(),
                                  fo_c,
                                  dimension, rng));
        } else {
            population.push(mutate(rng.choose(&elites).unwrap(), fo_c, mut_rate,
                                   dimension, ranges, rng));
        }
    }

    ()
}

fn mutate(input: &Individual, fo_c: &FuncObj, mut_rate: f64,
          dimension: &Range<usize>, ranges: &Vec<Range<f64>>, rng: &mut ThreadRng)
          -> (Individual) {
    let mut output_sol = Vec::new();

    for (r, &ind) in ranges.iter().zip(input.solution.iter()) {
        output_sol.push(
            if rng.gen::<f64>() < mut_rate {
                ind
            } else {
                GI::new_p(r.ind_sample(rng))
            });
    }

    let fitness = fo_c.call(&output_sol).lower();

    Individual{solution: output_sol, fitness: fitness}
}

fn breed(parent1: &Individual, parent2: &Individual, fo_c: &FuncObj,
         dimension: &Range<usize>, rng: &mut ThreadRng) -> (Individual) {
    let mut child = parent1.clone();
    let crossover_point = dimension.ind_sample(rng);
    child.solution.truncate(crossover_point);
    let mut rest = parent2.clone().solution.split_off(crossover_point);
    child.solution.append(&mut rest);
    child.fitness = fo_c.call(&child.solution).lower();
    child
}
<commit_msg>Fixed constant case for GA<commit_after>use std::sync::{Barrier, RwLock, Arc, RwLockWriteGuard};
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::atomic::Ordering as AtOrd;
extern crate rand;
use rand::{ThreadRng, Rng};
use rand::distributions::{IndependentSample, Range};

extern crate gr;
use gr::{GI, width_box, split_box, midpoint_box, eps_tol};

extern crate gelpia_utils;
use gelpia_utils::{Quple, INF, NINF, Flt, Parameters};

extern crate function;
use function::FuncObj;

#[derive(Clone)]
pub struct Individual {
    pub solution: Vec<GI>,
    pub fitness: Flt,
}

pub fn ea(x_e: Vec<GI>,
          param: Parameters,
          population: Arc<RwLock<Vec<Individual>>>,
          f_bestag: Arc<RwLock<Flt>>,
          x_bestbb: Arc<RwLock<Vec<GI>>>,
          b1: Arc<Barrier>,
          b2: Arc<Barrier>,
          stop: Arc<AtomicBool>,
          sync: Arc<AtomicBool>,
          fo_c: FuncObj) -> (Flt, Vec<GI>, bool) {
    // Constant function
    if x_e.len() == 0 {
        return (0.0, x_e, true);
    }
    let input = ea_core(&x_e, &param, &stop, &sync, &b1, &b2, &f_bestag,
                        &x_bestbb, population, &fo_c);
    let ans = fo_c.call(&input).upper();

    (ans, input, true)
}

fn ea_core(x_e: &Vec<GI>, param: &Parameters, stop: &Arc<AtomicBool>,
           sync: &Arc<AtomicBool>, b1: &Arc<Barrier>, b2: &Arc<Barrier>,
           f_bestag: &Arc<RwLock<Flt>>,
           x_bestbb: &Arc<RwLock<Vec<GI>>>,
           population: Arc<RwLock<Vec<Individual>>>, fo_c: &FuncObj)
           -> (Vec<GI>) {
    let mut rng = rand::thread_rng();
    let dimension = Range::new(0, x_e.len());
    let mut ranges = Vec::new();
    for g in x_e {
        ranges.push(Range::new(g.lower(), g.upper()));
    }

    while !stop.load(AtOrd::Acquire) {
        if sync.load(AtOrd::Acquire) {
            b1.wait();
            b2.wait();
        }
        let ref mut population = *population.write().unwrap();
        sample(param.population, population, fo_c, &ranges, &mut rng);

        population.sort_by(|a, b| b.fitness.partial_cmp(&a.fitness).unwrap());

        for iteration in 0..100 {
            population.truncate(param.elitism);

            for _ in 0..param.selection {
                population.push(rand_individual(fo_c, &ranges, &mut rng));
            }

            next_generation(param.population, population, fo_c, param.mutation,
                            param.crossover, &dimension, &ranges, &mut rng);
            population.sort_by(|a, b| b.fitness.partial_cmp(&a.fitness).unwrap());

            // Report fittest of the fit.
            {
                let mut fbest = f_bestag.write().unwrap();

                *fbest =
                    if *fbest < population[0].fitness { population[0].fitness }
                else { *fbest };
            }

            // Kill worst of the worst
            let mut ftg = Vec::new();
            {
                let bestbb = x_bestbb.read().unwrap();
                // From The Gods
                for i in 0..bestbb.len() {
                    ftg.push(Range::new(bestbb[i].lower(), bestbb[i].upper()));
                }
            }
            let worst_ind = population.len() - 1;
            population[worst_ind] = rand_individual(fo_c,
                                                    &ftg,
                                                    &mut rng);
            population.sort_by(|a, b| b.fitness.partial_cmp(&a.fitness).unwrap());
        }
    }
    let ref population = *population.read().unwrap();
    let result = population[0].solution.clone();

    result
}

fn sample(population_size: usize, population: &mut Vec<Individual>,
          fo_c: &FuncObj, ranges: &Vec<Range<f64>>, rng: &mut ThreadRng)
          -> () {
    for _ in 0..population_size-population.len() {
        population.push(rand_individual(fo_c, ranges, rng));
    }

    ()
}

fn rand_individual(fo_c: &FuncObj, ranges: &Vec<Range<f64>>, rng: &mut ThreadRng)
                   -> (Individual) {
    let mut new_sol = Vec::new();
    for r in ranges {
        new_sol.push(GI::new_p(r.ind_sample(rng)));
    }
    let fitness = fo_c.call(&new_sol).lower();

    Individual{solution:new_sol, fitness:fitness}
}

fn next_generation(population_size:usize, population: &mut Vec<Individual>,
                   fo_c: &FuncObj, mut_rate: f64, crossover: f64,
                   dimension: &Range<usize>, ranges: &Vec<Range<f64>>,
                   rng: &mut ThreadRng)
                   -> () {

    let elites = population.clone();

    for _ in 0..population_size-population.len() {
        if rng.gen::<f64>() < crossover {
            population.push(breed(rng.choose(&elites).unwrap(),
                                  rng.choose(&elites).unwrap(),
                                  fo_c,
                                  dimension, rng));
        } else {
            population.push(mutate(rng.choose(&elites).unwrap(), fo_c, mut_rate,
                                   dimension, ranges, rng));
        }
    }

    ()
}

fn mutate(input: &Individual, fo_c: &FuncObj, mut_rate: f64,
          dimension: &Range<usize>, ranges: &Vec<Range<f64>>, rng: &mut ThreadRng)
          -> (Individual) {
    let mut output_sol = Vec::new();

    for (r, &ind) in ranges.iter().zip(input.solution.iter()) {
        output_sol.push(
            if rng.gen::<f64>() < mut_rate {
                ind
            } else {
                GI::new_p(r.ind_sample(rng))
            });
    }

    let fitness = fo_c.call(&output_sol).lower();

    Individual{solution: output_sol, fitness: fitness}
}

fn breed(parent1: &Individual, parent2: &Individual, fo_c: &FuncObj,
         dimension: &Range<usize>, rng: &mut ThreadRng) -> (Individual) {
    let mut child = parent1.clone();
    let crossover_point = dimension.ind_sample(rng);
    child.solution.truncate(crossover_point);
    let mut rest = parent2.clone().solution.split_off(crossover_point);
    child.solution.append(&mut rest);
    child.fitness = fo_c.call(&child.solution).lower();
    child
}
<|endoftext|>


<commit_before>//! Provides a simple SAH split based BVH2 that stores types implementing the Boundable trait

use std::sync::Arc;

use geometry::Boundable;
use linalg::Ray;

pub struct BVH<T> {
    /// Maximum amount of geometry we're willing to put in a leaf
    max_geom: usize,
    /// Reference to the vec containing the unordered objects in the BVH
    objects: Arc<Vec<T>>,
    /// Should this be a vec of references? or of indices?
    /// doing ordered_geom: Vec<&T> seems to be a lifetime annotation nightmare
}

impl<T: Boundable> BVH<T> {
    pub fn new(max_geom: usize, objects: Arc<Vec<T>>) -> BVH<T> {
        BVH { max_geom: max_geom, objects: objects }
    }
    /// Traverse the BVH and call the function passed on the objects in the leaf nodes
    /// of the BVH, returning the value returned by the function after traversal
    /// completes.
    /// TODO: I've tried to base this interface on that of `Iterator::map` however they don't seem
    /// to take `f` as a mutable parameter?
    pub fn intersect<'a, F, R>(&'a self, ray: &mut Ray, f: F) -> Option<R>
            where F: Fn(&mut Ray, &'a T) -> Option<R> {
        let mut result = None;
		for o in &*self.objects {
			result = f(ray, o).or(result);
		}
        result
    }
}

<commit_msg>That shouldn't be a doc comment at the moment<commit_after>//! Provides a simple SAH split based BVH2 that stores types implementing the Boundable trait

use std::sync::Arc;

use geometry::Boundable;
use linalg::Ray;

pub struct BVH<T> {
    /// Maximum amount of geometry we're willing to put in a leaf
    max_geom: usize,
    /// Reference to the vec containing the unordered objects in the BVH
    objects: Arc<Vec<T>>,
    // Should this be a vec of references? or of indices?
    // doing ordered_geom: Vec<&T> seems to be a lifetime annotation nightmare
}

impl<T: Boundable> BVH<T> {
    pub fn new(max_geom: usize, objects: Arc<Vec<T>>) -> BVH<T> {
        BVH { max_geom: max_geom, objects: objects }
    }
    /// Traverse the BVH and call the function passed on the objects in the leaf nodes
    /// of the BVH, returning the value returned by the function after traversal
    /// completes.
    /// TODO: I've tried to base this interface on that of `Iterator::map` however they don't seem
    /// to take `f` as a mutable parameter?
    pub fn intersect<'a, F, R>(&'a self, ray: &mut Ray, f: F) -> Option<R>
            where F: Fn(&mut Ray, &'a T) -> Option<R> {
        let mut result = None;
		for o in &*self.objects {
			result = f(ray, o).or(result);
		}
        result
    }
}

<|endoftext|>


<commit_before>//! Provides a simple SAH split based BVH2 that stores types implementing the Boundable trait

use geometry::Boundable;
use linalg::Ray;

pub struct BVH<T> {
    /// Maximum amount of geometry we're willing to put in a leaf
    max_geom: usize,
    /// The geometry stored in this BVH, this will be re-ordered to
    /// fit the BVH construction layout. TODO: We may want to make
    /// the geometry accessible by index
    geometry: Vec<T>,
}

impl<T: Boundable> BVH<T> {
    /// Create a new BVH using a SAH construction algorithm
    pub fn new(max_geom: usize, geometry: Vec<T>) -> BVH<T> {
        BVH { max_geom: max_geom, geometry: geometry }
    }
    /// Traverse the BVH and call the function passed on the objects in the leaf nodes
    /// of the BVH, returning the value returned by the function after traversal completes
    pub fn intersect<'a, F, R>(&'a self, ray: &mut Ray, f: F) -> Option<R>
            where F: Fn(&mut Ray, &'a T) -> Option<R> {
        let mut result = None;
		for o in &*self.geometry {
			result = f(ray, o).or(result);
		}
        result
    }
}

<commit_msg>Working on SAH construction of BVH<commit_after>//! Provides a simple SAH split based BVH2 that stores types implementing the Boundable trait

use std::mem;
use std::f32;

use geometry::{BBox, Boundable};
use linalg::{Point, Ray, Axis};

/// A standard BVH2 that stores objects that can report their bounds in some space
/// via the `Boundable` trait. The BVH is constructed using a SAH partitioning scheme
pub struct BVH<T> {
    /// Maximum amount of geometry we're willing to put in a leaf
    max_geom: usize,
    /// The geometry stored in this BVH, this will be re-ordered to
    /// fit the BVH construction layout. TODO: We may want to make
    /// the geometry accessible by index
    geometry: Vec<T>,
}

/// Information about the location and bounds of some geometry
struct GeomInfo<'a, T: 'a> {
    geom: &'a T,
    geom_idx: usize,
    center: Point,
    bounds: BBox,
}

impl<'a, T: Boundable> GeomInfo<'a, T> {
    /// Create a new reference to some geometry
    fn new(geom: &'a T, geom_idx: usize) -> GeomInfo<T> {
        let bounds = geom.bounds();
        GeomInfo { geom: geom, geom_idx: geom_idx,
                   center: bounds.lerp(0.5, 0.5, 0.5),
                   bounds: bounds }
    }
}

/// Data needed by a build node during construction
enum BuildNodeData {
    /// Interior node of a BVH, stores two child nodes
    Interior {
        /// Left and Right children of the node
        children: [Box<BuildNode>; 2],
        /// Axis that geomtry was partitioned along to split into
        /// the child nodes
        split_axis: Axis,
    },
    /// Leaf node of a BVH, stores geometry
    Leaf {
        /// Number of objects stored in this node
        ngeom: usize,
        /// Offset into the array holding the sorted geometry
        geom_offset: usize,
    },
}

/// Temporary datastructure for constructing the BVH into a tree before
/// flattening it down into a Vec for performance
struct BuildNode {
    /// The data stored at this node, either information about an Interior
    /// or Lead node
    node: BuildNodeData,
    /// Bounding box of this node
    bounds: BBox,
}

impl BuildNode {
    fn interior(children: [Box<BuildNode>; 2], split_axis: Axis) -> BuildNode {
        let bounds = children[0].bounds.box_union(&children[1].bounds);
        BuildNode { node: BuildNodeData::Interior { children: children, split_axis: split_axis },
                    bounds: bounds }
    }
    fn leaf(ngeom: usize, geom_offset: usize, bounds: BBox) -> BuildNode {
        BuildNode { node: BuildNodeData::Leaf { ngeom: ngeom, geom_offset: geom_offset }, bounds: bounds }
    }
}

#[derive(Copy, Clone)]
struct SAHBucket {
    count: usize,
    bounds: BBox,
}

impl SAHBucket {
    /// Return a SAHBucket with no items and degenerate bounds
    fn new() -> SAHBucket {
        SAHBucket { count: 0, bounds: BBox::new() }
    }
}

impl<T: Boundable> BVH<T> {
    /// Create a new BVH using a SAH construction algorithm
    pub fn new(max_geom: usize, mut geometry: Vec<T>) -> BVH<T> {
        assert!(!geometry.is_empty());
        {
            let mut build_geom = Vec::with_capacity(geometry.len());
            for (i, g) in geometry.iter().enumerate() {
                build_geom.push(GeomInfo::new(g, i));
            }
            // TODO: How to sort the geometry into the flatten tree ordering?
            // we have the indices things should end up in stored in ordered geom
            // but how to use this information in sort_by for example?
            // Should we move things into/out of build_geom instead of borrowing?
            // it knows the index of the items
            let mut total_nodes = 0;
            let mut ordered_geom = Vec::with_capacity(geometry.len());
            let root = BVH::build(&mut build_geom[..], &mut ordered_geom, &mut total_nodes,
                                  max_geom);
        }
        // TODO: does the BVH even need to store max geom after building?
        BVH { max_geom: max_geom, geometry: geometry }
    }
    /// Traverse the BVH and call the function passed on the objects in the leaf nodes
    /// of the BVH, returning the value returned by the function after traversal completes
    pub fn intersect<'a, F, R>(&'a self, ray: &mut Ray, f: F) -> Option<R>
            where F: Fn(&mut Ray, &'a T) -> Option<R> {
        let mut result = None;
		for o in &*self.geometry {
			result = f(ray, o).or(result);
		}
        result
    }
    /// Construct the BVH tree using SAH splitting heuristic to determine split locations
    /// returns the root node of the subtree constructed over the slice of geom info passed
    /// and will increment `total_nodes` by the number of nodes in this subtree
    /// `ordered_geom` will be filled out with the indices of the geometry in the flattened
    /// tree ordering for more efficient access
    fn build(build_info: &mut [GeomInfo<T>], ordered_geom: &mut Vec<usize>,
             total_nodes: &mut usize, max_geom: usize) -> BuildNode {
        *total_nodes += 1;
        // Find bounding box for all geometry we're trying to store at this level
        let bounds = build_info.iter().fold(BBox::new(), |b, g| b.box_union(&g.geom.bounds()));
        let ngeom = build_info.len();
        if ngeom == 1 {
            return BVH::build_leaf(build_info, ordered_geom, bounds);
        }
        // Time to build an interior node
        // Start by figuring out which axis we should be splitting on by finding
        // the axis along which there is the most variation in the geometry's centroids
        let centroids = build_info.iter().fold(BBox::new(), |b, g| b.point_union(&g.center));
        let split_axis = centroids.max_extent();
        let mid = build_info.len() / 2;
        // If all the geometry's centers are on the same point there's no partitioning that makes
        // sense to do
        if centroids.max[split_axis] == centroids.min[split_axis] {
            if ngeom < max_geom {
                return BVH::build_leaf(&mut build_info[..], ordered_geom, bounds);
            } else {
                let l = Box::new(BVH::build(&mut build_info[..mid], ordered_geom,
                                            total_nodes, max_geom));
                let r = Box::new(BVH::build(&mut build_info[mid..], ordered_geom,
                                            total_nodes, max_geom));
                return BuildNode::interior([l, r], split_axis);
            }
        }
        // If there's only a few objects just use an equal partitioning to split
        // Otherwise do a full SAH based split on the geometry
        if ngeom < 5 {
            // TODO: I'd prefer to use something like nth_element like I do in tray
            // here, but I guess a full sort is kind of meh on 5 elements
            // There shouldn't be NaNs in these positions so just give up if there are
            build_info.sort_by(|a, b| {
                match a.center[split_axis].partial_cmp(&b.center[split_axis]) {
                    Some(o) => o,
                    None => panic!("NaNs in build info centers?!"),
                }
            });
        } else {
            // We only consider binning into 12 buckets
            let mut buckets = [SAHBucket::new(); 12];
            // Place geometry into nearest bucket
            for g in build_info.iter() {
                let b = ((g.center[split_axis] - centroids.min[split_axis])
                    / (centroids.max[split_axis] - centroids.min[split_axis]) * buckets.len() as f32) as usize;
                let b = if b == buckets.len() { b - 1 } else { b };
                buckets[b].count += 1;
                buckets[b].bounds = buckets[b].bounds.box_union(&g.bounds);
            }
            // Compute cost of each bucket but the last using the surface area heuristic
            let mut cost = [0.0; 11];
            for (i, c) in cost.iter_mut().enumerate() {
                let left = buckets.iter().take(i).fold(SAHBucket::new(), |mut s, b| {
                    s.bounds = s.bounds.box_union(&b.bounds);
                    s.count += b.count;
                    s
                });
                let right = buckets.iter().skip(i).fold(SAHBucket::new(), |mut s, b| {
                    s.bounds = s.bounds.box_union(&b.bounds);
                    s.count += b.count;
                    s
                });
                *c = 0.125 * (left.count as f32 * left.bounds.surface_area()
                             + right.count as f32 * right.bounds.surface_area()) / bounds.surface_area();
            }
            let (min_bucket, min_cost) = cost.iter().enumerate().fold((0, f32::INFINITY),
                |(pi, pc), (i, c)| {
                    if *c < pc { (i, *c) } else { (pi, pc) }
                });
            // If we're forced to split by the amount of geometry or it's cheaper to split, do so
            if ngeom > max_geom || min_cost < ngeom as f32 {
                // TODO: Implement partition
            }
        }
        let l = Box::new(BVH::build(&mut build_info[..mid], ordered_geom,
                                    total_nodes, max_geom));
        let r = Box::new(BVH::build(&mut build_info[mid..], ordered_geom,
                                    total_nodes, max_geom));
        return BuildNode::interior([l, r], split_axis);
    }
    /// Construct a new leaf node containing the passed geometry. Indices will be
    /// added to `ordered_geom` to instruct how the flattened tree should be placed
    /// in memory for the geometry in this leaf node
    fn build_leaf(build_info: &mut [GeomInfo<T>], ordered_geom: &mut Vec<usize>, bounds: BBox)
        -> BuildNode {
        let geom_offset = ordered_geom.len();
        // TODO: Function to append an iterator? Then we don't need this loop and
        // could do like: `ordered_geom.append(build_info.map(|g| g.geom_idx))`
        for g in build_info.iter() {
            ordered_geom.push(g.geom_idx);
        }
        BuildNode::leaf(build_info.len(), geom_offset, bounds)
    }
}

pub fn partition<'a, T: 'a, I, F>(mut it: I, pred: F) -> usize
        where I: DoubleEndedIterator<Item = &'a mut T>,
        F: Fn(&T) -> bool {
    let mut split_idx = 0;
    loop {
        let mut front = None;
        let mut back = None;
        while let Some(f) = it.next() {
            if pred(f) {
                split_idx += 1;
            } else {
                front = Some(f);
                break;
            }
        }
        while let Some(b) = it.next_back() {
            if pred(b) {
                back = Some(b);
                break;
            }
        }
        match (front, back) {
            (Some(f), Some(b)) => mem::swap(f, b),
            _ => break,
        }
    }
    split_idx
}

<|endoftext|>


<commit_before>extern crate conrod;
extern crate glutin_window;
extern crate graphics;
extern crate rebind;
extern crate piston;
extern crate opengl_graphics;
extern crate viewport;

use conrod::Color;
use conrod::color::{black, green, red};
use glutin_window::GlutinWindow;
use graphics::*;
use opengl_graphics::{GlGraphics, OpenGL};
use piston::event_loop::{EventMap, Events};
use piston::input::{
    Event,
    Input,
    Motion,
    RenderArgs,
    RenderEvent,
    UpdateArgs,
    UpdateEvent
};
use piston::input::keyboard::Key;
use piston::input::Button::Keyboard;
use piston::window::{Window, WindowSettings};
use rebind::{Action, InputTranslator, RebindBuilder, Translated};
use std::cell::RefCell;
use std::rc::Rc;

type RcWindow = Rc<RefCell<GlutinWindow>>;
type RcGraphics = Rc<RefCell<GlGraphics>>;

struct App {
    window: RcWindow,
    graphics: RcGraphics,
    translator: InputTranslator<CharacterAction>,
    character: Character,
    cursor: VirtualCursor,
    bg_color: Color
}

impl App {
    fn input(&mut self, input: &Input) {
        if let Some(t) = self.translator.translate(input) {
            match t {
                Translated::Press(action) => {
                    const CHARACTER_WALK_SPEED_INCREMENT: f64 = 400.0;
                    match action {
                        CharacterAction::Jump => {
                            println!("You jumped! Yay!");
                        },
                        CharacterAction::MoveLeft => {
                            if self.character.current_velocity[0] > (self.character.max_velocity[0] * -1.0) {
                                self.character.current_velocity[0] -= CHARACTER_WALK_SPEED_INCREMENT;
                            }
                        },
                        CharacterAction::MoveRight => {
                            if self.character.current_velocity[0] < self.character.max_velocity[0] {
                                self.character.current_velocity[0] += CHARACTER_WALK_SPEED_INCREMENT;
                            }
                        }
                    }
                },
                Translated::Release(_) => {
                    self.character.current_velocity = [0.0, 0.0];
                },
                Translated::Move(Motion::MouseCursor(x, y)) => {
                    self.cursor.position = [x, y];
                },
                _ => { }
            }
        }
    }

    fn update(&mut self, args: &UpdateArgs, window: RcWindow) {
        // we need to pass the window to update (and set the size here) because using
        // the update event from the window events queue is currently broken.
        self.translator.set_size(window.borrow().size());

        // update the character's velocity
        let ctl = self.character.topleft;
        let v = self.character.current_velocity;

        self.character.topleft = [ctl[0] + (v[0] * args.dt), ctl[1] + (v[1] * args.dt)];
    }

    fn render(&mut self, args: &RenderArgs) {
        let mut gl_graphics = self.graphics.borrow_mut();

        // draw the background color
        {
            gl_graphics.draw(args.viewport(), |_, gl| clear(self.bg_color.to_fsa(), gl));
        }

        // draw the character
        {
            let square = rectangle::square(self.character.topleft[0],
                                           self.character.topleft[1],
                                           self.character.size);

            gl_graphics.draw(args.viewport(), |c, gl| rectangle(self.character.color.to_fsa(),
                                                                square,
                                                                c.transform,
                                                                gl));
        }

        // draw the cursor dot
        {
            let dot = ellipse::circle(self.cursor.position[0],
                                      self.cursor.position[1],
                                      self.cursor.size);
            gl_graphics.draw(args.viewport(), |c, gl| ellipse(self.cursor.color.to_fsa(),
                                                              dot,
                                                              c.transform,
                                                              gl));
        }
    }
}

struct Character {
    color: Color,
    topleft: [f64; 2],
    current_velocity: [f64; 2],
    max_velocity: [f64; 2],
    size: f64
}

impl Character {
    fn new(col: Color, tl: [f64; 2], sz: f64) -> Self {
        Character {
            color: col,
            topleft: tl,
            current_velocity: [0.0, 0.0],
            max_velocity: [800.0, 0.0],
            size: sz
        }
    }
}

struct VirtualCursor {
    position: [f64; 2],
    color: Color,
    size: f64
}

impl VirtualCursor {
    fn new() -> Self {
        VirtualCursor {
            position: [0.0, 0.0],
            color: green(),
            size: 5.0
        }
    }
}

#[derive(Copy, Clone, Eq, Hash, Ord, PartialEq, PartialOrd)]
enum CharacterAction {
    Jump,
    MoveLeft,
    MoveRight
}

impl Action for CharacterAction { }

fn main() {
    const OPENGL: OpenGL = OpenGL::V3_2;
    const WINDOW_SIZE: (u32, u32) = (800, 600);

    let window = WindowSettings::new("calaxite", WINDOW_SIZE)
        .exit_on_esc(true)
        .fullscreen(false)
        .opengl(OPENGL)
        .vsync(true)
        .build()
        .ok()
        .expect("Could not create window: {}");

    let gl_graphics = GlGraphics::new(OPENGL);

    let translator = RebindBuilder::new(WINDOW_SIZE)
        .with_action_mapping(Keyboard(Key::Space), CharacterAction::Jump)
        .with_action_mapping(Keyboard(Key::Left),  CharacterAction::MoveLeft)
        .with_action_mapping(Keyboard(Key::A),     CharacterAction::MoveLeft)
        .with_action_mapping(Keyboard(Key::Right), CharacterAction::MoveRight)
        .with_action_mapping(Keyboard(Key::D),     CharacterAction::MoveRight)
        .y_motion_inverted(true)
        .build_translator();

    let character = {
        const INITIAL_CHARACTER_POS: [f64; 2] = [WINDOW_SIZE.0 as f64 / 20.0,
                                                 WINDOW_SIZE.1 as f64 * 0.85];
        Character::new(red(), INITIAL_CHARACTER_POS, 50.0)
    };

    let mut app = App {
        window: Rc::new(RefCell::new(window)),
        graphics: Rc::new(RefCell::new(gl_graphics)),
        translator: translator,
        character: character,
        cursor: VirtualCursor::new(),
        bg_color: black()
    };

    for e in  app.window.clone().events() {
        let app_window = app.window.clone();
        match e {
            Event::Render(r) => { app.render(&r); },
            Event::Update(u) => { app.update(&u, app_window); },
            Event::Input(i) => { app.input(&i); },
            _ => { }
        }
    }
}
<commit_msg>Remove trailing newline<commit_after>extern crate conrod;
extern crate glutin_window;
extern crate graphics;
extern crate rebind;
extern crate piston;
extern crate opengl_graphics;
extern crate viewport;

use conrod::Color;
use conrod::color::{black, green, red};
use glutin_window::GlutinWindow;
use graphics::*;
use opengl_graphics::{GlGraphics, OpenGL};
use piston::event_loop::{EventMap, Events};
use piston::input::{
    Event,
    Input,
    Motion,
    RenderArgs,
    RenderEvent,
    UpdateArgs,
    UpdateEvent
};
use piston::input::keyboard::Key;
use piston::input::Button::Keyboard;
use piston::window::{Window, WindowSettings};
use rebind::{Action, InputTranslator, RebindBuilder, Translated};
use std::cell::RefCell;
use std::rc::Rc;

type RcWindow = Rc<RefCell<GlutinWindow>>;
type RcGraphics = Rc<RefCell<GlGraphics>>;

struct App {
    window: RcWindow,
    graphics: RcGraphics,
    translator: InputTranslator<CharacterAction>,
    character: Character,
    cursor: VirtualCursor,
    bg_color: Color
}

impl App {
    fn input(&mut self, input: &Input) {
        if let Some(t) = self.translator.translate(input) {
            match t {
                Translated::Press(action) => {
                    const CHARACTER_WALK_SPEED_INCREMENT: f64 = 400.0;
                    match action {
                        CharacterAction::Jump => {
                            println!("You jumped! Yay!");
                        },
                        CharacterAction::MoveLeft => {
                            if self.character.current_velocity[0] > (self.character.max_velocity[0] * -1.0) {
                                self.character.current_velocity[0] -= CHARACTER_WALK_SPEED_INCREMENT;
                            }
                        },
                        CharacterAction::MoveRight => {
                            if self.character.current_velocity[0] < self.character.max_velocity[0] {
                                self.character.current_velocity[0] += CHARACTER_WALK_SPEED_INCREMENT;
                            }
                        }
                    }
                },
                Translated::Release(_) => {
                    self.character.current_velocity = [0.0, 0.0];
                },
                Translated::Move(Motion::MouseCursor(x, y)) => {
                    self.cursor.position = [x, y];
                },
                _ => { }
            }
        }
    }

    fn update(&mut self, args: &UpdateArgs, window: RcWindow) {
        // we need to pass the window to update (and set the size here) because using
        // the update event from the window events queue is currently broken.
        self.translator.set_size(window.borrow().size());

        // update the character's velocity
        let ctl = self.character.topleft;
        let v = self.character.current_velocity;

        self.character.topleft = [ctl[0] + (v[0] * args.dt), ctl[1] + (v[1] * args.dt)];
    }

    fn render(&mut self, args: &RenderArgs) {
        let mut gl_graphics = self.graphics.borrow_mut();

        // draw the background color
        {
            gl_graphics.draw(args.viewport(), |_, gl| clear(self.bg_color.to_fsa(), gl));
        }

        // draw the character
        {
            let square = rectangle::square(self.character.topleft[0],
                                           self.character.topleft[1],
                                           self.character.size);

            gl_graphics.draw(args.viewport(), |c, gl| rectangle(self.character.color.to_fsa(),
                                                                square,
                                                                c.transform,
                                                                gl));
        }

        // draw the cursor dot
        {
            let dot = ellipse::circle(self.cursor.position[0],
                                      self.cursor.position[1],
                                      self.cursor.size);
            gl_graphics.draw(args.viewport(), |c, gl| ellipse(self.cursor.color.to_fsa(),
                                                              dot,
                                                              c.transform,
                                                              gl));
        }
    }
}

struct Character {
    color: Color,
    topleft: [f64; 2],
    current_velocity: [f64; 2],
    max_velocity: [f64; 2],
    size: f64
}

impl Character {
    fn new(col: Color, tl: [f64; 2], sz: f64) -> Self {
        Character {
            color: col,
            topleft: tl,
            current_velocity: [0.0, 0.0],
            max_velocity: [800.0, 0.0],
            size: sz
        }
    }
}

struct VirtualCursor {
    position: [f64; 2],
    color: Color,
    size: f64
}

impl VirtualCursor {
    fn new() -> Self {
        VirtualCursor {
            position: [0.0, 0.0],
            color: green(),
            size: 5.0
        }
    }
}

#[derive(Copy, Clone, Eq, Hash, Ord, PartialEq, PartialOrd)]
enum CharacterAction {
    Jump,
    MoveLeft,
    MoveRight
}

impl Action for CharacterAction { }

fn main() {
    const OPENGL: OpenGL = OpenGL::V3_2;
    const WINDOW_SIZE: (u32, u32) = (800, 600);

    let window = WindowSettings::new("calaxite", WINDOW_SIZE)
        .exit_on_esc(true)
        .fullscreen(false)
        .opengl(OPENGL)
        .vsync(true)
        .build()
        .ok()
        .expect("Could not create window: {}");

    let gl_graphics = GlGraphics::new(OPENGL);

    let translator = RebindBuilder::new(WINDOW_SIZE)
        .with_action_mapping(Keyboard(Key::Space), CharacterAction::Jump)
        .with_action_mapping(Keyboard(Key::Left),  CharacterAction::MoveLeft)
        .with_action_mapping(Keyboard(Key::A),     CharacterAction::MoveLeft)
        .with_action_mapping(Keyboard(Key::Right), CharacterAction::MoveRight)
        .with_action_mapping(Keyboard(Key::D),     CharacterAction::MoveRight)
        .y_motion_inverted(true)
        .build_translator();

    let character = {
        const INITIAL_CHARACTER_POS: [f64; 2] = [WINDOW_SIZE.0 as f64 / 20.0,
                                                 WINDOW_SIZE.1 as f64 * 0.85];
        Character::new(red(), INITIAL_CHARACTER_POS, 50.0)
    };

    let mut app = App {
        window: Rc::new(RefCell::new(window)),
        graphics: Rc::new(RefCell::new(gl_graphics)),
        translator: translator,
        character: character,
        cursor: VirtualCursor::new(),
        bg_color: black()
    };

    for e in  app.window.clone().events() {
        let app_window = app.window.clone();
        match e {
            Event::Render(r) => { app.render(&r); },
            Event::Update(u) => { app.update(&u, app_window); },
            Event::Input(i) => { app.input(&i); },
            _ => { }
        }
    }
}<|endoftext|>


<commit_before>#![allow(unused_variables)]

extern crate glutin_window;
extern crate graphics;
extern crate rebind;
extern crate piston;
extern crate opengl_graphics;
extern crate viewport;

use glutin_window::GlutinWindow;
use graphics::*;
use opengl_graphics::{GlGraphics, OpenGL};
use piston::event_loop::{EventMap, Events};
use piston::input::{
    Event,
    Input,
    Motion,
    RenderArgs,
    RenderEvent,
    UpdateArgs,
    UpdateEvent
};
use piston::input::keyboard::Key;
use piston::input::Button::Keyboard;
use piston::window::WindowSettings;
use rebind::{Action, InputTranslator, RebindBuilder, Translated};
use std::cell::RefCell;
use std::rc::Rc;

struct App {
    window: Rc<RefCell<GlutinWindow>>,
    graphics: Rc<RefCell<GlGraphics>>,
    translator: InputTranslator<CharacterAction>,
    character: Character,
    virtual_cursor_pos: [f64; 2],
    bg_color: [f32; 4]
}

impl App {
    fn input(&mut self, input: &Input) {
        if let Some(t) = self.translator.translate(input) {
            match t {
                Translated::Press(action) => {
                    const CHARACTER_WALK_SPEED_INCREMENT: f64 = 400.0f64;
                    match action {
                        CharacterAction::Jump => {
                            println!("You jumped! Yay!");
                        },
                        CharacterAction::MoveLeft => {
                            if self.character.current_velocity[0] > (self.character.max_velocity[0] * -1.0) {
                                self.character.current_velocity[0] -= CHARACTER_WALK_SPEED_INCREMENT;
                            }
                        },
                        CharacterAction::MoveRight => {
                            if self.character.current_velocity[0] < self.character.max_velocity[0] {
                                self.character.current_velocity[0] += CHARACTER_WALK_SPEED_INCREMENT;
                            }
                        }
                    }
                },
                Translated::Release(_) => {
                    self.character.current_velocity = [0.0, 0.0];
                },
                Translated::Move(Motion::MouseCursor(x, y)) => {
                    self.virtual_cursor_pos = [x, y];
                },
                _ => { }
            }
        }
    }

    fn update(&mut self, args: &UpdateArgs) {
        let ctl = self.character.topleft;
        let v = self.character.current_velocity;

        self.character.topleft = [ctl[0] + (v[0] * args.dt), ctl[1] + (v[1] * args.dt)];
    }

    fn render(&mut self, args: &RenderArgs) {
        let mut gl_graphics = self.graphics.borrow_mut();

        // draw the background color
        {
            gl_graphics.draw(args.viewport(), |_, gl| clear(self.bg_color, gl));
        }

        // draw the character
        {
            let square = rectangle::square(self.character.topleft[0],
                                           self.character.topleft[1],
                                           self.character.size);

            gl_graphics.draw(args.viewport(), |c, gl| rectangle(self.character.color, square, c.transform, gl));
        }

        // draw the cursor dot
        {
            let dot = ellipse::circle(self.virtual_cursor_pos[0], self.virtual_cursor_pos[1], 5.0);
            gl_graphics.draw(args.viewport(), |c, gl| ellipse([0.0, 1.0, 0.0, 1.0], dot, c.transform, gl));
        }
    }
}

struct Character {
    color: [f32; 4],
    topleft: [f64; 2],
    current_velocity: [f64; 2],
    max_velocity: [f64; 2],
    size: f64
}

impl Character {
    fn new(col: [f32; 4], tl: [f64; 2], sz: f64) -> Self {
        Character {
            color: col,
            topleft: tl,
            current_velocity: [0.0f64, 0.0],
            max_velocity: [800.0, 0.0],
            size: sz
        }
    }
}

#[derive(Copy, Clone, Eq, Hash, Ord, PartialEq, PartialOrd)]
enum CharacterAction {
    Jump,
    MoveLeft,
    MoveRight
}

impl Action for CharacterAction { }

fn main() {
    const WINDOW_SIZE: (u32, u32)  = (800, 600);
    const OPENGL: OpenGL = OpenGL::V3_2;

    let window = WindowSettings::new("calaxite", WINDOW_SIZE)
        .exit_on_esc(true)
        .fullscreen(false)
        .opengl(OPENGL)
        .vsync(true)
        .build()
        .unwrap_or_else(|e| panic!("Could not create window: {}", e));

    let gl_graphics = GlGraphics::new(OPENGL);

    let translator = RebindBuilder::new(WINDOW_SIZE.into())
        .with_action_mapping(Keyboard(Key::Space), CharacterAction::Jump)
        .with_action_mapping(Keyboard(Key::Left),  CharacterAction::MoveLeft)
        .with_action_mapping(Keyboard(Key::A),     CharacterAction::MoveLeft)
        .with_action_mapping(Keyboard(Key::Right), CharacterAction::MoveRight)
        .with_action_mapping(Keyboard(Key::D),     CharacterAction::MoveRight)
        .x_motion_inverted(true)
        .build_translator();

    let character = Character::new([1.0, 0.0, 0.0, 1.0],
                                   [30.0, (WINDOW_SIZE.1 as f64) * 0.85],
                                   50.0);

    let mut app = App {
        window: Rc::new(RefCell::new(window)),
        graphics: Rc::new(RefCell::new(gl_graphics)),
        translator: translator,
        character: character,
        virtual_cursor_pos: [0.0, 0.0],
        bg_color: [0.0, 0.0, 0.0, 1.0] // black background
    };

    for e in app.window.clone().events() {
        match e {
            Event::Render(r) => { app.render(&r); },
            Event::Update(u) => { app.update(&u); },
            Event::Input(i)  => { app.input(&i); },
            _ => { }
        }
    }
}
<commit_msg>Remove accidentally commited code from 0f0422b<commit_after>#![allow(unused_variables)]

extern crate glutin_window;
extern crate graphics;
extern crate rebind;
extern crate piston;
extern crate opengl_graphics;
extern crate viewport;

use glutin_window::GlutinWindow;
use graphics::*;
use opengl_graphics::{GlGraphics, OpenGL};
use piston::event_loop::{EventMap, Events};
use piston::input::{
    Event,
    Input,
    Motion,
    RenderArgs,
    RenderEvent,
    UpdateArgs,
    UpdateEvent
};
use piston::input::keyboard::Key;
use piston::input::Button::Keyboard;
use piston::window::WindowSettings;
use rebind::{Action, InputTranslator, RebindBuilder, Translated};
use std::cell::RefCell;
use std::rc::Rc;

struct App {
    window: Rc<RefCell<GlutinWindow>>,
    graphics: Rc<RefCell<GlGraphics>>,
    translator: InputTranslator<CharacterAction>,
    character: Character,
    virtual_cursor_pos: [f64; 2],
    bg_color: [f32; 4]
}

impl App {
    fn input(&mut self, input: &Input) {
        if let Some(t) = self.translator.translate(input) {
            match t {
                Translated::Press(action) => {
                    const CHARACTER_WALK_SPEED_INCREMENT: f64 = 400.0f64;
                    match action {
                        CharacterAction::Jump => {
                            println!("You jumped! Yay!");
                        },
                        CharacterAction::MoveLeft => {
                            if self.character.current_velocity[0] > (self.character.max_velocity[0] * -1.0) {
                                self.character.current_velocity[0] -= CHARACTER_WALK_SPEED_INCREMENT;
                            }
                        },
                        CharacterAction::MoveRight => {
                            if self.character.current_velocity[0] < self.character.max_velocity[0] {
                                self.character.current_velocity[0] += CHARACTER_WALK_SPEED_INCREMENT;
                            }
                        }
                    }
                },
                Translated::Release(_) => {
                    self.character.current_velocity = [0.0, 0.0];
                },
                Translated::Move(Motion::MouseCursor(x, y)) => {
                    self.virtual_cursor_pos = [x, y];
                },
                _ => { }
            }
        }
    }

    fn update(&mut self, args: &UpdateArgs) {
        let ctl = self.character.topleft;
        let v = self.character.current_velocity;

        self.character.topleft = [ctl[0] + (v[0] * args.dt), ctl[1] + (v[1] * args.dt)];
    }

    fn render(&mut self, args: &RenderArgs) {
        let mut gl_graphics = self.graphics.borrow_mut();

        // draw the background color
        {
            gl_graphics.draw(args.viewport(), |_, gl| clear(self.bg_color, gl));
        }

        // draw the character
        {
            let square = rectangle::square(self.character.topleft[0],
                                           self.character.topleft[1],
                                           self.character.size);

            gl_graphics.draw(args.viewport(), |c, gl| rectangle(self.character.color, square, c.transform, gl));
        }

        // draw the cursor dot
        {
            let dot = ellipse::circle(self.virtual_cursor_pos[0], self.virtual_cursor_pos[1], 5.0);
            gl_graphics.draw(args.viewport(), |c, gl| ellipse([0.0, 1.0, 0.0, 1.0], dot, c.transform, gl));
        }
    }
}

struct Character {
    color: [f32; 4],
    topleft: [f64; 2],
    current_velocity: [f64; 2],
    max_velocity: [f64; 2],
    size: f64
}

impl Character {
    fn new(col: [f32; 4], tl: [f64; 2], sz: f64) -> Self {
        Character {
            color: col,
            topleft: tl,
            current_velocity: [0.0f64, 0.0],
            max_velocity: [800.0, 0.0],
            size: sz
        }
    }
}

#[derive(Copy, Clone, Eq, Hash, Ord, PartialEq, PartialOrd)]
enum CharacterAction {
    Jump,
    MoveLeft,
    MoveRight
}

impl Action for CharacterAction { }

fn main() {
    const WINDOW_SIZE: (u32, u32)  = (800, 600);
    const OPENGL: OpenGL = OpenGL::V3_2;

    let window = WindowSettings::new("calaxite", WINDOW_SIZE)
        .exit_on_esc(true)
        .fullscreen(false)
        .opengl(OPENGL)
        .vsync(true)
        .build()
        .unwrap_or_else(|e| panic!("Could not create window: {}", e));

    let gl_graphics = GlGraphics::new(OPENGL);

    let translator = RebindBuilder::new(WINDOW_SIZE.into())
        .with_action_mapping(Keyboard(Key::Space), CharacterAction::Jump)
        .with_action_mapping(Keyboard(Key::Left),  CharacterAction::MoveLeft)
        .with_action_mapping(Keyboard(Key::A),     CharacterAction::MoveLeft)
        .with_action_mapping(Keyboard(Key::Right), CharacterAction::MoveRight)
        .with_action_mapping(Keyboard(Key::D),     CharacterAction::MoveRight)
        .build_translator();

    let character = Character::new([1.0, 0.0, 0.0, 1.0],
                                   [30.0, (WINDOW_SIZE.1 as f64) * 0.85],
                                   50.0);

    let mut app = App {
        window: Rc::new(RefCell::new(window)),
        graphics: Rc::new(RefCell::new(gl_graphics)),
        translator: translator,
        character: character,
        virtual_cursor_pos: [0.0, 0.0],
        bg_color: [0.0, 0.0, 0.0, 1.0] // black background
    };

    for e in app.window.clone().events() {
        match e {
            Event::Render(r) => { app.render(&r); },
            Event::Update(u) => { app.update(&u); },
            Event::Input(i)  => { app.input(&i); },
            _ => { }
        }
    }
}
<|endoftext|>