<commit_before>use std::iter::repeat;
use std::sync::atomic::AtomicUsize;
use std::time::{Duration, Instant};

#[cfg(feature = "no_metrics")]
use std::marker::PhantomData;

#[cfg(not(feature = "no_metrics"))]
use std::sync::atomic::Ordering::{Acquire, Relaxed};

use historian::Histo;

lazy_static! {
    /// A metric collector for all pagecache users running in this
    /// process.
    pub static ref M: Metrics = Metrics::default();
}

pub(crate) fn clock() -> f64 {
    if cfg!(feature = "no_metrics") {
        0.
    } else {
        let u = uptime();
        (u.as_secs() * 1_000_000_000) as f64
            + f64::from(u.subsec_nanos())
    }
}

// not correct, since it starts counting at the first observance...
pub(crate) fn uptime() -> Duration {
    lazy_static! {
        static ref START: Instant = Instant::now();
    }

    if cfg!(feature = "no_metrics") {
        Duration::new(0, 0)
    } else {
        START.elapsed()
    }
}

/// Measure the duration of an event, and call `Histo::measure()`.
pub struct Measure<'h> {
    start: f64,
    #[cfg(not(feature = "no_metrics"))]
    histo: &'h Histo,
    #[cfg(feature = "no_metrics")]
    _pd: PhantomData<&'h ()>,
}

impl<'h> Measure<'h> {
    /// The time delta from ctor to dtor is recorded in `histo`.
    #[inline(always)]
    pub fn new(histo: &'h Histo) -> Measure<'h> {
        Measure {
            #[cfg(feature = "no_metrics")]
            _pd: PhantomData,
            #[cfg(not(feature = "no_metrics"))]
            histo,
            start: clock(),
        }
    }
}

impl<'h> Drop for Measure<'h> {
    #[inline(always)]
    fn drop(&mut self) {
        #[cfg(not(feature = "no_metrics"))]
        self.histo.measure(clock() - self.start);
    }
}

/// Measure the time spent on calling a given function in a given `Histo`.
#[cfg_attr(not(feature = "no_inline"), inline)]
pub(crate) fn measure<F: FnOnce() -> R, R>(histo: &Histo, f: F) -> R {
    #[cfg(not(feature = "no_metrics"))]
    let _measure = Measure::new(histo);
    f()
}

#[derive(Default, Debug)]
pub struct Metrics {
    pub advance_snapshot: Histo,
    pub tree_set: Histo,
    pub tree_get: Histo,
    pub tree_del: Histo,
    pub tree_cas: Histo,
    pub tree_scan: Histo,
    pub tree_merge: Histo,
    pub tree_start: Histo,
    pub tree_traverse: Histo,
    pub page_in: Histo,
    pub rewrite_page: Histo,
    pub merge_page: Histo,
    pub page_out: Histo,
    pub pull: Histo,
    pub serialize: Histo,
    pub deserialize: Histo,
    pub compress: Histo,
    pub decompress: Histo,
    pub make_stable: Histo,
    pub reserve: Histo,
    pub write_to_log: Histo,
    pub written_bytes: Histo,
    pub read: Histo,
    pub tree_loops: AtomicUsize,
    pub log_reservations: AtomicUsize,
    pub log_reservation_attempts: AtomicUsize,
    pub accountant_lock: Histo,
    pub accountant_hold: Histo,
}

#[cfg(not(feature = "no_metrics"))]
impl Metrics {
    pub fn tree_looped(&self) {
        self.tree_loops.fetch_add(1, Relaxed);
    }

    pub fn log_reservation_attempted(&self) {
        self.log_reservation_attempts.fetch_add(1, Relaxed);
    }

    pub fn log_reservation_success(&self) {
        self.log_reservations.fetch_add(1, Relaxed);
    }

    pub fn print_profile(&self) {
        println!(
            "pagecache profile:\n\
            {0: >17} | {1: >10} | {2: >10} | {3: >10} | {4: >10} | {5: >10} | {6: >10} | {7: >10}",
            "op",
            "min (us)",
            "90 (us)",
            "99 (us)",
            "99.9 (us)",
            "max (us)",
            "count",
            "sum (s)"
        );
        println!("{}", repeat("-").take(103).collect::<String>());

        let p = |mut tuples: Vec<(String, _, _, _, _, _, _, _)>| {
            tuples.sort_by_key(|t| (t.7 * -1. * 1e3) as i64);
            for v in tuples {
                println!(
                    "{0: >17} | {1: >10.1} | {2: >10.1} | {3: >10.1} \
                | {4: >10.1} | {5: >10.1} | {6: >10.1} | {7: >10.3}",
                    v.0,
                    v.1,
                    v.2,
                    v.3,
                    v.4,
                    v.5,
                    v.6,
                    v.7
                );
            }
        };

        let f = |name: &str, histo: &Histo| {
            (
                name.to_string(),
                histo.percentile(0.) / 1e3,
                histo.percentile(90.) / 1e3,
                histo.percentile(99.) / 1e3,
                histo.percentile(99.9) / 1e3,
                histo.percentile(100.) / 1e3,
                histo.count(),
                histo.sum() as f64 / 1e9,
            )
        };

        println!("tree:");
        p(vec![
            f("start", &self.tree_start),
            f("traverse", &self.tree_traverse),
            f("get", &self.tree_get),
            f("set", &self.tree_set),
            f("merge", &self.tree_merge),
            f("del", &self.tree_del),
            f("cas", &self.tree_cas),
            f("scan", &self.tree_scan),
        ]);
        println!(
            "tree contention loops: {}",
            self.tree_loops.load(Acquire)
        );

        println!("{}", repeat("-").take(103).collect::<String>());
        println!("pagecache:");
        p(vec![
            f("snapshot", &self.advance_snapshot),
            f("page_in", &self.page_in),
            f("merge", &self.merge_page),
            f("pull", &self.pull),
            f("page_out", &self.page_out),
        ]);

        println!("{}", repeat("-").take(103).collect::<String>());
        println!("serialization and compression:");
        p(vec![
            f("serialize", &self.serialize),
            f("deserialize", &self.deserialize),
            f("compress", &self.compress),
            f("decompress", &self.decompress),
        ]);

        println!("{}", repeat("-").take(103).collect::<String>());
        println!("log:");
        p(vec![
            f("make_stable", &self.make_stable),
            f("read", &self.read),
            f("write", &self.write_to_log),
            f("written bytes", &self.written_bytes),
            f("reserve", &self.reserve),
        ]);
        println!(
            "log reservations: {}",
            self.log_reservations.load(Acquire)
        );
        println!(
            "log res attempts: {}",
            self.log_reservation_attempts.load(Acquire)
        );

        println!("{}", repeat("-").take(103).collect::<String>());
        println!("segment accountant:");
        p(vec![
            f("acquire", &self.accountant_lock),
            f("hold", &self.accountant_hold),
        ]);
    }
}

#[cfg(feature = "no_metrics")]
impl Metrics {
    pub fn tree_looped(&self) {}

    pub fn log_looped(&self) {}

    pub fn print_profile(&self) {}
}
<commit_msg>Add fall-through methods for metrics that are not used with no_metrics<commit_after>use std::iter::repeat;
use std::sync::atomic::AtomicUsize;
use std::time::{Duration, Instant};

#[cfg(feature = "no_metrics")]
use std::marker::PhantomData;

#[cfg(not(feature = "no_metrics"))]
use std::sync::atomic::Ordering::{Acquire, Relaxed};

use historian::Histo;

lazy_static! {
    /// A metric collector for all pagecache users running in this
    /// process.
    pub static ref M: Metrics = Metrics::default();
}

pub(crate) fn clock() -> f64 {
    if cfg!(feature = "no_metrics") {
        0.
    } else {
        let u = uptime();
        (u.as_secs() * 1_000_000_000) as f64
            + f64::from(u.subsec_nanos())
    }
}

// not correct, since it starts counting at the first observance...
pub(crate) fn uptime() -> Duration {
    lazy_static! {
        static ref START: Instant = Instant::now();
    }

    if cfg!(feature = "no_metrics") {
        Duration::new(0, 0)
    } else {
        START.elapsed()
    }
}

/// Measure the duration of an event, and call `Histo::measure()`.
pub struct Measure<'h> {
    start: f64,
    #[cfg(not(feature = "no_metrics"))]
    histo: &'h Histo,
    #[cfg(feature = "no_metrics")]
    _pd: PhantomData<&'h ()>,
}

impl<'h> Measure<'h> {
    /// The time delta from ctor to dtor is recorded in `histo`.
    #[inline(always)]
    pub fn new(histo: &'h Histo) -> Measure<'h> {
        Measure {
            #[cfg(feature = "no_metrics")]
            _pd: PhantomData,
            #[cfg(not(feature = "no_metrics"))]
            histo,
            start: clock(),
        }
    }
}

impl<'h> Drop for Measure<'h> {
    #[inline(always)]
    fn drop(&mut self) {
        #[cfg(not(feature = "no_metrics"))]
        self.histo.measure(clock() - self.start);
    }
}

/// Measure the time spent on calling a given function in a given `Histo`.
#[cfg_attr(not(feature = "no_inline"), inline)]
pub(crate) fn measure<F: FnOnce() -> R, R>(histo: &Histo, f: F) -> R {
    #[cfg(not(feature = "no_metrics"))]
    let _measure = Measure::new(histo);
    f()
}

#[derive(Default, Debug)]
pub struct Metrics {
    pub advance_snapshot: Histo,
    pub tree_set: Histo,
    pub tree_get: Histo,
    pub tree_del: Histo,
    pub tree_cas: Histo,
    pub tree_scan: Histo,
    pub tree_merge: Histo,
    pub tree_start: Histo,
    pub tree_traverse: Histo,
    pub page_in: Histo,
    pub rewrite_page: Histo,
    pub merge_page: Histo,
    pub page_out: Histo,
    pub pull: Histo,
    pub serialize: Histo,
    pub deserialize: Histo,
    pub compress: Histo,
    pub decompress: Histo,
    pub make_stable: Histo,
    pub reserve: Histo,
    pub write_to_log: Histo,
    pub written_bytes: Histo,
    pub read: Histo,
    pub tree_loops: AtomicUsize,
    pub log_reservations: AtomicUsize,
    pub log_reservation_attempts: AtomicUsize,
    pub accountant_lock: Histo,
    pub accountant_hold: Histo,
}

#[cfg(not(feature = "no_metrics"))]
impl Metrics {
    pub fn tree_looped(&self) {
        self.tree_loops.fetch_add(1, Relaxed);
    }

    pub fn log_reservation_attempted(&self) {
        self.log_reservation_attempts.fetch_add(1, Relaxed);
    }

    pub fn log_reservation_success(&self) {
        self.log_reservations.fetch_add(1, Relaxed);
    }

    pub fn print_profile(&self) {
        println!(
            "pagecache profile:\n\
            {0: >17} | {1: >10} | {2: >10} | {3: >10} | {4: >10} | {5: >10} | {6: >10} | {7: >10}",
            "op",
            "min (us)",
            "90 (us)",
            "99 (us)",
            "99.9 (us)",
            "max (us)",
            "count",
            "sum (s)"
        );
        println!("{}", repeat("-").take(103).collect::<String>());

        let p = |mut tuples: Vec<(String, _, _, _, _, _, _, _)>| {
            tuples.sort_by_key(|t| (t.7 * -1. * 1e3) as i64);
            for v in tuples {
                println!(
                    "{0: >17} | {1: >10.1} | {2: >10.1} | {3: >10.1} \
                | {4: >10.1} | {5: >10.1} | {6: >10.1} | {7: >10.3}",
                    v.0,
                    v.1,
                    v.2,
                    v.3,
                    v.4,
                    v.5,
                    v.6,
                    v.7
                );
            }
        };

        let f = |name: &str, histo: &Histo| {
            (
                name.to_string(),
                histo.percentile(0.) / 1e3,
                histo.percentile(90.) / 1e3,
                histo.percentile(99.) / 1e3,
                histo.percentile(99.9) / 1e3,
                histo.percentile(100.) / 1e3,
                histo.count(),
                histo.sum() as f64 / 1e9,
            )
        };

        println!("tree:");
        p(vec![
            f("start", &self.tree_start),
            f("traverse", &self.tree_traverse),
            f("get", &self.tree_get),
            f("set", &self.tree_set),
            f("merge", &self.tree_merge),
            f("del", &self.tree_del),
            f("cas", &self.tree_cas),
            f("scan", &self.tree_scan),
        ]);
        println!(
            "tree contention loops: {}",
            self.tree_loops.load(Acquire)
        );

        println!("{}", repeat("-").take(103).collect::<String>());
        println!("pagecache:");
        p(vec![
            f("snapshot", &self.advance_snapshot),
            f("page_in", &self.page_in),
            f("merge", &self.merge_page),
            f("pull", &self.pull),
            f("page_out", &self.page_out),
        ]);

        println!("{}", repeat("-").take(103).collect::<String>());
        println!("serialization and compression:");
        p(vec![
            f("serialize", &self.serialize),
            f("deserialize", &self.deserialize),
            f("compress", &self.compress),
            f("decompress", &self.decompress),
        ]);

        println!("{}", repeat("-").take(103).collect::<String>());
        println!("log:");
        p(vec![
            f("make_stable", &self.make_stable),
            f("read", &self.read),
            f("write", &self.write_to_log),
            f("written bytes", &self.written_bytes),
            f("reserve", &self.reserve),
        ]);
        println!(
            "log reservations: {}",
            self.log_reservations.load(Acquire)
        );
        println!(
            "log res attempts: {}",
            self.log_reservation_attempts.load(Acquire)
        );

        println!("{}", repeat("-").take(103).collect::<String>());
        println!("segment accountant:");
        p(vec![
            f("acquire", &self.accountant_lock),
            f("hold", &self.accountant_hold),
        ]);
    }
}

#[cfg(feature = "no_metrics")]
impl Metrics {
    pub fn log_reservation_attempted(&self) {}

    pub fn log_reservation_success(&self) {}

    pub fn tree_looped(&self) {}

    pub fn log_looped(&self) {}

    pub fn print_profile(&self) {}
}
<|endoftext|>


<commit_before>extern crate num;
extern crate rand;

#[macro_use]
extern crate serde_derive;
extern crate serde_yaml;

extern crate tcod;
use tcod::RootConsole;
use tcod::{Console};
use tcod::console::{FontLayout, FontType, Offscreen};
use tcod::input::{Key, KeyCode};

mod traits;
use traits::{Renderable, Movable, Position};

mod point;
use point::Point;

mod rectangle;
mod item;
mod units;
mod map;

const SCREEN_WIDTH: u8 = 80;
const SCREEN_HEIGHT: u8 = 50;
const PANEL_HEIGHT: u8 = 5;

const FOV_RADIUS: u8 = 10;

#[derive(Debug, Eq, PartialEq, Copy, Clone)]
enum GameState {
    Playing,
    NewMap,
    Menu,
    Exit,
}

#[derive(Debug, Eq, PartialEq, Copy, Clone)]
enum PlayerAction {
    Moved,
    Turn,
    NoTurn,
}

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

impl Direction {
    fn to_rel_point(self) -> Point<i16> {
        match self {
            Direction::Up       => Point::new(0, -1),
            Direction::Down     => Point::new(0, 1),
            Direction::Left     => Point::new(-1, 0),
            Direction::Right    => Point::new(1, 0),
        }
    }
}

#[derive(Debug)]
enum KeyType {
    Movement(Direction),
    Exit,
    NewGame,
    Other,
}

fn key_type(key: &Key) -> KeyType {
    match key.code {
        KeyCode::Right  =>  KeyType::Movement(Direction::Right),
        KeyCode::Left   =>  KeyType::Movement(Direction::Left),
        KeyCode::Up     =>  KeyType::Movement(Direction::Up),
        KeyCode::Down   =>  KeyType::Movement(Direction::Down),
        KeyCode::Escape =>  KeyType::Exit,
        KeyCode::F1     =>  KeyType::NewGame,
        _ => KeyType::Other,
    }
}

fn render_all<'a>(root: &mut RootConsole, buffer_console: &mut Offscreen, map: &map::Map, npcs: &Vec<units::Unit<'a>>, player: &units::Unit) {
    buffer_console.clear();
    root.clear();

    // With the scrolling map, we need to try to centre the player on the screen
    // without going past the bounds of the buffer.
    let (map_width, map_height) = map.get_map_size();
    let draw_left = player.get_x() - SCREEN_WIDTH as i16 / 2;
    let draw_top = player.get_y() - SCREEN_HEIGHT as i16 / 2;

    let mut view_port = rectangle::Rectangle::new(Point{x: draw_left, y: draw_top}, (SCREEN_WIDTH, SCREEN_HEIGHT - PANEL_HEIGHT));
    view_port.clamp_to((0,0), (map_width as i16, map_height as i16));

    map.render_map(buffer_console);

    for unit in npcs.iter() {
        if map.point_in_fov(unit.get_position()) {
            unit.render(buffer_console);
        }
    }

    player.render(buffer_console);

    tcod::console::blit(buffer_console, (view_port.top_left.x as i32, view_port.top_left.y as i32), (SCREEN_WIDTH as i32, (SCREEN_HEIGHT - PANEL_HEIGHT) as i32), root, (0,0), 1.0, 1.0);
    root.flush();
}

fn handle_input<'a>(root: &mut RootConsole, cur_game_state: GameState, map: &map::Map, npcs: &mut Vec<units::Unit<'a>>, player: &mut units::Unit) -> (PlayerAction, GameState) {
    let key = root.wait_for_keypress(true);

    let mut player_action: PlayerAction = PlayerAction::NoTurn;
    let mut new_game_state: GameState = GameState::Playing;

    match key_type(&key) {
        KeyType::Movement(dir) if cur_game_state == GameState::Playing => {
            let pos = player.get_position();
            let new_pos = pos + dir.to_rel_point();

            player_action = match map.can_move_to(new_pos) {
                map::CanMoveResponse::Open => {
                    if let Some(enemy) = npcs.iter_mut().filter(|n| n.get_position() == new_pos).next() {
                        player.attack(enemy);
                        PlayerAction::Turn
                    } else {
                        player.move_to(new_pos);
                        PlayerAction::Moved
                    }
                },
                map::CanMoveResponse::Scenery => {
                    PlayerAction::NoTurn
                } // Nothing to do.
            };
        },
        KeyType::Movement(_) if cur_game_state == GameState::Menu => {} // Will likely be used for menus
        KeyType::Movement(_) => unreachable!(),

        KeyType::Exit           => {
            new_game_state = GameState::Exit;
        },
        KeyType::NewGame        => {
            new_game_state = GameState::NewMap;
        }
        KeyType::Other          => println!("{:?}", key),
    }

    (player_action, new_game_state)
}

fn main() {
    let mut root = RootConsole::initializer()
                    .size(SCREEN_WIDTH as i32, SCREEN_HEIGHT as i32)
                    .title("Roguelike Tutorial")
                    .fullscreen(false)
                    .font("arial10x10.png", FontLayout::Tcod)
                    .font_type(FontType::Greyscale)
                    .init();

    let mut buffer_console = Offscreen::new(map::MAP_MAX_WIDTH as i32, map::MAP_MAX_HEIGHT as i32);
    root.set_default_foreground(tcod::colors::WHITE);

    let unit_types = units::load_unit_types();
    let (mut map, mut npcs, start_coord) = map::Map::init(&unit_types);

    let player_type = units::UnitType::new("Player", '@', tcod::colors::WHITE);
    let mut player = units::Unit::new(start_coord, &player_type);

    map.update_fov(player.get_position(), FOV_RADIUS);

    let mut game_state = GameState::Playing;

    while !root.window_closed() {
        render_all(&mut root, &mut buffer_console, &map, &npcs, &player);

        let (player_action, new_game_state) = handle_input(&mut root, game_state, &map, &mut npcs, &mut player);
        game_state = new_game_state;

        if player_action == PlayerAction::Moved {
            map.update_fov(player.get_position(), FOV_RADIUS);
        }

        match (game_state, player_action) {
            (GameState::Exit, _) => break,
            (GameState::NewMap, _) => {
                let (new_map, units, start_coord) = map::Map::init(&unit_types);
                map = new_map;
                npcs = units;
                player.move_to(start_coord);
                map.update_fov(start_coord, FOV_RADIUS);
                game_state = GameState::Playing;
            }
            (GameState::Playing, PlayerAction::Moved) | (GameState::Playing, PlayerAction::Turn) => {
                for enemy in npcs.iter_mut() {
                    enemy.take_turn(&map, &mut player);
                }
            }
            _ => {} // Don't update AI.
        }
    }
}
<commit_msg>Added player death.<commit_after>extern crate num;
extern crate rand;

#[macro_use]
extern crate serde_derive;
extern crate serde_yaml;

extern crate tcod;
use tcod::RootConsole;
use tcod::{Console};
use tcod::console::{FontLayout, FontType, Offscreen};
use tcod::input::{Key, KeyCode};

mod traits;
use traits::{Renderable, Movable, Position};

mod point;
use point::Point;

mod rectangle;
mod item;
mod units;
mod map;

const SCREEN_WIDTH: u8 = 80;
const SCREEN_HEIGHT: u8 = 50;
const PANEL_HEIGHT: u8 = 5;

const FOV_RADIUS: u8 = 10;

#[derive(Debug, Eq, PartialEq, Copy, Clone)]
enum GameState {
    Playing,
    Dead,
    NewMap,
    Menu,
    Exit,
}

#[derive(Debug, Eq, PartialEq, Copy, Clone)]
enum PlayerAction {
    Moved,
    Turn,
    NoTurn,
}

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

impl Direction {
    fn to_rel_point(self) -> Point<i16> {
        match self {
            Direction::Up       => Point::new(0, -1),
            Direction::Down     => Point::new(0, 1),
            Direction::Left     => Point::new(-1, 0),
            Direction::Right    => Point::new(1, 0),
        }
    }
}

#[derive(Debug)]
enum KeyType {
    Movement(Direction),
    Exit,
    NewGame,
    Other,
}

fn key_type(key: &Key) -> KeyType {
    match key.code {
        KeyCode::Right  =>  KeyType::Movement(Direction::Right),
        KeyCode::Left   =>  KeyType::Movement(Direction::Left),
        KeyCode::Up     =>  KeyType::Movement(Direction::Up),
        KeyCode::Down   =>  KeyType::Movement(Direction::Down),
        KeyCode::Escape =>  KeyType::Exit,
        KeyCode::F1     =>  KeyType::NewGame,
        _ => KeyType::Other,
    }
}

fn render_all<'a>(root: &mut RootConsole, buffer_console: &mut Offscreen, map: &map::Map, npcs: &Vec<units::Unit<'a>>, player: &units::Unit) {
    buffer_console.clear();
    root.clear();

    // With the scrolling map, we need to try to centre the player on the screen
    // without going past the bounds of the buffer.
    let (map_width, map_height) = map.get_map_size();
    let draw_left = player.get_x() - SCREEN_WIDTH as i16 / 2;
    let draw_top = player.get_y() - SCREEN_HEIGHT as i16 / 2;

    let mut view_port = rectangle::Rectangle::new(Point{x: draw_left, y: draw_top}, (SCREEN_WIDTH, SCREEN_HEIGHT - PANEL_HEIGHT));
    view_port.clamp_to((0,0), (map_width as i16, map_height as i16));

    map.render_map(buffer_console);

    for unit in npcs.iter() {
        if map.point_in_fov(unit.get_position()) {
            unit.render(buffer_console);
        }
    }

    // If the player has died, a corpse will have been created.
    if player.get_hp() > 0 {
        player.render(buffer_console);
    }

    tcod::console::blit(buffer_console, (view_port.top_left.x as i32, view_port.top_left.y as i32), (SCREEN_WIDTH as i32, (SCREEN_HEIGHT - PANEL_HEIGHT) as i32), root, (0,0), 1.0, 1.0);
    root.flush();
}

fn handle_input<'a>(root: &mut RootConsole, cur_game_state: GameState, map: &map::Map, npcs: &mut Vec<units::Unit<'a>>, player: &mut units::Unit) -> (PlayerAction, GameState) {
    let key = root.wait_for_keypress(true);

    let mut player_action: PlayerAction = PlayerAction::NoTurn;
    let mut new_game_state: GameState = cur_game_state;

    match key_type(&key) {
        KeyType::Movement(dir) if cur_game_state == GameState::Playing => {
            let pos = player.get_position();
            let new_pos = pos + dir.to_rel_point();

            player_action = match map.can_move_to(new_pos) {
                map::CanMoveResponse::Open => {
                    if let Some(enemy) = npcs.iter_mut().filter(|n| n.get_position() == new_pos).next() {
                        player.attack(enemy);
                        PlayerAction::Turn
                    } else {
                        player.move_to(new_pos);
                        PlayerAction::Moved
                    }
                },
                map::CanMoveResponse::Scenery => {
                    PlayerAction::NoTurn
                } // Nothing to do.
            };
        },
        KeyType::Movement(_) if cur_game_state == GameState::Menu => {} // Will likely be used for menus
        KeyType::Movement(_) => {},

        KeyType::Exit           => {
            new_game_state = GameState::Exit;
        },
        KeyType::NewGame        => {
            new_game_state = GameState::NewMap;
        }
        KeyType::Other          => println!("{:?}", key),
    }

    (player_action, new_game_state)
}

fn main() {
    let mut root = RootConsole::initializer()
                    .size(SCREEN_WIDTH as i32, SCREEN_HEIGHT as i32)
                    .title("Roguelike Tutorial")
                    .fullscreen(false)
                    .font("arial10x10.png", FontLayout::Tcod)
                    .font_type(FontType::Greyscale)
                    .init();

    let mut buffer_console = Offscreen::new(map::MAP_MAX_WIDTH as i32, map::MAP_MAX_HEIGHT as i32);
    root.set_default_foreground(tcod::colors::WHITE);

    let unit_types = units::load_unit_types();
    let (mut map, mut npcs, start_coord) = map::Map::init(&unit_types);

    let player_type = units::UnitType::new("Player", '@', tcod::colors::WHITE);
    let mut player = units::Unit::new(start_coord, &player_type);

    map.update_fov(player.get_position(), FOV_RADIUS);

    let mut game_state = GameState::Playing;

    while !root.window_closed() {
        render_all(&mut root, &mut buffer_console, &map, &npcs, &player);

        let (player_action, new_game_state) = handle_input(&mut root, game_state, &map, &mut npcs, &mut player);
        game_state = new_game_state;

        if player_action == PlayerAction::Moved {
            map.update_fov(player.get_position(), FOV_RADIUS);
        }

        match (game_state, player_action) {
            (GameState::Exit, _) => break,
            (GameState::NewMap, _) => {
                let (new_map, units, start_coord) = map::Map::init(&unit_types);
                map = new_map;
                npcs = units;
                player.move_to(start_coord);
                player.heal(255); // Just max health, whatever that is.
                map.update_fov(start_coord, FOV_RADIUS);
                game_state = GameState::Playing;
            }
            (GameState::Playing, PlayerAction::Moved) | (GameState::Playing, PlayerAction::Turn) => {
                for enemy in npcs.iter_mut() {
                    if enemy.get_hp() > 0 {
                        enemy.take_turn(&map, &mut player);

                        if player.get_hp() == 0 {
                            println!("You died!");
                            let corpse = item::Item::new(&player.get_name(), player.get_glyph(), tcod::colors::DARK_RED, player.get_position());
                            map.place_item(corpse);
                            game_state = GameState::Dead;
                            break;
                        }
                    }
                }

                let dead_npc_indices: Vec<usize> = npcs.iter().enumerate().filter(|&(_, x)| x.get_hp() == 0).map(|(i, _)| i).collect();
                for i in dead_npc_indices {
                    let npc = npcs.remove(i);
                    let corpse = item::Item::new(&npc.get_name(), npc.get_glyph(), tcod::colors::DARK_RED, npc.get_position());

                    map.place_item(corpse);
                    println!("{} is dead!", npc.get_name());
                }
            }
            _ => {} // Don't update AI.
        }
    }
}
<|endoftext|>


<commit_before>#![recursion_limit = "128"]
#![feature(proc_macro_diagnostic)]

extern crate proc_macro;
use self::proc_macro::TokenStream;

use quote::{quote, quote_spanned};
use syn::parse::{Parse, ParseStream, Result};
use syn::spanned::Spanned;
use syn::{parse_macro_input, Expr, Ident, Token, Type, Visibility};

/// Parses the following syntax, which aligns with the input of the real
/// `lazy_static` crate.
///
///     lazy_static! {
///         $VISIBILITY static ref $NAME: $TYPE = $EXPR;
///     }
///
/// For example:
///
///     lazy_static! {
///         static ref USERNAME: Regex = Regex::new("^[a-z0-9_-]{3,16}$").unwrap();
///     }
struct LazyStatic {
    visibility: Visibility,
    name: Ident,
    ty: Type,
    init: Expr,
}

impl Parse for LazyStatic {
    fn parse(input: ParseStream) -> Result<Self> {
        let visibility: Visibility = input.parse()?;
        input.parse::<Token![static]>()?;
        input.parse::<Token![ref]>()?;
        let name: Ident = input.parse()?;
        input.parse::<Token![:]>()?;
        let ty: Type = input.parse()?;
        input.parse::<Token![=]>()?;
        let init: Expr = input.parse()?;
        input.parse::<Token![;]>()?;
        Ok(LazyStatic {
            visibility,
            name,
            ty,
            init,
        })
    }
}

#[proc_macro]
pub fn lazy_static(input: TokenStream) -> TokenStream {
    let LazyStatic {
        visibility,
        name,
        ty,
        init,
    } = parse_macro_input!(input as LazyStatic);

    // The warning looks like this.
    //
    //     warning: come on, pick a more creative name
    //       --> src/main.rs:10:16
    //        |
    //     10 |     static ref FOO: String = "lazy_static".to_owned();
    //        |                ^^^
    if name == "FOO" {
        name.span()
            .unwrap()
            .warning("come on, pick a more creative name")
            .emit();
    }

    // The error looks like this.
    //
    //     error: I can't think of a legitimate use for lazily initializing the value `()`
    //       --> src/main.rs:10:27
    //        |
    //     10 |     static ref UNIT: () = ();
    //        |                           ^^
    if let Expr::Tuple(ref init) = init {
        if init.elems.is_empty() {
            init.span()
                .unwrap()
                .error("I can't think of a legitimate use for lazily initializing the value `()`")
                .emit();
            return TokenStream::new();
        }
    }

    // Assert that the static type implements Sync. If not, user sees an error
    // message like the following. We span this assertion with the field type's
    // line/column so that the error message appears in the correct place.
    //
    //     error[E0277]: the trait bound `*const (): std::marker::Sync` is not satisfied
    //       --> src/main.rs:10:21
    //        |
    //     10 |     static ref PTR: *const () = &();
    //        |                     ^^^^^^^^^ `*const ()` cannot be shared between threads safely
    let assert_sync = quote_spanned! {ty.span()=>
        struct _AssertSync where #ty: std::marker::Sync;
    };

    // Check for Sized. Not vital to check here, but the error message is less
    // confusing this way than if they get a Sized error in one of our
    // implementation details where it assumes Sized.
    //
    //     error[E0277]: the trait bound `str: std::marker::Sized` is not satisfied
    //       --> src/main.rs:10:19
    //        |
    //     10 |     static ref A: str = "";
    //        |                   ^^^ `str` does not have a constant size known at compile-time
    let assert_sized = quote_spanned! {ty.span()=>
        struct _AssertSized where #ty: std::marker::Sized;
    };

    let init_ptr = quote_spanned! {init.span()=>
        Box::into_raw(Box::new(#init))
    };

    let expanded = quote! {
        #visibility struct #name;

        impl std::ops::Deref for #name {
            type Target = #ty;

            fn deref(&self) -> &#ty {
                #assert_sync
                #assert_sized

                static ONCE: std::sync::Once = std::sync::ONCE_INIT;
                static mut VALUE: *mut #ty = 0 as *mut #ty;

                unsafe {
                    ONCE.call_once(|| VALUE = #init_ptr);
                    &*VALUE
                }
            }
        }
    };

    TokenStream::from(expanded)
}
<commit_msg>Update deprecated ONCE_INIT to Once::new()<commit_after>#![recursion_limit = "128"]
#![feature(proc_macro_diagnostic)]

extern crate proc_macro;
use self::proc_macro::TokenStream;

use quote::{quote, quote_spanned};
use syn::parse::{Parse, ParseStream, Result};
use syn::spanned::Spanned;
use syn::{parse_macro_input, Expr, Ident, Token, Type, Visibility};

/// Parses the following syntax, which aligns with the input of the real
/// `lazy_static` crate.
///
///     lazy_static! {
///         $VISIBILITY static ref $NAME: $TYPE = $EXPR;
///     }
///
/// For example:
///
///     lazy_static! {
///         static ref USERNAME: Regex = Regex::new("^[a-z0-9_-]{3,16}$").unwrap();
///     }
struct LazyStatic {
    visibility: Visibility,
    name: Ident,
    ty: Type,
    init: Expr,
}

impl Parse for LazyStatic {
    fn parse(input: ParseStream) -> Result<Self> {
        let visibility: Visibility = input.parse()?;
        input.parse::<Token![static]>()?;
        input.parse::<Token![ref]>()?;
        let name: Ident = input.parse()?;
        input.parse::<Token![:]>()?;
        let ty: Type = input.parse()?;
        input.parse::<Token![=]>()?;
        let init: Expr = input.parse()?;
        input.parse::<Token![;]>()?;
        Ok(LazyStatic {
            visibility,
            name,
            ty,
            init,
        })
    }
}

#[proc_macro]
pub fn lazy_static(input: TokenStream) -> TokenStream {
    let LazyStatic {
        visibility,
        name,
        ty,
        init,
    } = parse_macro_input!(input as LazyStatic);

    // The warning looks like this.
    //
    //     warning: come on, pick a more creative name
    //       --> src/main.rs:10:16
    //        |
    //     10 |     static ref FOO: String = "lazy_static".to_owned();
    //        |                ^^^
    if name == "FOO" {
        name.span()
            .unwrap()
            .warning("come on, pick a more creative name")
            .emit();
    }

    // The error looks like this.
    //
    //     error: I can't think of a legitimate use for lazily initializing the value `()`
    //       --> src/main.rs:10:27
    //        |
    //     10 |     static ref UNIT: () = ();
    //        |                           ^^
    if let Expr::Tuple(ref init) = init {
        if init.elems.is_empty() {
            init.span()
                .unwrap()
                .error("I can't think of a legitimate use for lazily initializing the value `()`")
                .emit();
            return TokenStream::new();
        }
    }

    // Assert that the static type implements Sync. If not, user sees an error
    // message like the following. We span this assertion with the field type's
    // line/column so that the error message appears in the correct place.
    //
    //     error[E0277]: the trait bound `*const (): std::marker::Sync` is not satisfied
    //       --> src/main.rs:10:21
    //        |
    //     10 |     static ref PTR: *const () = &();
    //        |                     ^^^^^^^^^ `*const ()` cannot be shared between threads safely
    let assert_sync = quote_spanned! {ty.span()=>
        struct _AssertSync where #ty: std::marker::Sync;
    };

    // Check for Sized. Not vital to check here, but the error message is less
    // confusing this way than if they get a Sized error in one of our
    // implementation details where it assumes Sized.
    //
    //     error[E0277]: the trait bound `str: std::marker::Sized` is not satisfied
    //       --> src/main.rs:10:19
    //        |
    //     10 |     static ref A: str = "";
    //        |                   ^^^ `str` does not have a constant size known at compile-time
    let assert_sized = quote_spanned! {ty.span()=>
        struct _AssertSized where #ty: std::marker::Sized;
    };

    let init_ptr = quote_spanned! {init.span()=>
        Box::into_raw(Box::new(#init))
    };

    let expanded = quote! {
        #visibility struct #name;

        impl std::ops::Deref for #name {
            type Target = #ty;

            fn deref(&self) -> &#ty {
                #assert_sync
                #assert_sized

                static ONCE: std::sync::Once = std::sync::Once::new();
                static mut VALUE: *mut #ty = 0 as *mut #ty;

                unsafe {
                    ONCE.call_once(|| VALUE = #init_ptr);
                    &*VALUE
                }
            }
        }
    };

    TokenStream::from(expanded)
}
<|endoftext|>


<commit_before>extern crate roboime_next;
#[macro_use] extern crate glium;
extern crate clap;
extern crate clock_ticks;
//extern crate image;
extern crate env_logger;
#[macro_use] extern crate log;
extern crate rusttype;
//extern crate arrayvec;
extern crate unicode_normalization;

use std::error::Error;

mod draw;

fn main_loop() -> Result<(), Box<Error>> {
    use std::env;
    use std::thread;
    //use std::io::Cursor;
    use std::time::Duration;
    use std::process::Command;
    use roboime_next::prelude::*;
    use roboime_next::{sim, ai};
    use clap::{Arg, App, AppSettings};
    use glium::{glutin, DisplayBuild, Surface};
    use log::LogLevelFilter;
    use env_logger::LogBuilder;
    //use image::image::GenericImage;
    use ::draw::*;

    let matches = App::new("robime-next-cli")
        .setting(AppSettings::ColoredHelp)
        .setting(AppSettings::DeriveDisplayOrder)
        .setting(AppSettings::TrailingVarArg)
        .about("Connect an AI to a Robocup SSL game through an stdio interface (like codingame).")
        .arg(Arg::with_name("blue")
             .short("b")
             .long("blue")
             .value_name("BLUE COMMAND")
             .help("Command to start the blue AI, accepts arguments."))
        .arg(Arg::with_name("yellow")
             .short("y")
             .long("yellow")
             .value_name("YELLOW COMMAND")
             .help("Command to start the yellow AI, accepts arguments."))
        .arg(Arg::with_name("pause")
             .short("p")
             .long("pause")
             .help("Start the simulator paused."))
        .arg(Arg::with_name("v")
             .short("v")
             .multiple(true)
             .help("Sets the level of verbosity."))
        .arg(Arg::with_name("q")
             .conflicts_with("v")
             .long("quiet")
             .short("q")
             .help("Don't log warnings or errors."))
        //.arg(Arg::with_name("d")
        //     .long("debug")
        //     .short("d")
        //     .help("Enable debug logs."))
        .get_matches();

    {
        let mut builder = LogBuilder::new();
        builder.format(|record| {
            format!("{} [{}] {}", record.level(), record.location().module_path(), record.args())
        });
        let verbosity = matches.occurrences_of("v");
        builder.filter(Some("roboime"), match verbosity {
            0 => LogLevelFilter::Warn,
            1 => LogLevelFilter::Info,
            2 => LogLevelFilter::Debug,
            _ => LogLevelFilter::Trace,
        });
        if matches.is_present("q") {
            builder.filter(Some("roboime"), LogLevelFilter::Off);
        }
        if let Ok(ref log) = env::var("RUST_LOG") {
           builder.parse(log);
        }
        try!(builder.init());
    }

    // building the display, ie. the main object
    let display = try!(glutin::WindowBuilder::new()
        .with_title(format!("RoboIME Next"))
        // 1 extra pixel to align the middle lines to the screen
        .with_dimensions(1041, 741)
        .with_depth_buffer(24)
        .with_gl(glutin::GlRequest::Latest)
        .with_multisampling(4)
        .with_vsync()
        .build_glium());

    let team_side = {
        let mut team_side = Default::default();
        team_side
    };

    let mut is_paused = {
        let mut pause = false;
        if matches.is_present("pause") { pause = true; };
        pause
    };

    // Configs

    let mut ai_blue_cfg = if matches.is_present("blue") {
        let ai_cmd: Vec<&str> = matches.values_of("blue").unwrap().collect();
        let (ai_program, ai_args) = (ai_cmd[0], &ai_cmd[1..]);
        let mut ai_command = Command::new(ai_program);
        ai_command.args(ai_args);
        let mut ai_cfg = ai::Builder::new(ai_command);
        ai_cfg.color(Color::Blue);
        Some(ai_cfg)
    } else {
        None
    };

    let mut ai_yellow_cfg = if matches.is_present("yellow") {
        let ai_cmd: Vec<&str> = matches.values_of("yellow").unwrap().collect();
        let (ai_program, ai_args) = (ai_cmd[0], &ai_cmd[1..]);
        let mut ai_command = Command::new(ai_program);
        ai_command.args(ai_args);
        let mut ai_cfg = ai::Builder::new(ai_command);
        ai_cfg.color(Color::Yellow);
        Some(ai_cfg)
    } else {
        None
    };

    // States

    let mut sim_state = sim::Builder::new()
        .initial_formation(true)
        .team_side(team_side)
        .build();
    let mut draw_game = try!(Game::new(&display)); draw_game.team_side(&display, team_side);

    let mut ai_blue = match ai_blue_cfg {
        Some(mut ai_cfg) => Some(try!(ai_cfg.build())),
        None => None,
    };

    let mut ai_yellow = match ai_yellow_cfg {
        Some(mut ai_cfg) => Some(try!(ai_cfg.build())),
        None => None,
    };

    let mut accumulator = 0;
    let mut previous_clock = clock_ticks::precise_time_ns();
    let mut step_clock = previous_clock;
    let mut step_counter = 0;

    let mut key_meta = false;
    let mut key_ctrl = false;

    // debugger thread
    if let Some(ref mut ai) = ai_blue {
        let debug = ai.debug.take().unwrap();
        thread::spawn(move || {
            for line in debug {
                println!("Blue> {}", line.unwrap());
            }
        });
    }

    if let Some(ref mut ai) = ai_yellow {
        let debug = ai.debug.take().unwrap();
        thread::spawn(move || {
            for line in debug {
                println!("Blue> {}", line.unwrap());
            }
        });
    }

    // init the AI
    debug!("Wait for AI to start...");
    let mut ai_blue_state = match ai_blue {
        Some(ref mut ai) => Some(try!(ai.init(&sim_state))),
        None => None,
    };
    let mut ai_yellow_state = match ai_yellow {
        Some(ref mut ai) => Some(try!(ai.init(&sim_state))),
        None => None,
    };

    //drop(try!(rx.recv()));
    debug!("AI started, going on...");

    // the main loop
    'main: loop {
        #[derive(Copy, Clone, PartialEq, Eq)] enum Shot { No, Fwd, Bkw, }
        let mut single_shot = Shot::No;

        draw_game.update(&display, &sim_state);

        // render the game state
        let view = view_matrix(&[0.0, 0.0, 10.0], &[0.0, 0.0, -1.0], &[0.0, 1.0, 0.0]);
        //let view = view_matrix(&[-4.0, -4.0, 4.0], &[1.0, 1.0, -1.0], &[0.0, 0.0, 1.0]);
        //let view = view_matrix(&[4.0, -4.0, 4.0], &[-1.0, 1.0, -1.0], &[0.0, 0.0, 1.0]);
        //let view = view_matrix(&[-0.2, -0.2, 0.6], &[0.2, 0.2, -0.6], &[0.0, 0.0, 1.0]);
        //let view = view_matrix(&[1.0, 2.0, 3.0], &[1.0, 1.0, -3.0], &[0.0, 1.0, 0.0]);
        //let view = view_matrix(&[-4.0, 0.7, 1.6], &[-0.2, -0.2, -0.6], &[0.0, 0.0, 1.0]);
        //let view = view_matrix(&[-5.0, -0.7, 1.6], &[0.2, 0.2, -0.6], &[0.0, 0.0, 1.0]);
        //let view = view_matrix(&[4.0, 0.7, 1.6], &[0.2, -0.2, -0.6], &[0.0, 0.0, 1.0]);
        //let view = view_matrix(&[5.0, -0.7, 1.6], &[-0.2, 0.2, -0.6], &[0.0, 0.0, 1.0]);
        //let view = view_matrix(&[0.0, 0.0, 0.6], &[0.0, 0.0, -1.0], &[0.0, 1.0, 0.0]);
        let mut target = display.draw();
        let view_port = display.get_window().unwrap().get_inner_size_points().unwrap();
        try!(draw_game.draw_to(&mut target, &sim_state, view_port, view));
        try!(target.finish());

        // polling and handling the events received by the window
        for event in display.poll_events() {
            use glium::glutin::Event::*;
            use glium::glutin::ElementState::*;
            use glium::glutin::VirtualKeyCode::*;

            match event {

                // close on Ctrl+Q, Cmd+Q, Win+Q, Esc, window X button
                KeyboardInput(Pressed, _, Some(Q)) if key_meta || key_ctrl => break 'main,
                KeyboardInput(Pressed, _, Some(Escape)) | Closed => break 'main,

                // modifier keys
                KeyboardInput(Pressed,  _, Some(LWin)) |
                KeyboardInput(Pressed,  _, Some(RWin)) => { key_meta = true; }
                KeyboardInput(Released, _, Some(LWin)) |
                KeyboardInput(Released, _, Some(RWin)) => { key_meta = false; }
                KeyboardInput(Pressed,  _, Some(LControl)) |
                KeyboardInput(Pressed,  _, Some(RControl)) => { key_ctrl = true; }
                KeyboardInput(Released, _, Some(LControl)) |
                KeyboardInput(Released, _, Some(RControl)) => { key_ctrl = false; }

                // some actions
                KeyboardInput(Pressed, _, Some(P)) => {
                    is_paused = !is_paused;
                }
                KeyboardInput(Pressed, _, Some(RBracket)) => {
                    single_shot = Shot::Fwd;
                }
                KeyboardInput(Pressed, _, Some(LBracket)) => {
                    single_shot = Shot::Bkw;
                }
                KeyboardInput(Pressed, _, Some(R)) => {
                    // reset ball position and speed
                    sim_state.ball.pos = Vec2d(0.0, 0.0);
                    sim_state.ball.vel = Vec2d(0.0, 0.0);
                }
                KeyboardInput(..) => {
                    debug!("{:?}", event);
                }
                _ => ()
            }
        }

        const FIXED_TIME_STEP: u64 = 16_666_667;

        let now = clock_ticks::precise_time_ns();
        if !is_paused {
            accumulator += now - previous_clock;

            while accumulator >= FIXED_TIME_STEP {
                accumulator -= FIXED_TIME_STEP;
                let now = clock_ticks::precise_time_ns();
                let delta = now - step_clock;
                if delta >= 1_000_000_000 {
                    // expect ~60 steps per second
                    info!("{:2} steps in {:.03} seconds", step_counter, delta as f32 * 1.0e-9);
                    step_counter = 0;
                    step_clock = now;
                }

                // game step
                let mut cmds = vec![];

                if let Some(ref mut ai_state) = ai_blue_state {
                    cmds.push(try!(ai_state.update(&sim_state)));
                }

                if let Some(ref mut ai_state) = ai_yellow_state {
                    cmds.push(try!(ai_state.update(&sim_state)));
                }

                sim_state.step(&cmds, FIXED_TIME_STEP as f32 * 1.0e-9);
                step_counter += 1;
            }
        }
        previous_clock = now;

        if single_shot != Shot::No {
            // XXX: is there a simple way to no duplicade this?
            // game step
            let mut cmds = vec![];

            if let Some(ref mut ai_state) = ai_blue_state {
                cmds.push(try!(ai_state.update(&sim_state)));
            }

            if let Some(ref mut ai_state) = ai_yellow_state {
                cmds.push(try!(ai_state.update(&sim_state)));
            }

            let mut timestep = FIXED_TIME_STEP as f32 * 1.0e-9;
            if single_shot == Shot::Bkw { timestep = -timestep; }
            sim_state.step(&cmds, timestep);
        }

        thread::sleep(Duration::from_millis(((FIXED_TIME_STEP - accumulator) / 1_000_000) as u64));
    }

    info!("Bye!");
    Ok(())
}

fn main() {
    use std::process::exit;

    if let Err(err) = main_loop() {
        println!("Error: {}.", err.description());

        let mut err: &Error = &*err;
        while let Some(cause) = err.cause() {
            println!("- caused by: {}", cause.description());
            err = cause;
        }

        exit(1);
    }
}
<commit_msg>Corrected warnings<commit_after>extern crate roboime_next;
#[macro_use] extern crate glium;
extern crate clap;
extern crate clock_ticks;
//extern crate image;
extern crate env_logger;
#[macro_use] extern crate log;
extern crate rusttype;
//extern crate arrayvec;
extern crate unicode_normalization;

use std::error::Error;

mod draw;

fn main_loop() -> Result<(), Box<Error>> {
    use std::env;
    use std::thread;
    //use std::io::Cursor;
    use std::time::Duration;
    use std::process::Command;
    use roboime_next::prelude::*;
    use roboime_next::{sim, ai};
    use clap::{Arg, App, AppSettings};
    use glium::{glutin, DisplayBuild, Surface};
    use log::LogLevelFilter;
    use env_logger::LogBuilder;
    //use image::image::GenericImage;
    use ::draw::*;

    let matches = App::new("robime-next-cli")
        .setting(AppSettings::ColoredHelp)
        .setting(AppSettings::DeriveDisplayOrder)
        .setting(AppSettings::TrailingVarArg)
        .about("Connect an AI to a Robocup SSL game through an stdio interface (like codingame).")
        .arg(Arg::with_name("blue")
             .short("b")
             .long("blue")
             .value_name("BLUE COMMAND")
             .help("Command to start the blue AI, accepts arguments."))
        .arg(Arg::with_name("yellow")
             .short("y")
             .long("yellow")
             .value_name("YELLOW COMMAND")
             .help("Command to start the yellow AI, accepts arguments."))
        .arg(Arg::with_name("pause")
             .short("p")
             .long("pause")
             .help("Start the simulator paused."))
        .arg(Arg::with_name("v")
             .short("v")
             .multiple(true)
             .help("Sets the level of verbosity."))
        .arg(Arg::with_name("q")
             .conflicts_with("v")
             .long("quiet")
             .short("q")
             .help("Don't log warnings or errors."))
        //.arg(Arg::with_name("d")
        //     .long("debug")
        //     .short("d")
        //     .help("Enable debug logs."))
        .get_matches();

    {
        let mut builder = LogBuilder::new();
        builder.format(|record| {
            format!("{} [{}] {}", record.level(), record.location().module_path(), record.args())
        });
        let verbosity = matches.occurrences_of("v");
        builder.filter(Some("roboime"), match verbosity {
            0 => LogLevelFilter::Warn,
            1 => LogLevelFilter::Info,
            2 => LogLevelFilter::Debug,
            _ => LogLevelFilter::Trace,
        });
        if matches.is_present("q") {
            builder.filter(Some("roboime"), LogLevelFilter::Off);
        }
        if let Ok(ref log) = env::var("RUST_LOG") {
           builder.parse(log);
        }
        try!(builder.init());
    }

    // building the display, ie. the main object
    let display = try!(glutin::WindowBuilder::new()
        .with_title(format!("RoboIME Next"))
        // 1 extra pixel to align the middle lines to the screen
        .with_dimensions(1041, 741)
        .with_depth_buffer(24)
        .with_gl(glutin::GlRequest::Latest)
        .with_multisampling(4)
        .with_vsync()
        .build_glium());

    let team_side = {
        let team_side = Default::default();
        team_side
    };

    let mut is_paused = {
        let mut pause = false;
        if matches.is_present("pause") { pause = true; };
        pause
    };

    // Configs

    let ai_blue_cfg = if matches.is_present("blue") {
        let ai_cmd: Vec<&str> = matches.values_of("blue").unwrap().collect();
        let (ai_program, ai_args) = (ai_cmd[0], &ai_cmd[1..]);
        let mut ai_command = Command::new(ai_program);
        ai_command.args(ai_args);
        let mut ai_cfg = ai::Builder::new(ai_command);
        ai_cfg.color(Color::Blue);
        Some(ai_cfg)
    } else {
        None
    };

    let ai_yellow_cfg = if matches.is_present("yellow") {
        let ai_cmd: Vec<&str> = matches.values_of("yellow").unwrap().collect();
        let (ai_program, ai_args) = (ai_cmd[0], &ai_cmd[1..]);
        let mut ai_command = Command::new(ai_program);
        ai_command.args(ai_args);
        let mut ai_cfg = ai::Builder::new(ai_command);
        ai_cfg.color(Color::Yellow);
        Some(ai_cfg)
    } else {
        None
    };

    // States

    let mut sim_state = sim::Builder::new()
        .initial_formation(true)
        .team_side(team_side)
        .build();
    let mut draw_game = try!(Game::new(&display)); draw_game.team_side(&display, team_side);

    let mut ai_blue = match ai_blue_cfg {
        Some(mut ai_cfg) => Some(try!(ai_cfg.build())),
        None => None,
    };

    let mut ai_yellow = match ai_yellow_cfg {
        Some(mut ai_cfg) => Some(try!(ai_cfg.build())),
        None => None,
    };

    let mut accumulator = 0;
    let mut previous_clock = clock_ticks::precise_time_ns();
    let mut step_clock = previous_clock;
    let mut step_counter = 0;

    let mut key_meta = false;
    let mut key_ctrl = false;

    // debugger thread
    if let Some(ref mut ai) = ai_blue {
        let debug = ai.debug.take().unwrap();
        thread::spawn(move || {
            for line in debug {
                println!("Blue> {}", line.unwrap());
            }
        });
    }

    if let Some(ref mut ai) = ai_yellow {
        let debug = ai.debug.take().unwrap();
        thread::spawn(move || {
            for line in debug {
                println!("Blue> {}", line.unwrap());
            }
        });
    }

    // init the AI
    debug!("Wait for AI to start...");
    let mut ai_blue_state = match ai_blue {
        Some(ref mut ai) => Some(try!(ai.init(&sim_state))),
        None => None,
    };
    let mut ai_yellow_state = match ai_yellow {
        Some(ref mut ai) => Some(try!(ai.init(&sim_state))),
        None => None,
    };

    //drop(try!(rx.recv()));
    debug!("AI started, going on...");

    // the main loop
    'main: loop {
        #[derive(Copy, Clone, PartialEq, Eq)] enum Shot { No, Fwd, Bkw, }
        let mut single_shot = Shot::No;

        draw_game.update(&display, &sim_state);

        // render the game state
        let view = view_matrix(&[0.0, 0.0, 10.0], &[0.0, 0.0, -1.0], &[0.0, 1.0, 0.0]);
        //let view = view_matrix(&[-4.0, -4.0, 4.0], &[1.0, 1.0, -1.0], &[0.0, 0.0, 1.0]);
        //let view = view_matrix(&[4.0, -4.0, 4.0], &[-1.0, 1.0, -1.0], &[0.0, 0.0, 1.0]);
        //let view = view_matrix(&[-0.2, -0.2, 0.6], &[0.2, 0.2, -0.6], &[0.0, 0.0, 1.0]);
        //let view = view_matrix(&[1.0, 2.0, 3.0], &[1.0, 1.0, -3.0], &[0.0, 1.0, 0.0]);
        //let view = view_matrix(&[-4.0, 0.7, 1.6], &[-0.2, -0.2, -0.6], &[0.0, 0.0, 1.0]);
        //let view = view_matrix(&[-5.0, -0.7, 1.6], &[0.2, 0.2, -0.6], &[0.0, 0.0, 1.0]);
        //let view = view_matrix(&[4.0, 0.7, 1.6], &[0.2, -0.2, -0.6], &[0.0, 0.0, 1.0]);
        //let view = view_matrix(&[5.0, -0.7, 1.6], &[-0.2, 0.2, -0.6], &[0.0, 0.0, 1.0]);
        //let view = view_matrix(&[0.0, 0.0, 0.6], &[0.0, 0.0, -1.0], &[0.0, 1.0, 0.0]);
        let mut target = display.draw();
        let view_port = display.get_window().unwrap().get_inner_size_points().unwrap();
        try!(draw_game.draw_to(&mut target, &sim_state, view_port, view));
        try!(target.finish());

        // polling and handling the events received by the window
        for event in display.poll_events() {
            use glium::glutin::Event::*;
            use glium::glutin::ElementState::*;
            use glium::glutin::VirtualKeyCode::*;

            match event {

                // close on Ctrl+Q, Cmd+Q, Win+Q, Esc, window X button
                KeyboardInput(Pressed, _, Some(Q)) if key_meta || key_ctrl => break 'main,
                KeyboardInput(Pressed, _, Some(Escape)) | Closed => break 'main,

                // modifier keys
                KeyboardInput(Pressed,  _, Some(LWin)) |
                KeyboardInput(Pressed,  _, Some(RWin)) => { key_meta = true; }
                KeyboardInput(Released, _, Some(LWin)) |
                KeyboardInput(Released, _, Some(RWin)) => { key_meta = false; }
                KeyboardInput(Pressed,  _, Some(LControl)) |
                KeyboardInput(Pressed,  _, Some(RControl)) => { key_ctrl = true; }
                KeyboardInput(Released, _, Some(LControl)) |
                KeyboardInput(Released, _, Some(RControl)) => { key_ctrl = false; }

                // some actions
                KeyboardInput(Pressed, _, Some(P)) => {
                    is_paused = !is_paused;
                }
                KeyboardInput(Pressed, _, Some(RBracket)) => {
                    single_shot = Shot::Fwd;
                }
                KeyboardInput(Pressed, _, Some(LBracket)) => {
                    single_shot = Shot::Bkw;
                }
                KeyboardInput(Pressed, _, Some(R)) => {
                    // reset ball position and speed
                    sim_state.ball.pos = Vec2d(0.0, 0.0);
                    sim_state.ball.vel = Vec2d(0.0, 0.0);
                }
                KeyboardInput(..) => {
                    debug!("{:?}", event);
                }
                _ => ()
            }
        }

        const FIXED_TIME_STEP: u64 = 16_666_667;

        let now = clock_ticks::precise_time_ns();
        if !is_paused {
            accumulator += now - previous_clock;

            while accumulator >= FIXED_TIME_STEP {
                accumulator -= FIXED_TIME_STEP;
                let now = clock_ticks::precise_time_ns();
                let delta = now - step_clock;
                if delta >= 1_000_000_000 {
                    // expect ~60 steps per second
                    info!("{:2} steps in {:.03} seconds", step_counter, delta as f32 * 1.0e-9);
                    step_counter = 0;
                    step_clock = now;
                }

                // game step
                let mut cmds = vec![];

                if let Some(ref mut ai_state) = ai_blue_state {
                    cmds.push(try!(ai_state.update(&sim_state)));
                }

                if let Some(ref mut ai_state) = ai_yellow_state {
                    cmds.push(try!(ai_state.update(&sim_state)));
                }

                sim_state.step(&cmds, FIXED_TIME_STEP as f32 * 1.0e-9);
                step_counter += 1;
            }
        }
        previous_clock = now;

        if single_shot != Shot::No {
            // XXX: is there a simple way to no duplicade this?
            // game step
            let mut cmds = vec![];

            if let Some(ref mut ai_state) = ai_blue_state {
                cmds.push(try!(ai_state.update(&sim_state)));
            }

            if let Some(ref mut ai_state) = ai_yellow_state {
                cmds.push(try!(ai_state.update(&sim_state)));
            }

            let mut timestep = FIXED_TIME_STEP as f32 * 1.0e-9;
            if single_shot == Shot::Bkw { timestep = -timestep; }
            sim_state.step(&cmds, timestep);
        }

        thread::sleep(Duration::from_millis(((FIXED_TIME_STEP - accumulator) / 1_000_000) as u64));
    }

    info!("Bye!");
    Ok(())
}

fn main() {
    use std::process::exit;

    if let Err(err) = main_loop() {
        println!("Error: {}.", err.description());

        let mut err: &Error = &*err;
        while let Some(cause) = err.cause() {
            println!("- caused by: {}", cause.description());
            err = cause;
        }

        exit(1);
    }
}
<|endoftext|>


<commit_before>import codemap::span;
import ast::*;

fn respan<T: copy>(sp: span, t: T) -> spanned<T> {
    ret {node: t, span: sp};
}

/* assuming that we're not in macro expansion */
fn mk_sp(lo: uint, hi: uint) -> span {
    ret {lo: lo, hi: hi, expanded_from: codemap::os_none};
}

// make this a const, once the compiler supports it
fn dummy_sp() -> span { ret mk_sp(0u, 0u); }

fn path_name(p: @path) -> str { path_name_i(p.node.idents) }

fn path_name_i(idents: [ident]) -> str { str::connect(idents, "::") }

fn local_def(id: node_id) -> def_id { ret {crate: local_crate, node: id}; }

fn variant_def_ids(d: def) -> {tg: def_id, var: def_id} {
    alt d { def_variant(tag_id, var_id) { ret {tg: tag_id, var: var_id}; } }
}

fn def_id_of_def(d: def) -> def_id {
    alt d {
      def_fn(id, _) | def_self(id) | def_mod(id) |
      def_native_mod(id) | def_const(id) | def_arg(id, _) | def_local(id, _) |
      def_variant(_, id) | def_ty(id) | def_ty_param(id, _) |
      def_binding(id) | def_use(id) | def_native_ty(id) |
      def_native_fn(id, _) | def_upvar(id, _, _) { id }
    }
}

fn binop_to_str(op: binop) -> str {
    alt op {
      add { ret "+"; }
      subtract { ret "-"; }
      mul { ret "*"; }
      div { ret "/"; }
      rem { ret "%"; }
      and { ret "&&"; }
      or { ret "||"; }
      bitxor { ret "^"; }
      bitand { ret "&"; }
      bitor { ret "|"; }
      lsl { ret "<<"; }
      lsr { ret ">>"; }
      asr { ret ">>>"; }
      eq { ret "=="; }
      lt { ret "<"; }
      le { ret "<="; }
      ne { ret "!="; }
      ge { ret ">="; }
      gt { ret ">"; }
    }
}

pure fn lazy_binop(b: binop) -> bool {
    alt b { and { true } or { true } _ { false } }
}

fn unop_to_str(op: unop) -> str {
    alt op {
      box(mt) { if mt == mut { ret "@mutable "; } ret "@"; }
      uniq(mt) { if mt == mut { ret "~mutable "; } ret "~"; }
      deref { ret "*"; }
      not { ret "!"; }
      neg { ret "-"; }
    }
}

fn is_path(e: @expr) -> bool {
    ret alt e.node { expr_path(_) { true } _ { false } };
}

fn int_ty_to_str(t: int_ty) -> str {
    alt t {
      ty_i { "" } ty_i8 { "i8" } ty_i16 { "i16" }
      ty_i32 { "i32" } ty_i64 { "i64" }
    }
}

fn int_ty_max(t: int_ty) -> u64 {
    alt t {
      ty_i8 { 0x80u64 }
      ty_i16 { 0x800u64 }
      ty_char | ty_i32 { 0x80000000u64 }
      ty_i64 { 0x8000000000000000u64 }
    }
}

fn uint_ty_to_str(t: uint_ty) -> str {
    alt t {
      ty_u { "u" } ty_u8 { "u8" } ty_u16 { "u16" }
      ty_u32 { "u32" } ty_u64 { "u64" }
    }
}

fn uint_ty_max(t: uint_ty) -> u64 {
    alt t {
      ty_u8 { 0xffu64 }
      ty_u16 { 0xffffu64 }
      ty_u32 { 0xffffffffu64 }
      ty_u64 { 0xffffffffffffffffu64 }
    }
}

fn float_ty_to_str(t: float_ty) -> str {
    alt t { ty_f { "" } ty_f32 { "f32" } ty_f64 { "f64" } }
}

fn is_exported(i: ident, m: _mod) -> bool {
    let nonlocal = true;
    let parent_tag : option<ident> = none;
    for it: @item in m.items {
        if it.ident == i { nonlocal = false; }
        alt it.node {
          item_tag(variants, _) {
            for v: variant in variants {
                if v.node.name == i {
                   nonlocal = false;
                   parent_tag = some(it.ident);
                }
            }
          }
          _ { }
        }
        if !nonlocal { break; }
    }
    let count = 0u;
    for vi: @view_item in m.view_items {
        alt vi.node {
          view_item_export(ids, _) {
              // If any of ids is a tag, we want to consider
              // all the variants to be exported
            for id in ids {
                if str::eq(i, id) { ret true; }
                alt parent_tag {
                    some(parent_tag_id) {
                        if str::eq(id, parent_tag_id) { ret true; }
                    }
                    _ { }
                 }
            }
            count += 1u;
          }
          view_item_export_tag_none(id, _) {
              if str::eq(i, id) { ret true; }
              count += 1u;
          }
          view_item_export_tag_some(id, ids, _) {
              if str::eq(i, id) { ret true; }
              for id in ids { if str::eq(i, id.node.name) { ret true; } }
              count += 1u;
          }
          _ {/* fall through */ }
        }
    }
    // If there are no declared exports then
    // everything not imported is exported
    // even if it's nonlocal (since it's explicit)
    ret count == 0u && !nonlocal;
}

pure fn is_call_expr(e: @expr) -> bool {
    alt e.node { expr_call(_, _, _) { true } _ { false } }
}

fn is_constraint_arg(e: @expr) -> bool {
    alt e.node {
      expr_lit(_) { ret true; }
      expr_path(_) { ret true; }
      _ { ret false; }
    }
}

fn eq_ty(&&a: @ty, &&b: @ty) -> bool { ret box::ptr_eq(a, b); }

fn hash_ty(&&t: @ty) -> uint {
    let res = (t.span.lo << 16u) + t.span.hi;
    ret res;
}

fn hash_def_id(&&id: def_id) -> uint {
    (id.crate as uint << 16u) + (id.node as uint)
}

fn eq_def_id(&&a: def_id, &&b: def_id) -> bool {
    a == b
}

fn new_def_id_hash<T: copy>() -> std::map::hashmap<def_id, T> {
    std::map::mk_hashmap(hash_def_id, eq_def_id)
}

fn block_from_expr(e: @expr) -> blk {
    let blk_ = default_block([], option::some::<@expr>(e), e.id);
    ret {node: blk_, span: e.span};
}

fn default_block(stmts1: [@stmt], expr1: option::t<@expr>, id1: node_id) ->
   blk_ {
    {view_items: [], stmts: stmts1, expr: expr1, id: id1, rules: default_blk}
}

// This is a convenience function to transfor ternary expressions to if
// expressions so that they can be treated the same
fn ternary_to_if(e: @expr) -> @expr {
    alt e.node {
      expr_ternary(cond, then, els) {
        let then_blk = block_from_expr(then);
        let els_blk = block_from_expr(els);
        let els_expr =
            @{id: els.id, node: expr_block(els_blk), span: els.span};
        ret @{id: e.id,
              node: expr_if(cond, then_blk, option::some(els_expr)),
              span: e.span};
      }
      _ { fail; }
    }
}

// FIXME this doesn't handle big integer/float literals correctly (nor does
// the rest of our literal handling)
enum const_val {
    const_float(float),
    const_int(i64),
    const_uint(u64),
    const_str(str),
}

// FIXME: issue #1417
fn eval_const_expr(e: @expr) -> const_val {
    fn fromb(b: bool) -> const_val { const_int(b as i64) }
    alt e.node {
      expr_unary(neg, inner) {
        alt eval_const_expr(inner) {
          const_float(f) { const_float(-f) }
          const_int(i) { const_int(-i) }
          const_uint(i) { const_uint(-i) }
        }
      }
      expr_unary(not, inner) {
        alt eval_const_expr(inner) {
          const_int(i) { const_int(!i) }
          const_uint(i) { const_uint(!i) }
        }
      }
      expr_binary(op, a, b) {
        alt (eval_const_expr(a), eval_const_expr(b)) {
          (const_float(a), const_float(b)) {
            alt op {
              add { const_float(a + b) } subtract { const_float(a - b) }
              mul { const_float(a * b) } div { const_float(a / b) }
              rem { const_float(a % b) } eq { fromb(a == b) }
              lt { fromb(a < b) } le { fromb(a <= b) } ne { fromb(a != b) }
              ge { fromb(a >= b) } gt { fromb(a > b) }
            }
          }
          (const_int(a), const_int(b)) {
            alt op {
              add { const_int(a + b) } subtract { const_int(a - b) }
              mul { const_int(a * b) } div { const_int(a / b) }
              rem { const_int(a % b) } and | bitand { const_int(a & b) }
              or | bitor { const_int(a | b) } bitxor { const_int(a ^ b) }
              eq { fromb(a == b) } lt { fromb(a < b) }
              le { fromb(a <= b) } ne { fromb(a != b) }
              ge { fromb(a >= b) } gt { fromb(a > b) }
            }
          }
          (const_uint(a), const_uint(b)) {
            alt op {
              add { const_uint(a + b) } subtract { const_uint(a - b) }
              mul { const_uint(a * b) } div { const_uint(a / b) }
              rem { const_uint(a % b) } and | bitand { const_uint(a & b) }
              or | bitor { const_uint(a | b) } bitxor { const_uint(a ^ b) }
              eq { fromb(a == b) } lt { fromb(a < b) }
              le { fromb(a <= b) } ne { fromb(a != b) }
              ge { fromb(a >= b) } gt { fromb(a > b) }
            }
          }
        }
      }
      expr_lit(lit) { lit_to_const(lit) }
    }
}

fn lit_to_const(lit: @lit) -> const_val {
    alt lit.node {
      lit_str(s) { const_str(s) }
      lit_int(n, _) { const_int(n) }
      lit_uint(n, _) { const_uint(n) }
      lit_float(n, _) { const_float(float::from_str(n)) }
      lit_nil { const_int(0i64) }
      lit_bool(b) { const_int(b as i64) }
    }
}

fn compare_const_vals(a: const_val, b: const_val) -> int {
  alt (a, b) {
    (const_int(a), const_int(b)) { a == b ? 0 : a < b ? -1 : 1 }
    (const_uint(a), const_uint(b)) { a == b ? 0 : a < b ? -1 : 1 }
    (const_float(a), const_float(b)) { a == b ? 0 : a < b ? -1 : 1 }
    (const_str(a), const_str(b)) { a == b ? 0 : a < b ? -1 : 1 }
  }
}

fn compare_lit_exprs(a: @expr, b: @expr) -> int {
  compare_const_vals(eval_const_expr(a), eval_const_expr(b))
}

fn lit_expr_eq(a: @expr, b: @expr) -> bool { compare_lit_exprs(a, b) == 0 }

fn lit_eq(a: @lit, b: @lit) -> bool {
    compare_const_vals(lit_to_const(a), lit_to_const(b)) == 0
}

fn ident_to_path(s: span, i: ident) -> @path {
    @respan(s, {global: false, idents: [i], types: []})
}

// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// End:
<commit_msg>Add bit-shifting ops to ast_util::eval_const_expr<commit_after>import codemap::span;
import ast::*;

fn respan<T: copy>(sp: span, t: T) -> spanned<T> {
    ret {node: t, span: sp};
}

/* assuming that we're not in macro expansion */
fn mk_sp(lo: uint, hi: uint) -> span {
    ret {lo: lo, hi: hi, expanded_from: codemap::os_none};
}

// make this a const, once the compiler supports it
fn dummy_sp() -> span { ret mk_sp(0u, 0u); }

fn path_name(p: @path) -> str { path_name_i(p.node.idents) }

fn path_name_i(idents: [ident]) -> str { str::connect(idents, "::") }

fn local_def(id: node_id) -> def_id { ret {crate: local_crate, node: id}; }

fn variant_def_ids(d: def) -> {tg: def_id, var: def_id} {
    alt d { def_variant(tag_id, var_id) { ret {tg: tag_id, var: var_id}; } }
}

fn def_id_of_def(d: def) -> def_id {
    alt d {
      def_fn(id, _) | def_self(id) | def_mod(id) |
      def_native_mod(id) | def_const(id) | def_arg(id, _) | def_local(id, _) |
      def_variant(_, id) | def_ty(id) | def_ty_param(id, _) |
      def_binding(id) | def_use(id) | def_native_ty(id) |
      def_native_fn(id, _) | def_upvar(id, _, _) { id }
    }
}

fn binop_to_str(op: binop) -> str {
    alt op {
      add { ret "+"; }
      subtract { ret "-"; }
      mul { ret "*"; }
      div { ret "/"; }
      rem { ret "%"; }
      and { ret "&&"; }
      or { ret "||"; }
      bitxor { ret "^"; }
      bitand { ret "&"; }
      bitor { ret "|"; }
      lsl { ret "<<"; }
      lsr { ret ">>"; }
      asr { ret ">>>"; }
      eq { ret "=="; }
      lt { ret "<"; }
      le { ret "<="; }
      ne { ret "!="; }
      ge { ret ">="; }
      gt { ret ">"; }
    }
}

pure fn lazy_binop(b: binop) -> bool {
    alt b { and { true } or { true } _ { false } }
}

fn unop_to_str(op: unop) -> str {
    alt op {
      box(mt) { if mt == mut { ret "@mutable "; } ret "@"; }
      uniq(mt) { if mt == mut { ret "~mutable "; } ret "~"; }
      deref { ret "*"; }
      not { ret "!"; }
      neg { ret "-"; }
    }
}

fn is_path(e: @expr) -> bool {
    ret alt e.node { expr_path(_) { true } _ { false } };
}

fn int_ty_to_str(t: int_ty) -> str {
    alt t {
      ty_i { "" } ty_i8 { "i8" } ty_i16 { "i16" }
      ty_i32 { "i32" } ty_i64 { "i64" }
    }
}

fn int_ty_max(t: int_ty) -> u64 {
    alt t {
      ty_i8 { 0x80u64 }
      ty_i16 { 0x800u64 }
      ty_char | ty_i32 { 0x80000000u64 }
      ty_i64 { 0x8000000000000000u64 }
    }
}

fn uint_ty_to_str(t: uint_ty) -> str {
    alt t {
      ty_u { "u" } ty_u8 { "u8" } ty_u16 { "u16" }
      ty_u32 { "u32" } ty_u64 { "u64" }
    }
}

fn uint_ty_max(t: uint_ty) -> u64 {
    alt t {
      ty_u8 { 0xffu64 }
      ty_u16 { 0xffffu64 }
      ty_u32 { 0xffffffffu64 }
      ty_u64 { 0xffffffffffffffffu64 }
    }
}

fn float_ty_to_str(t: float_ty) -> str {
    alt t { ty_f { "" } ty_f32 { "f32" } ty_f64 { "f64" } }
}

fn is_exported(i: ident, m: _mod) -> bool {
    let nonlocal = true;
    let parent_tag : option<ident> = none;
    for it: @item in m.items {
        if it.ident == i { nonlocal = false; }
        alt it.node {
          item_tag(variants, _) {
            for v: variant in variants {
                if v.node.name == i {
                   nonlocal = false;
                   parent_tag = some(it.ident);
                }
            }
          }
          _ { }
        }
        if !nonlocal { break; }
    }
    let count = 0u;
    for vi: @view_item in m.view_items {
        alt vi.node {
          view_item_export(ids, _) {
              // If any of ids is a tag, we want to consider
              // all the variants to be exported
            for id in ids {
                if str::eq(i, id) { ret true; }
                alt parent_tag {
                    some(parent_tag_id) {
                        if str::eq(id, parent_tag_id) { ret true; }
                    }
                    _ { }
                 }
            }
            count += 1u;
          }
          view_item_export_tag_none(id, _) {
              if str::eq(i, id) { ret true; }
              count += 1u;
          }
          view_item_export_tag_some(id, ids, _) {
              if str::eq(i, id) { ret true; }
              for id in ids { if str::eq(i, id.node.name) { ret true; } }
              count += 1u;
          }
          _ {/* fall through */ }
        }
    }
    // If there are no declared exports then
    // everything not imported is exported
    // even if it's nonlocal (since it's explicit)
    ret count == 0u && !nonlocal;
}

pure fn is_call_expr(e: @expr) -> bool {
    alt e.node { expr_call(_, _, _) { true } _ { false } }
}

fn is_constraint_arg(e: @expr) -> bool {
    alt e.node {
      expr_lit(_) { ret true; }
      expr_path(_) { ret true; }
      _ { ret false; }
    }
}

fn eq_ty(&&a: @ty, &&b: @ty) -> bool { ret box::ptr_eq(a, b); }

fn hash_ty(&&t: @ty) -> uint {
    let res = (t.span.lo << 16u) + t.span.hi;
    ret res;
}

fn hash_def_id(&&id: def_id) -> uint {
    (id.crate as uint << 16u) + (id.node as uint)
}

fn eq_def_id(&&a: def_id, &&b: def_id) -> bool {
    a == b
}

fn new_def_id_hash<T: copy>() -> std::map::hashmap<def_id, T> {
    std::map::mk_hashmap(hash_def_id, eq_def_id)
}

fn block_from_expr(e: @expr) -> blk {
    let blk_ = default_block([], option::some::<@expr>(e), e.id);
    ret {node: blk_, span: e.span};
}

fn default_block(stmts1: [@stmt], expr1: option::t<@expr>, id1: node_id) ->
   blk_ {
    {view_items: [], stmts: stmts1, expr: expr1, id: id1, rules: default_blk}
}

// This is a convenience function to transfor ternary expressions to if
// expressions so that they can be treated the same
fn ternary_to_if(e: @expr) -> @expr {
    alt e.node {
      expr_ternary(cond, then, els) {
        let then_blk = block_from_expr(then);
        let els_blk = block_from_expr(els);
        let els_expr =
            @{id: els.id, node: expr_block(els_blk), span: els.span};
        ret @{id: e.id,
              node: expr_if(cond, then_blk, option::some(els_expr)),
              span: e.span};
      }
      _ { fail; }
    }
}

// FIXME this doesn't handle big integer/float literals correctly (nor does
// the rest of our literal handling)
enum const_val {
    const_float(float),
    const_int(i64),
    const_uint(u64),
    const_str(str),
}

// FIXME: issue #1417
fn eval_const_expr(e: @expr) -> const_val {
    fn fromb(b: bool) -> const_val { const_int(b as i64) }
    alt e.node {
      expr_unary(neg, inner) {
        alt eval_const_expr(inner) {
          const_float(f) { const_float(-f) }
          const_int(i) { const_int(-i) }
          const_uint(i) { const_uint(-i) }
        }
      }
      expr_unary(not, inner) {
        alt eval_const_expr(inner) {
          const_int(i) { const_int(!i) }
          const_uint(i) { const_uint(!i) }
        }
      }
      expr_binary(op, a, b) {
        alt (eval_const_expr(a), eval_const_expr(b)) {
          (const_float(a), const_float(b)) {
            alt op {
              add { const_float(a + b) } subtract { const_float(a - b) }
              mul { const_float(a * b) } div { const_float(a / b) }
              rem { const_float(a % b) } eq { fromb(a == b) }
              lt { fromb(a < b) } le { fromb(a <= b) } ne { fromb(a != b) }
              ge { fromb(a >= b) } gt { fromb(a > b) }
            }
          }
          (const_int(a), const_int(b)) {
            alt op {
              add { const_int(a + b) } subtract { const_int(a - b) }
              mul { const_int(a * b) } div { const_int(a / b) }
              rem { const_int(a % b) } and | bitand { const_int(a & b) }
              or | bitor { const_int(a | b) } bitxor { const_int(a ^ b) }
              lsl { const_int(a << b) } lsr { const_int(a >> b) }
              asr { const_int(a >>> b) }
              eq { fromb(a == b) } lt { fromb(a < b) }
              le { fromb(a <= b) } ne { fromb(a != b) }
              ge { fromb(a >= b) } gt { fromb(a > b) }
            }
          }
          (const_uint(a), const_uint(b)) {
            alt op {
              add { const_uint(a + b) } subtract { const_uint(a - b) }
              mul { const_uint(a * b) } div { const_uint(a / b) }
              rem { const_uint(a % b) } and | bitand { const_uint(a & b) }
              or | bitor { const_uint(a | b) } bitxor { const_uint(a ^ b) }
              lsl { const_int(a << b as i64) } lsr { const_int(a >> b as i64) }
              asr { const_int(a >>> b as i64) }
              eq { fromb(a == b) } lt { fromb(a < b) }
              le { fromb(a <= b) } ne { fromb(a != b) }
              ge { fromb(a >= b) } gt { fromb(a > b) }
            }
          }
        }
      }
      expr_lit(lit) { lit_to_const(lit) }
    }
}

fn lit_to_const(lit: @lit) -> const_val {
    alt lit.node {
      lit_str(s) { const_str(s) }
      lit_int(n, _) { const_int(n) }
      lit_uint(n, _) { const_uint(n) }
      lit_float(n, _) { const_float(float::from_str(n)) }
      lit_nil { const_int(0i64) }
      lit_bool(b) { const_int(b as i64) }
    }
}

fn compare_const_vals(a: const_val, b: const_val) -> int {
  alt (a, b) {
    (const_int(a), const_int(b)) { a == b ? 0 : a < b ? -1 : 1 }
    (const_uint(a), const_uint(b)) { a == b ? 0 : a < b ? -1 : 1 }
    (const_float(a), const_float(b)) { a == b ? 0 : a < b ? -1 : 1 }
    (const_str(a), const_str(b)) { a == b ? 0 : a < b ? -1 : 1 }
  }
}

fn compare_lit_exprs(a: @expr, b: @expr) -> int {
  compare_const_vals(eval_const_expr(a), eval_const_expr(b))
}

fn lit_expr_eq(a: @expr, b: @expr) -> bool { compare_lit_exprs(a, b) == 0 }

fn lit_eq(a: @lit, b: @lit) -> bool {
    compare_const_vals(lit_to_const(a), lit_to_const(b)) == 0
}

fn ident_to_path(s: span, i: ident) -> @path {
    @respan(s, {global: false, idents: [i], types: []})
}

// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// End:
<|endoftext|>


<commit_before>use image::ImageResult;
use mli::{Forward, Graph, Train};
use mli_conv::Conv2;
use mli_ndarray::Map2Static;
use mli_relu::Softplus;
use mli_sigmoid::Logistic;
use ndarray::{array, s, Array, Array2};
use ndarray_image::{open_gray_image, save_gray_image};
use rand_core::SeedableRng;
use rand_distr::{Distribution, Normal};
use rand_pcg::Pcg64;
use std::path::{Path, PathBuf};
use structopt::StructOpt;

#[derive(Debug, StructOpt)]
#[structopt(name = "image", about = "Loads and convolves an image as a test")]
struct Opt {
    /// Number of epochs
    #[structopt(short = "t", default_value = "2000")]
    epochs: usize,
    /// Number of epochs per output image
    #[structopt(short = "s", default_value = "10")]
    show_every: usize,
    /// Initial learning rate
    #[structopt(short = "i", default_value = "0.000000000001")]
    initial_learning_rate: f32,
    /// Learning rate multiplier per epoch
    #[structopt(short = "m", default_value = "1.003")]
    learning_rate_multiplier: f32,
    /// File to load
    #[structopt(parse(from_os_str))]
    file: PathBuf,
    /// Output directory
    #[structopt(parse(from_os_str))]
    output_dir: PathBuf,
}

fn sobel(image: &Array2<f32>) -> Array2<f32> {
    let down_filter = array![[-1.0, -2.0, -1.0], [0.0, 0.0, 0.0], [1.0, 2.0, 1.0],];
    let right_filter = down_filter.t().to_owned();
    let down = Conv2(down_filter).forward(&image).1;
    let right = Conv2(right_filter).forward(&image).1;
    (down.map(|f| f.powi(2)) + right.map(|f| f.powi(2))).map(|f| f.sqrt())
}

fn open_image(path: impl AsRef<Path>) -> ImageResult<Array2<f32>> {
    let image = open_gray_image(path)?;
    Ok(image.map(|&n| f32::from(n) / 255.0))
}

fn save_image(path: impl AsRef<Path>, image: &Array2<f32>) -> ImageResult<()> {
    let image = image.map(|&n| num::clamp(n * 255.0, 0.0, 255.0) as u8);
    save_gray_image(path, image.view())
}

fn main() -> ImageResult<()> {
    let opt = Opt::from_args();
    let mut prng = Pcg64::from_seed([0; 32]);
    let image = open_image(opt.file)?;
    let sobel_image = sobel(&image);
    let conv_layers = 4;
    let filter_radius = 1usize;
    let filter_len = (filter_radius * 2 + 1).pow(2);
    let padding = (conv_layers * filter_radius - 1) as i32;
    #[allow(clippy::deref_addrof)]
    let expected = sobel_image.slice(s![padding..-padding, padding..-padding]);
    save_image(opt.output_dir.join("actual.png"), &expected.to_owned())?;
    let mut random_filter = |mean: f32, variance: f32| {
        // Xavier initialize by changing the variance to be 1/N where N is the number of neurons.
        Array::from_iter(
            Normal::new(mean / filter_len as f32, variance / filter_len as f32)
                .unwrap()
                .sample_iter(&mut prng)
                .take(filter_len),
        )
        .into_shape((filter_radius * 2 + 1, filter_radius * 2 + 1))
        .unwrap()
    };
    let mut train_filter = Conv2(random_filter(0.0, 3.0))
        .chain(Map2Static(Softplus))
        .chain(Conv2(random_filter(0.0, 3.0)))
        .chain(Map2Static(Logistic))
        .chain(Conv2(random_filter(0.0, 3.0)))
        .chain(Map2Static(Logistic))
        .chain(Conv2(random_filter(15.0, 15.0)));
    let mut learn_rate = opt.initial_learning_rate;
    for i in 0..opt.epochs {
        let (internal, output) = train_filter.forward(&image);
        if i % opt.show_every == 0 {
            save_image(opt.output_dir.join(format!("epoch{:04}.png", i)), &output)?;
        }
        let loss = (output.clone() - expected.view()).map(|n| n.powi(2)).sum();
        eprintln!("epoch {:04} loss: {}, learn_rate: {}", i, loss, learn_rate);
        // The loss function is (n - t)^2, so 2*(n - t) is dE/df where
        // `E` is loss and `f` is output.
        let delta_loss = (output - expected).map(|n| 2.0 * n);
        let output_delta = -learn_rate * delta_loss;
        train_filter.propogate(&image, &internal, &output_delta);
        learn_rate *= opt.learning_rate_multiplier;
    }
    Ok(())
}
<commit_msg>more properly do xavier init<commit_after>use image::ImageResult;
use mli::{Forward, Graph, Train};
use mli_conv::Conv2;
use mli_ndarray::Map2Static;
use mli_relu::Softplus;
use mli_sigmoid::Logistic;
use ndarray::{array, s, Array, Array2};
use ndarray_image::{open_gray_image, save_gray_image};
use rand_core::SeedableRng;
use rand_distr::{Distribution, Normal};
use rand_pcg::Pcg64;
use std::path::{Path, PathBuf};
use structopt::StructOpt;

#[derive(Debug, StructOpt)]
#[structopt(name = "image", about = "Loads and convolves an image as a test")]
struct Opt {
    /// Number of epochs
    #[structopt(short = "t", default_value = "2000")]
    epochs: usize,
    /// Number of epochs per output image
    #[structopt(short = "s", default_value = "10")]
    show_every: usize,
    /// Initial learning rate
    #[structopt(short = "i", default_value = "0.000000000001")]
    initial_learning_rate: f32,
    /// Learning rate multiplier per epoch
    #[structopt(short = "m", default_value = "1.003")]
    learning_rate_multiplier: f32,
    /// File to load
    #[structopt(parse(from_os_str))]
    file: PathBuf,
    /// Output directory
    #[structopt(parse(from_os_str))]
    output_dir: PathBuf,
}

fn sobel(image: &Array2<f32>) -> Array2<f32> {
    let down_filter = array![[-1.0, -2.0, -1.0], [0.0, 0.0, 0.0], [1.0, 2.0, 1.0],];
    let right_filter = down_filter.t().to_owned();
    let down = Conv2(down_filter).forward(&image).1;
    let right = Conv2(right_filter).forward(&image).1;
    (down.map(|f| f.powi(2)) + right.map(|f| f.powi(2))).map(|f| f.sqrt())
}

fn open_image(path: impl AsRef<Path>) -> ImageResult<Array2<f32>> {
    let image = open_gray_image(path)?;
    Ok(image.map(|&n| f32::from(n) / 255.0))
}

fn save_image(path: impl AsRef<Path>, image: &Array2<f32>) -> ImageResult<()> {
    let image = image.map(|&n| num::clamp(n * 255.0, 0.0, 255.0) as u8);
    save_gray_image(path, image.view())
}

fn main() -> ImageResult<()> {
    let opt = Opt::from_args();
    let mut prng = Pcg64::from_seed([0; 32]);
    let image = open_image(opt.file)?;
    let sobel_image = sobel(&image);
    let conv_layers = 4;
    let filter_radius = 1usize;
    let filter_len = (filter_radius * 2 + 1).pow(2);
    let padding = (conv_layers * filter_radius - 1) as i32;
    #[allow(clippy::deref_addrof)]
    let expected = sobel_image.slice(s![padding..-padding, padding..-padding]);
    save_image(opt.output_dir.join("actual.png"), &expected.to_owned())?;
    let mut random_filter = |mean: f32, variance: f32| {
        // Xavier initialize by changing the variance to be 1/N where N is the number of neurons.
        Array::from_iter(
            Normal::new(mean / filter_len as f32, variance / filter_len as f32)
                .unwrap()
                .sample_iter(&mut prng)
                .take(filter_len),
        )
        .into_shape((filter_radius * 2 + 1, filter_radius * 2 + 1))
        .unwrap()
    };
    let mut train_filter = Conv2(random_filter(1.0, 9.0f32.powi(-1)))
        .chain(Map2Static(Softplus))
        .chain(Conv2(random_filter(0.0, 9.0f32.powi(0))))
        .chain(Map2Static(Logistic))
        .chain(Conv2(random_filter(0.0, 9.0f32.powi(1))))
        .chain(Map2Static(Logistic))
        .chain(Conv2(random_filter(8.0, 9.0f32.powi(2))));
    let mut learn_rate = opt.initial_learning_rate;
    for i in 0..opt.epochs {
        let (internal, output) = train_filter.forward(&image);
        if i % opt.show_every == 0 {
            save_image(opt.output_dir.join(format!("epoch{:04}.png", i)), &output)?;
        }
        let loss = (output.clone() - expected.view()).map(|n| n.powi(2)).sum();
        eprintln!("epoch {:04} loss: {}, learn_rate: {}", i, loss, learn_rate);
        // The loss function is (n - t)^2, so 2*(n - t) is dE/df where
        // `E` is loss and `f` is output.
        let delta_loss = (output - expected).map(|n| 2.0 * n);
        let output_delta = -learn_rate * delta_loss;
        train_filter.propogate(&image, &internal, &output_delta);
        learn_rate *= opt.learning_rate_multiplier;
    }
    Ok(())
}
<|endoftext|>