<commit_before>extern crate clock_ticks;
extern crate rand;
extern crate sdl2;

use rand::distributions::{IndependentSample, Range};

use sdl2::event::Event;
use sdl2::keyboard::Keycode;
use sdl2::keyboard::Scancode;
use sdl2::rect::Rect;
use sdl2::render::Renderer;
use sdl2::Sdl;
use sdl2::TimerSubsystem;
use sdl2::VideoSubsystem;

use std::default::Default;
use std::f32;
use std::path::Path;
use std::thread;

pub struct Ui {
    width: f32,
    height: f32,
    sdl_ctx: Sdl,
    renderer: Renderer<'static>
}

impl Ui {
    pub fn new(width: f32, height: f32, sdl_ctx: Sdl, renderer: Renderer<'static>) -> Self {
        Ui {
            width: width,
            height: height,
            sdl_ctx: sdl_ctx,
            renderer: renderer
        }
    }

    pub fn poll_event(&self) -> Option<Event> {
        let mut event_pump = self.sdl_ctx.event_pump().unwrap();
        return event_pump.poll_event();
    }
}

pub struct Ball {
    pub x: f32,         // x pixel co-ordinate of top left corner
    pub y: f32,         // y pixel co-ordinate of top left corner
    pub width: f32,     // pixels
    pub height: f32,    // pixels
    pub speed: f32,     // pixels per second
    pub vx: f32,        // pixels per second
    pub vy: f32         // pixels per second
}

impl Ball {
    pub fn new(x: f32, y: f32, width: f32, height: f32,
               speed: f32, vx: f32, vy: f32) -> Self {
        Ball {
            x: x,
            y: y,
            width: width,
            height: height,
            speed: speed,
            vx: vx,
            vy: vy
        }
    }
}

pub struct Paddle {
    pub x: f32,         // x pixel co-ordinate of top left corner
    pub y: f32,         // y pixel co-ordinate of top left corner
    pub width: f32,     // pixels
    pub height: f32,    // pixels
    pub speed: f32,     // pixels per second
    pub vy: f32,        // pixels per second
    pub score: u32
}

impl Paddle {
    pub fn new(x: f32, y: f32, width: f32, height: f32, speed: f32, vy: f32,
               score: u32) -> Self {
        Paddle {
            x: x,
            y: y,
            width: width,
            height: height,
            speed: speed,
            vy: vy,
            score: score}
    }
}

pub struct Game {
    ui: Ui,
    fps: u32,
    ball: Ball,
    lpaddle: Paddle,
    rpaddle: Paddle,
    running: bool
}

impl Game {

    /// Create initial game state.
    pub fn new(ui: Ui, fps: u32, ball: Ball, lpaddle: Paddle,
               rpaddle: Paddle) -> Self {
        Game {
            ui: ui,
            fps: fps,
            ball: ball,
            lpaddle: lpaddle,
            rpaddle: rpaddle,
            running: false,
        }
    }

    /// Start the game and block until finished.
    pub fn start(&mut self) {
        self.running = true;
        let mut time_last_invocation = clock_ticks::precise_time_ms();
        while self.running {
            let time_this_invocation = clock_ticks::precise_time_ms();
            let delta_time = time_this_invocation - time_last_invocation;
            self.update(delta_time as f32 / 1000.);
            self.cap_fps(delta_time);
            time_last_invocation = time_this_invocation;
        }
    }

    /// Called once per frame.
    fn update(&mut self, dt_sec: f32) {
        self.handle_input(dt_sec);
        self.update_ball_position(dt_sec);
        self.check_for_ball_and_wall_collisions();
        self.check_for_ball_and_lpaddle_collision();
        self.redraw()
    }

    fn handle_input(&mut self, dt_sec: f32) {
        match self.ui.poll_event() {
            Some(event) => {
                match event {
                    Event::Quit{..} => {
                        self.running = false;
                    },
                    Event::KeyDown{keycode,..} => match keycode {
                        Option::Some(Keycode::Escape) => {
                            self.running = false;
                        },
                        Option::Some(Keycode::Up) => {
                            let lpaddle = &mut self.lpaddle;
                            lpaddle.y -= lpaddle.speed * dt_sec;
                            if lpaddle.y < 0. { lpaddle.y = 0.; }
                        },
                        Option::Some(Keycode::Down) => {
                            let lpaddle = &mut self.lpaddle;
                            lpaddle.y += lpaddle.speed * dt_sec;
                            if lpaddle.y + lpaddle.height > self.ui.height {
                                lpaddle.y = self.ui.height - lpaddle.height;
                            }
                        },
                        _ => {}
                    },
                    _ => {}
                }
            },
            None => {}
        }
    }

    fn update_ball_position(&mut self, dt_sec: f32) {
        let ball = &mut self.ball;
        ball.x += ball.vx * dt_sec;
        ball.y += ball.vy * dt_sec;
    }

    fn check_for_ball_and_wall_collisions(&mut self) {
        let ball = &mut self.ball;
        let ui = &mut self.ui;

        // Left or right wall.
        if ball.x <= 0. && ball.vx < -0. {
            ball.x = 0.;
            ball.vx = -ball.vx;
        } else if ball.x + ball.width >= ui.width && ball.vx > 0. {
            ball.x = ui.width - ball.width;
            ball.vx = -ball.vx;
        }

        // Top or bottom wall.
        if ball.y <= 0. && ball.vy < -0. {
            ball.y = 0.;
            ball.vy = -ball.vy;
        } else if ball.y + ball.height >= ui.height && ball.vy > 0. {
            ball.y = ui.height - ball.height;
            ball.vy = -ball.vy;
        }
    }

    fn check_for_ball_and_lpaddle_collision(&mut self) {
        let ball = &mut self.ball;
        let lpaddle = &mut self.lpaddle;

        if ball.vx < 0. && ball.x <= lpaddle.width &&
            ball.y >= lpaddle.y && ball.y <= lpaddle.y + lpaddle.height {

            // Calculate the ball's position relative to the center of the paddle.
            let hit_loc = ball.y - lpaddle.y;

            // Calculate an angle multiplier as a percentage of half the paddle's height.
            let angle_multiplier = (hit_loc / (lpaddle.height / 2.)).abs();

            // Calculate the angle the ball should return at.
            let angle = (f32::consts::PI / 6.) * angle_multiplier;

            // Calculate new vertical and horizontal velocities.
            let vx = angle.cos() * ball.speed;
            let vy = angle.sin() * ball.speed * if hit_loc > 0. {1.} else {-1.};

            ball.x = ball.width;
            ball.vx = vx;
            ball.vy = vy;
        }
    }

    fn redraw(&mut self) {
        // Clear the screen.
        self.ui.renderer.clear();

        // Draw the ball.
        let ball = &mut self.ball;
        let ball_rect = Rect::new_unwrap(ball.x as i32,
                                    ball.y as i32,
                                    ball.width as u32,
                                    ball.height as u32);
        self.ui.renderer.fill_rect(ball_rect);

        // Draw the left paddle.
        let lpaddle = &mut self.lpaddle;
        let lpaddle_rect = Rect::new_unwrap(lpaddle.x as i32,
                                    lpaddle.y as i32,
                                    lpaddle.width as u32,
                                    lpaddle.height as u32);
        self.ui.renderer.fill_rect(lpaddle_rect);

        // Draw the right paddle.
        let rpaddle = &mut self.rpaddle;
        let rpaddle_rect = Rect::new_unwrap(rpaddle.x as i32,
                                    rpaddle.y as i32,
                                    rpaddle.width as u32,
                                    rpaddle.height as u32);
        self.ui.renderer.fill_rect(rpaddle_rect);

        // Flip backbuffer to front.
        self.ui.renderer.present();
    }

    // Ensure we run no faster than the desired fps by introducing
    // a delay if necessary.
    fn cap_fps(&self, took_ms: u64) {
        let max_ms = 1000 / self.fps as u64;
        if max_ms > took_ms {
            thread::sleep_ms((max_ms - took_ms) as u32);
        }
    }
}

struct GameBuilder {
    screen_width: f32,
    screen_height: f32,
    fps: u32,
    ball_speed: f32,
    paddle_speed: f32
}

impl GameBuilder {

    pub fn new() -> Self {
        GameBuilder {
            screen_width: 480.,
            screen_height: 320.,
            fps: 40,
            ball_speed: 320.,
            paddle_speed: 640.
        }
    }

    pub fn with_dimensions(mut self, width: f32, height: f32) -> Self {
        self.screen_width = width;
        self.screen_height = height;
        self
    }

    pub fn with_fps(mut self, fps: u32) -> Self {
        self.fps = fps;
        self
    }

    pub fn with_ball_speed_per_sec(mut self, ball_speed: f32) -> Self {
        self.ball_speed = ball_speed;
        self
    }

    pub fn with_paddle_speed_per_sec(mut self, paddle_speed: f32) -> Self {
        self.paddle_speed = paddle_speed;
        self
    }

    fn create_ui(&self) -> Ui {
        let sdl_ctx = sdl2::init().unwrap();
        let video_subsystem = sdl_ctx.video().unwrap();
        let window = video_subsystem.window("pong",
                self.screen_width as u32, self.screen_height as u32)
                .position_centered()
                .build()
                .unwrap();
        let renderer = window.renderer().build().unwrap();
        Ui::new(self.screen_width, self.screen_height, sdl_ctx, renderer)
    }

    fn create_ball(&self) -> Ball {
        let width = 10.;
        let height = 10.;

        // Place ball at center of screen.
        let x = (self.screen_width - width) / 2.;
        let y = (self.screen_height - height) / 2.;

        let speed = self.ball_speed;
        let mut rng = rand::thread_rng();

        // Launch at an angle less than or equal to 45 degrees.
        let angle = Range::new(0., f32::consts::PI/4.).ind_sample(&mut rng);
        let dir = [-1., 1.];

        // Use the sine of the angle to determine the vertical speed. Then,
        // choose a direction (up or down) to select a vertical velocity.
        let up_or_down = rand::sample(&mut rng, dir.into_iter(),1)[0];
        let vy = angle.sin() * speed * up_or_down;
        let left_or_right = rand::sample(&mut rng, dir.into_iter(),1)[0];

        // Use Pythagoras to determine the horizontal speed. Then, choose a
        // direction (left or right) to select a horizontal velocity.
        let vx = ((speed * speed) - (vy * vy)).sqrt() * left_or_right;
        Ball::new(x, y, width, height, speed, vx, vy)
    }

    fn create_left_paddle(&self) -> Paddle {
        let width = 10.;
        let height = 60.;
        let x = 0.;
        let y = (self.screen_height - height) / 2.;
        let vy = 0.;
        let score = 0;
        Paddle::new(x, y, width, height, self.paddle_speed, vy, score)
    }

    fn create_right_paddle(&self) -> Paddle {
        let width = 10.;
        let height = 60.;
        let x = self.screen_width - width;;
        let y = (self.screen_height - height) / 2.;
        let vy = 0.;
        let score = 0;
        Paddle::new(x, y, width, height, self.paddle_speed, vy, score)
    }

    pub fn build(&self) -> Game {
        Game::new(self.create_ui(),
                  self.fps,
                  self.create_ball(),
                  self.create_left_paddle(),
                  self.create_right_paddle())
    }
}

fn main() {
    let mut game = GameBuilder::new()
        .with_dimensions(480., 320.)
        .with_fps(40)
        .with_ball_speed_per_sec(320.)
        .with_paddle_speed_per_sec(1000.)
        .build();
    game.start();
}
<commit_msg>In the process of rewriting the logic for moving the ball.<commit_after>extern crate clock_ticks;
extern crate rand;
extern crate sdl2;

use rand::distributions::{IndependentSample, Range};

use sdl2::event::Event;
use sdl2::keyboard::Keycode;
use sdl2::keyboard::Scancode;
use sdl2::rect::Rect;
use sdl2::render::Renderer;
use sdl2::Sdl;
use sdl2::TimerSubsystem;
use sdl2::VideoSubsystem;

use std::default::Default;
use std::f32;
use std::path::Path;
use std::thread;

pub struct Ui {
    width: f32,
    height: f32,
    sdl_ctx: Sdl,
    renderer: Renderer<'static>
}

impl Ui {
    pub fn new(width: f32, height: f32, sdl_ctx: Sdl,
               renderer: Renderer<'static>) -> Self {
        Ui {
            width: width,
            height: height,
            sdl_ctx: sdl_ctx,
            renderer: renderer
        }
    }

    pub fn poll_event(&self) -> Option<Event> {
        let mut event_pump = self.sdl_ctx.event_pump().unwrap();
        return event_pump.poll_event();
    }
}

pub struct Ball {
    pub x: f32,         // x pixel co-ordinate of top left corner
    pub y: f32,         // y pixel co-ordinate of top left corner
    pub diameter: f32,
    pub speed: f32,     // pixels per second
    pub vx: f32,        // pixels per second
    pub vy: f32         // pixels per second
}

impl Ball {
    pub fn new(x: f32, y: f32, diameter: f32,
               speed: f32, vx: f32, vy: f32) -> Self {
        Ball {
            x: x,
            y: y,
            diameter: diameter,
            speed: speed,
            vx: vx,
            vy: vy
        }
    }
}

pub struct Paddle {
    pub x: f32,         // x pixel co-ordinate of top left corner
    pub y: f32,         // y pixel co-ordinate of top left corner
    pub width: f32,
    pub height: f32,
    pub speed: f32,     // pixels per second
    pub vy: f32,        // pixels per second
    pub score: u32
}

impl Paddle {
    pub fn new(x: f32, y: f32, width: f32, height: f32, speed: f32, vy: f32,
               score: u32) -> Self {
        Paddle {
            x: x,
            y: y,
            width: width,
            height: height,
            speed: speed,
            vy: vy,
            score: score}
    }
}

pub struct Game {
    ui: Ui,
    fps: u32,
    ball: Ball,
    lpaddle: Paddle,
    rpaddle: Paddle,
    running: bool
}

impl Game {

    /// Create initial game state.
    pub fn new(ui: Ui, fps: u32, ball: Ball, lpaddle: Paddle,
               rpaddle: Paddle) -> Self {
        Game {
            ui: ui,
            fps: fps,
            ball: ball,
            lpaddle: lpaddle,
            rpaddle: rpaddle,
            running: false,
        }
    }

    /// Start the game and block until finished.
    pub fn start(&mut self) {
        self.running = true;
        let mut time_last_invocation = clock_ticks::precise_time_ms();
        while self.running {
            let time_this_invocation = clock_ticks::precise_time_ms();
            let delta_time = time_this_invocation - time_last_invocation;
            self.update(delta_time as f32 / 1000.);
            self.cap_fps(delta_time);
            time_last_invocation = time_this_invocation;
        }
    }

    // Called once per frame.
    fn update(&mut self, dt_sec: f32) {
        self.handle_input(dt_sec);
        self.update_ball_position(dt_sec);
        self.redraw()
    }

    // Handle user input including moving the left paddle.
    fn handle_input(&mut self, dt_sec: f32) {
        match self.ui.poll_event() {
            Some(event) => {
                match event {
                    Event::Quit{..} => {
                        self.running = false;
                    },
                    Event::KeyDown{keycode,..} => match keycode {
                        Option::Some(Keycode::Escape) => {
                            self.running = false;
                        },
                        Option::Some(Keycode::Up) => {
                            let lpaddle = &mut self.lpaddle;
                            lpaddle.y -= lpaddle.speed * dt_sec;
                            if lpaddle.y < 0. { lpaddle.y = 0.; }
                        },
                        Option::Some(Keycode::Down) => {
                            let lpaddle = &mut self.lpaddle;
                            lpaddle.y += lpaddle.speed * dt_sec;
                            if lpaddle.y + lpaddle.height > self.ui.height {
                                lpaddle.y = self.ui.height - lpaddle.height;
                            }
                        },
                        _ => {}
                    },
                    _ => {}
                }
            },
            None => {}
        }
    }

    // Update the position of the ball and deal with wall and paddle collisions.
    fn update_ball_position(&mut self, dt_sec: f32) {
        let ui = &mut self.ui;
        let ball = &mut self.ball;

        let new_ball_x = ball.x + ball.vx * dt_sec;
        let mut new_ball_y = ball.y + ball.vy * dt_sec;

        if new_ball_y < 0. {
            new_ball_y = -new_ball_y;
            ball.vy = -ball.vy;
        } else if (new_ball_y + ball.diameter > (ui.height - 1.)) {
            new_ball_y -= 2. * ((new_ball_y + ball.diameter) - (ui.height - 1.));
        }

        ball.x = new_ball_x;
        ball.y = new_ball_y;
    }

    fn check_for_ball_and_wall_collisions(&mut self) {
        let ball = &mut self.ball;
        let ui = &mut self.ui;

        // Left or right wall.
        if ball.x <= 0. && ball.vx < -0. {
            ball.x = 0.;
            ball.vx = -ball.vx;
        } else if ball.x + ball.diameter >= ui.width && ball.vx > 0. {
            ball.x = ui.width - ball.diameter;
            ball.vx = -ball.vx;
        }

        // Top or bottom wall.
        if ball.y <= 0. && ball.vy < -0. {
            ball.y = 0.;
            ball.vy = -ball.vy;
        } else if ball.y + ball.diameter >= ui.height && ball.vy > 0. {
            ball.y = ui.height - ball.diameter;
            ball.vy = -ball.vy;
        }
    }

    fn check_for_ball_and_lpaddle_collision(&mut self) {
        let ball = &mut self.ball;
        let lpaddle = &mut self.lpaddle;

        //if ball.vx < 0. && ball.x < lpaddle.width && ball.x >= 0 {
        //
        //    let x_intersect = lpaddle.width;
        //    let y_intersect = ball.y - (ball.x - lpaddle.width) *

        //    // Calculate the ball's position relative to the center of the paddle.
        //    let relative_hit_loc = lpaddle.y + (lpaddle.height/2.) - (ball.y + ball.height/2.);
        //
        //    let normalized_hit_loc = relative_hit_loc / (lpaddle.height/2.);
        //
        //    // Calculate an angle multiplier as a percentage of half the paddle's height.
        //    let angle_multiplier = normalized_hit_loc / (lpaddle.height/2.);

        //    // Set the maximum bounce angle to 75 degrees.
        //    let max_angle = f32::consts::PI * 5./12.;

        //    // Calculate the angle the ball should return at.
        //    let angle = max_angle * angle_multiplier;

        //    // Calculate new vertical and horizontal velocities.
        //    let vx = angle.cos() * ball.speed;
        //    let vy = angle.sin() * -ball.speed;
        //
        //    ball.x = lpaddle.width;
        //    ball.vx = vx;
        //    ball.vy = vy;
        //}
    }

    fn redraw(&mut self) {

        // Clear the screen.
        self.ui.renderer.clear();

        // Draw the ball.
        let ball = &mut self.ball;
        let ball_rect = Rect::new_unwrap(ball.x as i32,
                                    ball.y as i32,
                                    ball.diameter as u32,
                                    ball.diameter as u32);
        self.ui.renderer.fill_rect(ball_rect);

        // Draw the left paddle.
        let lpaddle = &mut self.lpaddle;
        let lpaddle_rect = Rect::new_unwrap(lpaddle.x as i32,
                                    lpaddle.y as i32,
                                    lpaddle.width as u32,
                                    lpaddle.height as u32);
        self.ui.renderer.fill_rect(lpaddle_rect);

        // Draw the right paddle.
        let rpaddle = &mut self.rpaddle;
        let rpaddle_rect = Rect::new_unwrap(rpaddle.x as i32,
                                    rpaddle.y as i32,
                                    rpaddle.width as u32,
                                    rpaddle.height as u32);
        self.ui.renderer.fill_rect(rpaddle_rect);

        // Flip backbuffer to front.
        self.ui.renderer.present();
    }

    // Ensure we run no faster than the desired fps by introducing
    // a delay if necessary.
    fn cap_fps(&self, took_ms: u64) {
        let max_ms = 1000 / self.fps as u64;
        if max_ms > took_ms {
            thread::sleep_ms((max_ms - took_ms) as u32);
        }
    }
}

struct GameBuilder {
    screen_width: f32,
    screen_height: f32,
    fps: u32,
    ball_speed: f32,
    ball_diameter: f32,
    paddle_offset: f32,
    paddle_width: f32,
    paddle_height: f32,
    paddle_speed: f32,
    max_bounce_angle: f32
}

impl GameBuilder {

    pub fn new() -> Self {
        GameBuilder {
            screen_width: 480.,
            screen_height: 320.,
            fps: 40,
            ball_speed: 320.,
            ball_diameter: 10.,
            paddle_offset: 4.,
            paddle_width: 10.,
            paddle_height: 80.,
            paddle_speed: 640.,
            max_bounce_angle: f32::consts::PI/12.
        }
    }

    pub fn with_dimensions(mut self, width: f32, height: f32) -> Self {
        self.screen_width = width;
        self.screen_height = height;
        self
    }

    pub fn with_fps(mut self, fps: u32) -> Self {
        self.fps = fps;
        self
    }

    pub fn with_ball_speed_per_sec(mut self, ball_speed: f32) -> Self {
        self.ball_speed = ball_speed;
        self
    }

    pub fn with_ball_diameter(mut self, ball_diameter: f32) -> Self {
        self.ball_diameter = ball_diameter;
        self
    }

    pub fn with_paddle_offset(mut self, paddle_offset: f32) -> Self {
        self.paddle_offset = paddle_offset;
        self
    }

    pub fn with_paddle_width(mut self, paddle_width: f32) -> Self {
        self.paddle_width = paddle_width;
        self
    }

    pub fn with_paddle_height(mut self, paddle_height: f32) -> Self {
        self.paddle_height = paddle_height;
        self
    }

    pub fn with_paddle_speed_per_sec(mut self, paddle_speed: f32) -> Self {
        self.paddle_speed = paddle_speed;
        self
    }

    pub fn with_max_bounce_angle_rads(mut self, max_bounce_angle: f32) -> Self {
        self.max_bounce_angle = max_bounce_angle;
        self
    }

    fn create_ui(&self) -> Ui {
        let sdl_ctx = sdl2::init().unwrap();
        let video_subsystem = sdl_ctx.video().unwrap();
        let window = video_subsystem.window("pong",
                self.screen_width as u32, self.screen_height as u32)
                .position_centered()
                .build()
                .unwrap();
        let renderer = window.renderer().build().unwrap();
        Ui::new(self.screen_width, self.screen_height, sdl_ctx, renderer)
    }

    fn create_ball(&self) -> Ball {

        // Place ball at center of screen.
        let diameter = self.ball_diameter;
        let x = (self.screen_width - diameter)/2.;
        let y = (self.screen_height - diameter)/2.;

        let speed = self.ball_speed;
        let mut rng = rand::thread_rng();

        // Launch at an angle less than or equal to 45 degrees.
        let angle = Range::new(0., self.max_bounce_angle).ind_sample(&mut rng);
        let dir = [-1., 1.];

        // Use the sine of the angle to determine the vertical speed. Then,
        // choose a direction (up or down) to select a vertical velocity.
        let up_or_down = rand::sample(&mut rng, dir.into_iter(),1)[0];
        let vy = angle.sin() * speed * up_or_down;
        let left_or_right = rand::sample(&mut rng, dir.into_iter(),1)[0];

        // Use Pythagoras to determine the horizontal speed. Then, choose a
        // direction (left or right) to select a horizontal velocity.
        let vx = ((speed * speed) - (vy * vy)).sqrt() * left_or_right;
        Ball::new(x, y, diameter, speed, vx, vy)
    }

    fn create_left_paddle(&self) -> Paddle {
        let width = self.paddle_width;
        let height = self.paddle_height;
        let x = self.paddle_offset;
        let y = (self.screen_height - height)/2.;
        let speed = self.paddle_speed;
        let vy = 0.;
        let score = 0;
        Paddle::new(x, y, width, height, speed, vy, score)
    }

    fn create_right_paddle(&self) -> Paddle {
        let width = self.paddle_width;
        let height = self.paddle_height;
        let x = self.screen_width - (self.paddle_offset + width);
        let y = (self.screen_height - height)/2.;
        let speed = self.paddle_speed;
        let vy = 0.;
        let score = 0;
        Paddle::new(x, y, width, height, speed, vy, score)
    }

    pub fn build(&self) -> Game {
        Game::new(self.create_ui(),
                  self.fps,
                  self.create_ball(),
                  self.create_left_paddle(),
                  self.create_right_paddle())
    }
}

fn main() {
    let mut game = GameBuilder::new()
        .with_dimensions(800., 600.)
        .with_fps(40)
        .with_ball_speed_per_sec(400.)
        .with_ball_diameter(10.)
        .with_paddle_offset(4.)
        .with_paddle_width(10.)
        .with_paddle_height(80.)
        .with_paddle_speed_per_sec(1000.)
        .with_max_bounce_angle_rads(f32::consts::PI/12.)
        .build();
    game.start();
}
<|endoftext|>


<commit_before>extern crate chrono;
extern crate iron;
extern crate persistent;
extern crate r2d2;
extern crate r2d2_sqlite;
extern crate router;
extern crate rusqlite;
extern crate rustc_serialize;
extern crate sha2;

use chrono::*;

use iron::prelude::*;
use iron::Url;
use iron::modifiers::Redirect;
use iron::status::Status;
use iron::typemap::Key;

use persistent::Read;

use r2d2::Pool;

use r2d2_sqlite::SqliteConnectionManager;

use router::Router;

use rusqlite::Connection;

use rustc_serialize::hex::ToHex;

use sha2::{Digest, Sha256};

use std::env;

const HOST: &'static str = "https://yaus.pw/";

pub type SqlitePool = Pool<SqliteConnectionManager>;

pub struct YausDb;
impl Key for YausDb {
    type Value = SqlitePool;
}

// A simple macro to return early if the URL can't parse.
macro_rules! try_url {
    ($url:expr) => {
        match Url::parse($url) {
            Ok(_) => { },
            Err(_) => {
                return Ok(Response::with((Status::BadRequest, "Malformed URL")));
            }
        }
    }
}

fn create_shortened_url(db: &Connection, long_url: &str) -> IronResult<Response> {
    let mut hash = Sha256::new();
    hash.input(long_url.as_bytes());
    let locator = hash.result().as_slice().to_hex();

    let timestamp = Local::now().to_rfc3339();
    db.execute("INSERT INTO urls VALUES (NULL, ?1, ?2, ?3)",
        &[&timestamp, &long_url, &&locator[0..7]]).unwrap();

    Ok(Response::with((Status::Created, [HOST, &locator[0..7]].join(""))))
}

/// Given a long URL, see if it already exists in the table, else create an entry and return
/// it.
///
/// A 200 means that a shortened URL already exists and has been returned. A 201
/// response means that a new shortened URL has been created.
fn check_or_shorten_url(db: &Connection, long_url: &str) -> IronResult<Response> {
    let mut stmt = db.prepare("SELECT locator FROM urls WHERE url = (?)").unwrap();
    let mut row = stmt.query_map::<String, _>(&[&long_url], |r| r.get(0)).unwrap();

    if let Some(l) = row.next() {
        return Ok(Response::with((Status::Ok, [HOST, &l.unwrap()].join(""))));
    }
    create_shortened_url(db, long_url)
}

/// The handler to shorten a URL.
fn shorten_handler(req: &mut Request) -> IronResult<Response> {
    match req.url.clone().query() {
        None => { Ok(Response::with((Status::BadRequest, "URL missing in query"))) },
        Some(s) => {
            let (k, v) = s.split_at(4);
            if k == "url=" {
                try_url!(v);
                let pool = req.get::<Read<YausDb>>().unwrap().clone();
                let db = pool.get().unwrap();
                check_or_shorten_url(&db, v)
            } else {
                Ok(Response::with((Status::BadRequest, "Malformed query string")))
            }
        }
    }
}

/// The handler that redirects to the long URL.
fn redirect_handler(req: &mut Request) -> IronResult<Response> {
    let pool = req.get::<Read<YausDb>>().unwrap().clone();
    let db = pool.get().unwrap();
    let locator = req.url.path()[0];
    let mut stmt = db.prepare("SELECT url FROM urls WHERE locator = (?)").unwrap();
    let mut row = stmt.query_map::<String, _>(&[&locator], |r| r.get(0)).unwrap();

    if let Some(u) = row.next() {
        let long_url = Url::parse(&u.unwrap()).unwrap();
        Ok(Response::with((Status::MovedPermanently, Redirect(long_url))))
    } else {
        Ok(Response::with((Status::NotFound, "Not found")))
    }
}

fn index_handler(_: &mut Request) -> IronResult<Response> {
    Ok(Response::with((Status::Ok, "See https://github.com/gsquire/yaus for the API")))
}

fn main() {
    let mut router = Router::new();
    router.get("/shorten", shorten_handler, "shorten");
    router.get("/:locator", redirect_handler, "locator");
    router.get("/", index_handler, "index");

    let config = r2d2::Config::default();
    let db = env::var("SHORT_DB").unwrap();
    let manager = SqliteConnectionManager::new(&db);
    let pool = r2d2::Pool::new(config, manager).unwrap();

    let mut chain = Chain::new(router);
    chain.link_before(Read::<YausDb>::one(pool));

    Iron::new(chain).http("localhost:9090").unwrap();
}
<commit_msg>change port back to 3000<commit_after>extern crate chrono;
extern crate iron;
extern crate persistent;
extern crate r2d2;
extern crate r2d2_sqlite;
extern crate router;
extern crate rusqlite;
extern crate rustc_serialize;
extern crate sha2;

use chrono::*;

use iron::prelude::*;
use iron::Url;
use iron::modifiers::Redirect;
use iron::status::Status;
use iron::typemap::Key;

use persistent::Read;

use r2d2::Pool;

use r2d2_sqlite::SqliteConnectionManager;

use router::Router;

use rusqlite::Connection;

use rustc_serialize::hex::ToHex;

use sha2::{Digest, Sha256};

use std::env;

const HOST: &'static str = "https://yaus.pw/";

pub type SqlitePool = Pool<SqliteConnectionManager>;

pub struct YausDb;
impl Key for YausDb {
    type Value = SqlitePool;
}

// A simple macro to return early if the URL can't parse.
macro_rules! try_url {
    ($url:expr) => {
        match Url::parse($url) {
            Ok(_) => { },
            Err(_) => {
                return Ok(Response::with((Status::BadRequest, "Malformed URL")));
            }
        }
    }
}

fn create_shortened_url(db: &Connection, long_url: &str) -> IronResult<Response> {
    let mut hash = Sha256::new();
    hash.input(long_url.as_bytes());
    let locator = hash.result().as_slice().to_hex();

    let timestamp = Local::now().to_rfc3339();
    db.execute("INSERT INTO urls VALUES (NULL, ?1, ?2, ?3)",
        &[&timestamp, &long_url, &&locator[0..7]]).unwrap();

    Ok(Response::with((Status::Created, [HOST, &locator[0..7]].join(""))))
}

/// Given a long URL, see if it already exists in the table, else create an entry and return
/// it.
///
/// A 200 means that a shortened URL already exists and has been returned. A 201
/// response means that a new shortened URL has been created.
fn check_or_shorten_url(db: &Connection, long_url: &str) -> IronResult<Response> {
    let mut stmt = db.prepare("SELECT locator FROM urls WHERE url = (?)").unwrap();
    let mut row = stmt.query_map::<String, _>(&[&long_url], |r| r.get(0)).unwrap();

    if let Some(l) = row.next() {
        return Ok(Response::with((Status::Ok, [HOST, &l.unwrap()].join(""))));
    }
    create_shortened_url(db, long_url)
}

/// The handler to shorten a URL.
fn shorten_handler(req: &mut Request) -> IronResult<Response> {
    match req.url.clone().query() {
        None => { Ok(Response::with((Status::BadRequest, "URL missing in query"))) },
        Some(s) => {
            let (k, v) = s.split_at(4);
            if k == "url=" {
                try_url!(v);
                let pool = req.get::<Read<YausDb>>().unwrap().clone();
                let db = pool.get().unwrap();
                check_or_shorten_url(&db, v)
            } else {
                Ok(Response::with((Status::BadRequest, "Malformed query string")))
            }
        }
    }
}

/// The handler that redirects to the long URL.
fn redirect_handler(req: &mut Request) -> IronResult<Response> {
    let pool = req.get::<Read<YausDb>>().unwrap().clone();
    let db = pool.get().unwrap();
    let locator = req.url.path()[0];
    let mut stmt = db.prepare("SELECT url FROM urls WHERE locator = (?)").unwrap();
    let mut row = stmt.query_map::<String, _>(&[&locator], |r| r.get(0)).unwrap();

    if let Some(u) = row.next() {
        let long_url = Url::parse(&u.unwrap()).unwrap();
        Ok(Response::with((Status::MovedPermanently, Redirect(long_url))))
    } else {
        Ok(Response::with((Status::NotFound, "Not found")))
    }
}

fn index_handler(_: &mut Request) -> IronResult<Response> {
    Ok(Response::with((Status::Ok, "See https://github.com/gsquire/yaus for the API")))
}

fn main() {
    let mut router = Router::new();
    router.get("/shorten", shorten_handler, "shorten");
    router.get("/:locator", redirect_handler, "locator");
    router.get("/", index_handler, "index");

    let config = r2d2::Config::default();
    let db = env::var("SHORT_DB").unwrap();
    let manager = SqliteConnectionManager::new(&db);
    let pool = r2d2::Pool::new(config, manager).unwrap();

    let mut chain = Chain::new(router);
    chain.link_before(Read::<YausDb>::one(pool));

    Iron::new(chain).http("localhost:3000").unwrap();
}
<|endoftext|>


<commit_before>
extern crate rand;
extern crate sdl2;

use std::env;
use std::fs;

pub mod machine;
pub mod opcode;
pub mod frontend;

use machine::Chip8;
use frontend::{SdlFrontend, Frontend};

fn main() {
    let path = env::args().nth(1).unwrap();

    let file = match fs::File::open(&path) {
        Ok(file) => file,
        Err(err) => {
            println!("Could not open {}: {:?}", path, err);
            return;
        }
    };

    let mut chip8 = Chip8::new();
    let mut sdl = SdlFrontend::new(sdl2::init().unwrap());

    match chip8.load_program(file) {
        Ok(_) => (),
        Err(err) => {
            println!("Could not load program: {:?}", err);
            return;
        }
    }

    sdl.emulate_loop(chip8);
}
<commit_msg>Improve main error handling<commit_after>
extern crate rand;
extern crate sdl2;

use std::env;
use std::fs;

pub mod machine;
pub mod opcode;
pub mod frontend;

use machine::Chip8;
use frontend::{SdlFrontend, Frontend};

fn main() {
    let path = env::args().nth(1).unwrap();

    let file = fs::File::open(&path).unwrap_or_else(|err| {
        panic!("Could not open program '{}': {}", path, err);
    });

    let mut chip8 = Chip8::new();
    let mut sdl = SdlFrontend::new(sdl2::init().unwrap());

    chip8.load_program(file).unwrap_or_else(|err| {
        panic!("Could not load program '{}': {}", path, err);
    });

    sdl.emulate_loop(chip8);
}
<|endoftext|>


<commit_before>extern crate piston;
extern crate graphics;
extern crate glutin_window;
extern crate opengl_graphics;
extern crate rand;

pub mod tetris;

use piston::window::{ AdvancedWindow, WindowSettings };
use glutin_window::GlutinWindow as Window;
use piston::event_loop::*;
use opengl_graphics::{ GlGraphics, OpenGL };
use opengl_graphics::glyph_cache::GlyphCache;
use graphics::{ Transformed };
use piston::input::*;

use std::path::Path;
use std::fs::OpenOptions;
use tetris::*;

struct App {
    gl: GlGraphics,
    tetris: Tetris,
    elapsed_time: f64,
    cache: GlyphCache<'static>,
}

//const WHITE: [f32; 4] = [1.0, 1.0, 1.0, 1.0];
const BLACK: [f32; 4] = [0.0, 0.0, 0.0, 1.0];
const LIGHT_GRAY: [f32; 4] = [0.3, 0.3, 0.3, 1.0];
const DARK_GRAY: [f32; 4] = [0.1, 0.1, 0.1, 1.0];
const GREEN: [f32; 4] = [0.0, 1.0, 0.0, 1.0];
const CYAN: [f32; 4] = [0.0, 1.0, 1.0, 1.0];
const RED: [f32; 4] = [1.0, 0.0, 0.0, 1.0];
const BLUE: [f32; 4] = [0.0, 0.0, 1.0, 1.0];
const ORANGE: [f32; 4] = [1.0, 0.5, 0.0, 1.0];
const YELLOW: [f32; 4] = [1.0, 1.0, 0.0, 1.0];
const PURPLE: [f32; 4] = [0.5, 0.0, 1.0, 1.0];

fn get_shape_color(shape_index: i32) -> [f32; 4] {
    match shape_index {
        0 => PURPLE,
        1 => YELLOW,
        2 => RED,
        3 => GREEN,
        4 => ORANGE,
        5 => BLUE,
        6 => CYAN,
        _ => {
            BLACK
        }
    }
}

const TEXT_FONT_SIZE: u32 = 22;
const CELL_SIZE: f64 = 30.0;
const LEFT_MARGIN: f64 = 20f64;
const TOP_MARGIN: f64 = 30f64;

const STATUS_LEFT_MARGIN: f64 = 400f64;
const STATUS_TOP_MARGIN: f64 = 100f64;
const LINE_HEIGHT: f64 = 40f64;
const STATUS_PREVIEW_GRID_HEIGHT: f64 = CELL_SIZE * 6f64;

struct Render;

impl Render {
    pub fn render_cell(c: &graphics::Context, gl: &mut GlGraphics, transform: [[f64; 3]; 2], color: [f32; 4]) {
        let square = graphics::rectangle::square(0f64, 0f64, CELL_SIZE - 1f64);
        let mut rectangle = graphics::Rectangle::new(color);
        rectangle.shape = graphics::rectangle::Shape::Round(4.0, 16);
        rectangle.draw(square, &c.draw_state, transform, gl);
    }

    pub fn render_next_shape(c: &graphics::Context, gl: &mut GlGraphics, tetris: &Tetris,
        transform: graphics::context::Context) -> graphics::context::Context {
        // render the next shape as a preview of what's coming next
        for point in tetris.get_next_shape().iter() {
            let color = get_shape_color(tetris.get_next_shape_index());
            // render the shape at col 2 and row 2
            let (x, y) = ((2 as i16 + point.x) as f64 * CELL_SIZE,
                (2 as i16 + point.y) as f64 * CELL_SIZE);
            Render::render_cell(&c, gl, transform.trans(x, y).transform, color);
        }
        transform.trans(0f64, STATUS_PREVIEW_GRID_HEIGHT)
    }

    pub fn render_game_over_section(c: &graphics::Context, gl: &mut GlGraphics, cache: &mut GlyphCache<'static>,
        tetris: &Tetris, transform: graphics::context::Context) -> graphics::context::Context {
        let mut result: graphics::context::Context = transform;
        let mut text = graphics::Text::new(TEXT_FONT_SIZE);
        text.color = ORANGE;
        text.draw(&"GAME OVER", cache, &c.draw_state, result.transform, gl);
        result = result.trans(0f64, LINE_HEIGHT);

        text.draw(&"Press 'N' for a new game", cache, &c.draw_state, result.transform, gl);
        result = result.trans(0f64, LINE_HEIGHT);

        text.draw(&"Use arrow keys to move and rotate", cache, &c.draw_state,
            result.transform, gl);
        result = result.trans(0f64, LINE_HEIGHT);

        text.draw(&"Press spacebar to drop", cache, &c.draw_state,
            result.transform, gl);
        result = result.trans(0f64, LINE_HEIGHT);

        text.draw(&format!("Press 'K' to decrease starting level ({})", tetris.get_starting_level()),
            cache, &c.draw_state, result.transform, gl);
        result = result.trans(0f64, LINE_HEIGHT);

        text.draw(&"Press 'L' to increase starting level",
            cache, &c.draw_state, result.transform, gl);
        result = result.trans(0f64, LINE_HEIGHT);
        result
    }

    // renders the game board cells e.g. the current shape, ghost shape, and all prior shapes that are
    // fixed in place
    pub fn render_game_board(c: &graphics::Context, gl: &mut GlGraphics, tetris: &Tetris) {
        for col in 0..COL_COUNT as i32 {
            for row in 0..ROW_COUNT as i32 {
                let cell = tetris.get_grid_cell(col, row);
                if cell.cell_type != GridCellType::Void {
                    let color = match cell.cell_type {
                        GridCellType::Shape => get_shape_color(cell.shape_index),
                        GridCellType::Fixed => get_shape_color(cell.shape_index),
                        GridCellType::Ghost => DARK_GRAY,
                        _ => {
                            assert!(false);
                            BLACK
                        }
                    };
                    let (x, y) = (col as f64 * CELL_SIZE, row as f64 * CELL_SIZE);
                    let transform = c.transform.trans(LEFT_MARGIN, TOP_MARGIN).trans(x, y);
                    Render::render_cell(&c, gl, transform, color);
                }
            }
        }
    }
}

impl App {
    fn render(&mut self, args: &RenderArgs) {
        // so that we can access inside closure
        let use_cache = &mut self.cache;
        let use_tetris = &self.tetris;

        self.gl.draw(args.viewport(), |c, gl| {
            // clear the viewport
            graphics::clear(BLACK, gl);

            // render the current score and level
            let mut text = graphics::Text::new(TEXT_FONT_SIZE);
            text.color = ORANGE;
            let mut transform: graphics::context::Context = c.trans(STATUS_LEFT_MARGIN, STATUS_TOP_MARGIN);
            text.draw(&format!("Level: {}", use_tetris.get_level()), use_cache, &c.draw_state,
                transform.transform, gl);
            transform = transform.trans(0f64, LINE_HEIGHT);

            text.draw(&format!("Score: {}", use_tetris.get_score()), use_cache, &c.draw_state,
                transform.transform, gl);
            transform = transform.trans(0f64, LINE_HEIGHT);

            transform = Render::render_next_shape(&c, gl, use_tetris, transform);

            // render GAME OVER text if necessary
            if use_tetris.get_game_over() {
                /*transform =*/ Render::render_game_over_section(&c, gl, use_cache, use_tetris, transform);
            }

            // draw a white border around the game board
            let rect_border = graphics::Rectangle::new_border(LIGHT_GRAY, 1.5);
            rect_border.draw([
                LEFT_MARGIN - 2f64,
                TOP_MARGIN - 2f64,
                (CELL_SIZE * COL_COUNT as f64) + 3f64,
                (CELL_SIZE * ROW_COUNT as f64) + 3f64,
            ], &c.draw_state, c.transform, gl);

            Render::render_game_board(&c, gl, use_tetris);
        });
    }

    fn update(&mut self, args: &UpdateArgs) {
        if self.tetris.get_game_over() {
            self.elapsed_time = 0.0;
        } else {
            // Here we increment the time elapsed between update()'s
            self.elapsed_time += args.dt;
            // if the elapsed time is now greater than the time allotted between ticks, then invoke tetris.tick()
            if self.elapsed_time > self.tetris.get_tick_time() as f64 {
                self.elapsed_time = 0.0;
                self.tetris.tick();
            }
        }
    }

    fn handle_key_input(&mut self, key: keyboard::Key) {
        match key {
            Key::Left => {
                let col: i32 = self.tetris.get_col();
                self.tetris.set_col(col - 1);
            },

            Key::Right => {
                let col: i32 = self.tetris.get_col();
                self.tetris.set_col(col + 1);
            },

            Key::Up => {
                self.tetris.rotate(true);
            },

            Key::Down => {
                let row: i32 = self.tetris.get_row() + 1;
                self.tetris.set_row(row);
            },

            Key::Space => {
                let mut row: i32 = self.tetris.get_row() + 1;
                while self.tetris.set_row(row) {
                    row += 1;
                }
                // hard drop immediately spawns next shape
                self.tetris.tick();
                self.elapsed_time = 0.0;
            },

            Key::N => {
                self.tetris.start_game();
            },

            Key::K => {
                if self.tetris.get_starting_level() > 0 {
                    let new_level: u32 = self.tetris.get_starting_level() - 1;
                    self.tetris.set_starting_level(new_level);
                }
            },

            Key::L => {
                if self.tetris.get_starting_level() < 30 {
                    let new_level: u32 = self.tetris.get_starting_level() + 1;
                    self.tetris.set_starting_level(new_level);
                }
            },

            _ => { }
        }
    }
}

fn main() {
    start_app();
}

fn start_app() {
    let opengl = OpenGL::V2_1;

    let mut window: Window = WindowSettings::new("Piston Tetris", [1024, 768]).
        exit_on_esc(true).
        opengl(opengl).
        build().
        unwrap();

    let font_path = match OpenOptions::new().open("FiraMono-Bold.ttf") {
        Ok(_) => Path::new("FiraMono-Bold.ttf"),
        Err(_) => {
            match OpenOptions::new().open("src/FiraMono-Bold.ttf") {
                Ok(_) => Path::new("src/FiraMono-Bold.ttf"),
                Err(_) => panic!("Font file is missing, or does not exist in the current path."),
            }
        }
    };

    let mut app = App {
        gl: GlGraphics::new(opengl),
        tetris: Tetris::new(),
        elapsed_time: 0.0,
        cache: GlyphCache::new(font_path).unwrap(),
    };

    let mut events = window.events();
    while let Some(e) = events.next(&mut window) {
        if let Some(Button::Keyboard(key)) = e.press_args() {
            app.handle_key_input(key);
        };

        if let Some(args) = e.render_args() {
            app.render(&args);
        };

        e.update(|args| { app.update(&args); });
    }
}<commit_msg>bug with OpenOptions opening font file<commit_after>extern crate piston;
extern crate graphics;
extern crate glutin_window;
extern crate opengl_graphics;
extern crate rand;

pub mod tetris;

use piston::window::{ AdvancedWindow, WindowSettings };
use glutin_window::GlutinWindow as Window;
use piston::event_loop::*;
use opengl_graphics::{ GlGraphics, OpenGL };
use opengl_graphics::glyph_cache::GlyphCache;
use graphics::{ Transformed };
use piston::input::*;

use std::path::Path;
use std::fs::OpenOptions;
use tetris::*;

struct App {
    gl: GlGraphics,
    tetris: Tetris,
    elapsed_time: f64,
    cache: GlyphCache<'static>,
}

//const WHITE: [f32; 4] = [1.0, 1.0, 1.0, 1.0];
const BLACK: [f32; 4] = [0.0, 0.0, 0.0, 1.0];
const LIGHT_GRAY: [f32; 4] = [0.3, 0.3, 0.3, 1.0];
const DARK_GRAY: [f32; 4] = [0.1, 0.1, 0.1, 1.0];
const GREEN: [f32; 4] = [0.0, 1.0, 0.0, 1.0];
const CYAN: [f32; 4] = [0.0, 1.0, 1.0, 1.0];
const RED: [f32; 4] = [1.0, 0.0, 0.0, 1.0];
const BLUE: [f32; 4] = [0.0, 0.0, 1.0, 1.0];
const ORANGE: [f32; 4] = [1.0, 0.5, 0.0, 1.0];
const YELLOW: [f32; 4] = [1.0, 1.0, 0.0, 1.0];
const PURPLE: [f32; 4] = [0.5, 0.0, 1.0, 1.0];

fn get_shape_color(shape_index: i32) -> [f32; 4] {
    match shape_index {
        0 => PURPLE,
        1 => YELLOW,
        2 => RED,
        3 => GREEN,
        4 => ORANGE,
        5 => BLUE,
        6 => CYAN,
        _ => {
            BLACK
        }
    }
}

const TEXT_FONT_SIZE: u32 = 22;
const CELL_SIZE: f64 = 30.0;
const LEFT_MARGIN: f64 = 20f64;
const TOP_MARGIN: f64 = 30f64;

const STATUS_LEFT_MARGIN: f64 = 400f64;
const STATUS_TOP_MARGIN: f64 = 100f64;
const LINE_HEIGHT: f64 = 40f64;
const STATUS_PREVIEW_GRID_HEIGHT: f64 = CELL_SIZE * 6f64;

struct Render;

impl Render {
    pub fn render_cell(c: &graphics::Context, gl: &mut GlGraphics, transform: [[f64; 3]; 2], color: [f32; 4]) {
        let square = graphics::rectangle::square(0f64, 0f64, CELL_SIZE - 1f64);
        let mut rectangle = graphics::Rectangle::new(color);
        rectangle.shape = graphics::rectangle::Shape::Round(4.0, 16);
        rectangle.draw(square, &c.draw_state, transform, gl);
    }

    pub fn render_next_shape(c: &graphics::Context, gl: &mut GlGraphics, tetris: &Tetris,
        transform: graphics::context::Context) -> graphics::context::Context {
        // render the next shape as a preview of what's coming next
        for point in tetris.get_next_shape().iter() {
            let color = get_shape_color(tetris.get_next_shape_index());
            // render the shape at col 2 and row 2
            let (x, y) = ((2 as i16 + point.x) as f64 * CELL_SIZE,
                (2 as i16 + point.y) as f64 * CELL_SIZE);
            Render::render_cell(&c, gl, transform.trans(x, y).transform, color);
        }
        transform.trans(0f64, STATUS_PREVIEW_GRID_HEIGHT)
    }

    pub fn render_game_over_section(c: &graphics::Context, gl: &mut GlGraphics, cache: &mut GlyphCache<'static>,
        tetris: &Tetris, transform: graphics::context::Context) -> graphics::context::Context {
        let mut result: graphics::context::Context = transform;
        let mut text = graphics::Text::new(TEXT_FONT_SIZE);
        text.color = ORANGE;
        text.draw(&"GAME OVER", cache, &c.draw_state, result.transform, gl);
        result = result.trans(0f64, LINE_HEIGHT);

        text.draw(&"Press 'N' for a new game", cache, &c.draw_state, result.transform, gl);
        result = result.trans(0f64, LINE_HEIGHT);

        text.draw(&"Use arrow keys to move and rotate", cache, &c.draw_state,
            result.transform, gl);
        result = result.trans(0f64, LINE_HEIGHT);

        text.draw(&"Press spacebar to drop", cache, &c.draw_state,
            result.transform, gl);
        result = result.trans(0f64, LINE_HEIGHT);

        text.draw(&format!("Press 'K' to decrease starting level ({})", tetris.get_starting_level()),
            cache, &c.draw_state, result.transform, gl);
        result = result.trans(0f64, LINE_HEIGHT);

        text.draw(&"Press 'L' to increase starting level",
            cache, &c.draw_state, result.transform, gl);
        result = result.trans(0f64, LINE_HEIGHT);
        result
    }

    // renders the game board cells e.g. the current shape, ghost shape, and all prior shapes that are
    // fixed in place
    pub fn render_game_board(c: &graphics::Context, gl: &mut GlGraphics, tetris: &Tetris) {
        for col in 0..COL_COUNT as i32 {
            for row in 0..ROW_COUNT as i32 {
                let cell = tetris.get_grid_cell(col, row);
                if cell.cell_type != GridCellType::Void {
                    let color = match cell.cell_type {
                        GridCellType::Shape => get_shape_color(cell.shape_index),
                        GridCellType::Fixed => get_shape_color(cell.shape_index),
                        GridCellType::Ghost => DARK_GRAY,
                        _ => {
                            assert!(false);
                            BLACK
                        }
                    };
                    let (x, y) = (col as f64 * CELL_SIZE, row as f64 * CELL_SIZE);
                    let transform = c.transform.trans(LEFT_MARGIN, TOP_MARGIN).trans(x, y);
                    Render::render_cell(&c, gl, transform, color);
                }
            }
        }
    }
}

impl App {
    fn render(&mut self, args: &RenderArgs) {
        // so that we can access inside closure
        let use_cache = &mut self.cache;
        let use_tetris = &self.tetris;

        self.gl.draw(args.viewport(), |c, gl| {
            // clear the viewport
            graphics::clear(BLACK, gl);

            // render the current score and level
            let mut text = graphics::Text::new(TEXT_FONT_SIZE);
            text.color = ORANGE;
            let mut transform: graphics::context::Context = c.trans(STATUS_LEFT_MARGIN, STATUS_TOP_MARGIN);
            text.draw(&format!("Level: {}", use_tetris.get_level()), use_cache, &c.draw_state,
                transform.transform, gl);
            transform = transform.trans(0f64, LINE_HEIGHT);

            text.draw(&format!("Score: {}", use_tetris.get_score()), use_cache, &c.draw_state,
                transform.transform, gl);
            transform = transform.trans(0f64, LINE_HEIGHT);

            transform = Render::render_next_shape(&c, gl, use_tetris, transform);

            // render GAME OVER text if necessary
            if use_tetris.get_game_over() {
                /*transform =*/ Render::render_game_over_section(&c, gl, use_cache, use_tetris, transform);
            }

            // draw a white border around the game board
            let rect_border = graphics::Rectangle::new_border(LIGHT_GRAY, 1.5);
            rect_border.draw([
                LEFT_MARGIN - 2f64,
                TOP_MARGIN - 2f64,
                (CELL_SIZE * COL_COUNT as f64) + 3f64,
                (CELL_SIZE * ROW_COUNT as f64) + 3f64,
            ], &c.draw_state, c.transform, gl);

            Render::render_game_board(&c, gl, use_tetris);
        });
    }

    fn update(&mut self, args: &UpdateArgs) {
        if self.tetris.get_game_over() {
            self.elapsed_time = 0.0;
        } else {
            // Here we increment the time elapsed between update()'s
            self.elapsed_time += args.dt;
            // if the elapsed time is now greater than the time allotted between ticks, then invoke tetris.tick()
            if self.elapsed_time > self.tetris.get_tick_time() as f64 {
                self.elapsed_time = 0.0;
                self.tetris.tick();
            }
        }
    }

    fn handle_key_input(&mut self, key: keyboard::Key) {
        match key {
            Key::Left => {
                let col: i32 = self.tetris.get_col();
                self.tetris.set_col(col - 1);
            },

            Key::Right => {
                let col: i32 = self.tetris.get_col();
                self.tetris.set_col(col + 1);
            },

            Key::Up => {
                self.tetris.rotate(true);
            },

            Key::Down => {
                let row: i32 = self.tetris.get_row() + 1;
                self.tetris.set_row(row);
            },

            Key::Space => {
                let mut row: i32 = self.tetris.get_row() + 1;
                while self.tetris.set_row(row) {
                    row += 1;
                }
                // hard drop immediately spawns next shape
                self.tetris.tick();
                self.elapsed_time = 0.0;
            },

            Key::N => {
                self.tetris.start_game();
            },

            Key::K => {
                if self.tetris.get_starting_level() > 0 {
                    let new_level: u32 = self.tetris.get_starting_level() - 1;
                    self.tetris.set_starting_level(new_level);
                }
            },

            Key::L => {
                if self.tetris.get_starting_level() < 30 {
                    let new_level: u32 = self.tetris.get_starting_level() + 1;
                    self.tetris.set_starting_level(new_level);
                }
            },

            _ => { }
        }
    }
}

fn main() {
    start_app();
}

fn start_app() {
    let opengl = OpenGL::V2_1;

    let mut window: Window = WindowSettings::new("Piston Tetris", [1024, 768]).
        exit_on_esc(true).
        opengl(opengl).
        build().
        unwrap();

    let font_path = match OpenOptions::new().read(true).open("FiraMono-Bold.ttf") {
        Ok(_) => Path::new("FiraMono-Bold.ttf"),
        Err(_) => {
            match OpenOptions::new().read(true).open("src/FiraMono-Bold.ttf") {
                Ok(_) => Path::new("src/FiraMono-Bold.ttf"),
                Err(_) => panic!("Font file is missing, or does not exist in the current path."),
            }
        }
    };

    let mut app = App {
        gl: GlGraphics::new(opengl),
        tetris: Tetris::new(),
        elapsed_time: 0.0,
        cache: GlyphCache::new(font_path).unwrap(),
    };

    let mut events = window.events();
    while let Some(e) = events.next(&mut window) {
        if let Some(Button::Keyboard(key)) = e.press_args() {
            app.handle_key_input(key);
        };

        if let Some(args) = e.render_args() {
            app.render(&args);
        };

        e.update(|args| { app.update(&args); });
    }
}<|endoftext|>


<commit_before>#[macro_use]
extern crate clap;
extern crate libc;
extern crate signal;

use clap::ArgMatches;
use std::time::Duration;
use world::World;

#[macro_use]
mod macros;
mod screen;
mod world;

const MAPS_MSG: &'static str = "\
MAPS:
    Maps must be rectangular. Whitespace is ignored.
    '·' is a dead cell. Anything else is a living cell.
";
const TICK_MS: u64 = 50;

fn main() {
    fn is_number(s: String) -> Result<(), String> {
        if s.chars().all(|c| c.is_digit(10)) { Ok(()) }
        else { Err(format!("expected a number, found \"{}\"", s)) }
    }

    let matches = clap_app!( rgol =>
        (about: "Conway's game of life for terminal in Rust")
        (author: crate_authors!())
        (version: crate_version!())
        (after_help: MAPS_MSG)
        (@setting SubcommandRequiredElseHelp)
        (@setting VersionlessSubcommands)
        (@subcommand genmap =>
            (about: "Prints an empty map")
            (after_help: MAPS_MSG)
            (@arg NROW: {is_number} * "Number of rows")
            (@arg NCOL: {is_number} * "Number of columns")
            (@arg space: -s --space "Adds spaces to the map"))
        (@subcommand play =>
            (about: "Plays the game (CTRL-c to exit)")
            (after_help: MAPS_MSG)
            (@arg FILE: * "File containing the map")
            (@arg TICK_MS: {is_number} "Elapsed time between iterations in ms")
        )
    ).get_matches();

    match matches.subcommand() {
        ("genmap", Some(args)) => genmap(args),
        ("play",   Some(args)) => play(args),
        _                      => unreachable!(),
    }
}

fn genmap(args: &ArgMatches) {
    use std::io::{Write, stdout};
    use std::iter::repeat;

    let nrow = args.value_of("NROW").expect("NROW has no value").parse().expect("NROW is not a number");
    let ncol = args.value_of("NCOL").expect("NCOL has no value").parse().expect("NCOL is not a number");
    if nrow == 0 || ncol == 0 { return }
    let line = if args.is_present("space") {
        let mut line: String = repeat("· ").take(ncol).collect();
        line.pop();
        line
    }
    else { repeat('·').take(ncol).collect() };
    for _ in 0..nrow { writeln!(&mut stdout(), "{}", line).unwrap(); }
}

fn play(args: &ArgMatches) {
    let filename = args.value_of("FILE").expect("FILE has no value");
    let tick_ms = args.value_of("TICK_MS").map_or(TICK_MS, |tms| tms.parse().expect("TICK_MS is not a number"));
    let tick = Duration::from_millis(tick_ms);
    match World::load(filename) {
        Ok(world) => play_world(world, tick),
        Err(err)  => eprintln!("error: {}", err),
    }
}

fn play_world(mut world: World, tick: Duration) {
    use screen::Screen;
    use std::time::Instant;
    use signal::trap::Trap;

    let sigtrap = Trap::trap(&[libc::SIGINT]);
    let screen = Screen::new();
    let mut deadline = Instant::now();
    loop {
        screen.clear();
        println!("{}", world);
        world.next();
        deadline += tick;
        if sigtrap.wait(deadline).is_some() { break }
    }
}
<commit_msg>use str::repeat()<commit_after>#[macro_use]
extern crate clap;
extern crate libc;
extern crate signal;

use clap::ArgMatches;
use std::time::Duration;
use world::World;

#[macro_use]
mod macros;
mod screen;
mod world;

const MAPS_MSG: &'static str = "\
MAPS:
    Maps must be rectangular. Whitespace is ignored.
    '·' is a dead cell. Anything else is a living cell.
";
const TICK_MS: u64 = 50;

fn main() {
    fn is_number(s: String) -> Result<(), String> {
        if s.chars().all(|c| c.is_digit(10)) { Ok(()) }
        else { Err(format!("expected a number, found \"{}\"", s)) }
    }

    let matches = clap_app!( rgol =>
        (about: "Conway's game of life for terminal in Rust")
        (author: crate_authors!())
        (version: crate_version!())
        (after_help: MAPS_MSG)
        (@setting SubcommandRequiredElseHelp)
        (@setting VersionlessSubcommands)
        (@subcommand genmap =>
            (about: "Prints an empty map")
            (after_help: MAPS_MSG)
            (@arg NROW: {is_number} * "Number of rows")
            (@arg NCOL: {is_number} * "Number of columns")
            (@arg space: -s --space "Adds spaces to the map"))
        (@subcommand play =>
            (about: "Plays the game (CTRL-c to exit)")
            (after_help: MAPS_MSG)
            (@arg FILE: * "File containing the map")
            (@arg TICK_MS: {is_number} "Elapsed time between iterations in ms")
        )
    ).get_matches();

    match matches.subcommand() {
        ("genmap", Some(args)) => genmap(args),
        ("play",   Some(args)) => play(args),
        _                      => unreachable!(),
    }
}

fn genmap(args: &ArgMatches) {
    use std::io::{Write, stdout};

    let nrow = args.value_of("NROW").expect("NROW has no value").parse().expect("NROW is not a number");
    let ncol = args.value_of("NCOL").expect("NCOL has no value").parse().expect("NCOL is not a number");
    if nrow == 0 || ncol == 0 { return }
    let line = if args.is_present("space") {
        let mut line = "· ".repeat(ncol);
        line.pop();
        line
    }
    else { "·".repeat(ncol) };
    for _ in 0..nrow { writeln!(&mut stdout(), "{}", line).unwrap(); }
}

fn play(args: &ArgMatches) {
    let filename = args.value_of("FILE").expect("FILE has no value");
    let tick_ms = args.value_of("TICK_MS").map_or(TICK_MS, |tms| tms.parse().expect("TICK_MS is not a number"));
    let tick = Duration::from_millis(tick_ms);
    match World::load(filename) {
        Ok(world) => play_world(world, tick),
        Err(err)  => eprintln!("error: {}", err),
    }
}

fn play_world(mut world: World, tick: Duration) {
    use screen::Screen;
    use std::time::Instant;
    use signal::trap::Trap;

    let sigtrap = Trap::trap(&[libc::SIGINT]);
    let screen = Screen::new();
    let mut deadline = Instant::now();
    loop {
        screen.clear();
        println!("{}", world);
        world.next();
        deadline += tick;
        if sigtrap.wait(deadline).is_some() { break }
    }
}
<|endoftext|>


<commit_before>extern crate xml;

use std::os;

use std::io::{File, BufferedReader};
use std::fmt;

use xml::reader::EventReader;
use xml::reader::events::XmlEvent;

fn main() {
	println!("XGConsole:");
	for arg in parse_command_line(os::args()).iter() {
		println!("  {}", arg);
	}
	sample();
}

fn parse_command_line(args: Vec<String>) -> Vec<String> {
	let mut result: Vec<String> = Vec::new();
	for arg in args.slice(1, args.len()).iter() {
			result.push(arg.clone());
	}
	result
}

struct XgTask {
id: Option<String>,
title: Option<String>,
tool: Option<String>,
working_dir: Option<String>,
depends_on: Vec<String>,
}

impl XgTask {
fn new() -> XgTask {
	XgTask {
	id: None,
	title: None,
	tool: None,
	working_dir: None,
	depends_on: vec![],
	}
}
}

impl fmt::Show for XgTask {
fn fmt(& self, f: &mut fmt::Formatter) -> fmt::Result {
	write!(f, "id={}, title={}, tool={}, working_dir={}, depends_on={}", self .id, self .title, self .tool, self .working_dir, self .depends_on)
}
}

struct XgTool {
id: Option<String>,
path: Option<String>,
params: Option<String>,
}

impl XgTool {
fn new() -> XgTool {
	XgTool {
	id: None,
	path: None,
	params: None,
	}
}
}

impl fmt::Show for XgTool {
fn fmt(& self, f: &mut fmt::Formatter) -> fmt::Result {
	write!(f, "id={}, path={}", self .id, self .path)
}
}

fn sample() {
	let file = File::open(&Path::new("tests/graph-parser.xml")).unwrap();
	let reader = BufferedReader::new(file);

	let mut parser = EventReader::new(reader);
	let mut tasks:Vec<XgTask> = vec![];
	let mut tools:Vec<XgTool> = vec![];
	for e in parser.events() {
		match e {
				XmlEvent::StartElement {name, attributes, ..} => {
				match name.local_name.as_slice() {
						"Task" =>
						{
								tasks.push(xg_parse_task(&attributes));
						}
						"Tool" =>
						{
								tools.push(xg_parse_tool(&attributes));
						}
						_ => {}
					}
			}
				XmlEvent::EndElement{..} => {
			}
				_ => {
			}
			}
	}
}

fn xg_parse_task (attributes: &Vec<xml::attribute::OwnedAttribute>)->XgTask {
	let mut task = XgTask::new();
	for attr in attributes.iter() {
		match attr.name.local_name.as_slice()
			{
				"Name" =>
				{
						task.id = Some(attr.value.to_string());
				}
				"Caption" =>
				{
						task.title = Some(attr.value.to_string());
				}
				"Tool" =>
				{
						task.tool = Some(attr.value.to_string());
				}
				"WorkingDir" =>
				{
						task.working_dir = Some(attr.value.to_string());
				}
				"DependsOn" =>
				{
					for item in attr.value.split_str(";").collect::<Vec<&str>>().iter() {
							task.depends_on.push(item.to_string());
					}
				}
				_ =>
				{
				}
			}
	}
	task
}
fn xg_parse_tool (attributes: &Vec<xml::attribute::OwnedAttribute>)->XgTool {
	let mut tool = XgTool::new();
	for attr in attributes.iter() {
		match attr.name.local_name.as_slice()
			{
				"Name" =>
				{
						tool.id = Some(attr.value.to_string());
				}
				"Path" =>
				{
						tool.path = Some(attr.value.to_string());
				}
				"Params" =>
				{
						tool.params = Some(attr.value.to_string());
				}
				_ =>
				{
				}
			}
	}
	tool
}
<commit_msg>Remove some optional parameters.<commit_after>extern crate xml;

use std::os;

use std::io::{File, BufferedReader};
use std::fmt;
use std::collections::HashMap;

use xml::reader::EventReader;
use xml::reader::events::XmlEvent;

fn main() {
	println!("XGConsole:");
	for arg in parse_command_line(os::args()).iter() {
		println!("  {}", arg);
	}
	sample();
}

fn parse_command_line(args: Vec<String>) -> Vec<String> {
	let mut result: Vec<String> = Vec::new();
	for arg in args.slice(1, args.len()).iter() {
			result.push(arg.clone());
	}
	result
}

struct XgTask {
id: String,
title: Option<String>,
tool: String,
working_dir: String,
depends_on: Vec<String>,
}

impl fmt::Show for XgTask {
fn fmt(& self, f: &mut fmt::Formatter) -> fmt::Result {
	write!(f, "id={}, title={}, tool={}, working_dir={}, depends_on={}", self .id, self .title, self .tool, self .working_dir, self .depends_on)
}
}

struct XgTool {
id: String,
path: String,
params: String,
}

impl fmt::Show for XgTool {
fn fmt(& self, f: &mut fmt::Formatter) -> fmt::Result {
	write!(f, "id={}, path={}", self .id, self .path)
}
}

fn sample() {
	let file = File::open(&Path::new("tests/graph-parser.xml")).unwrap();
	let reader = BufferedReader::new(file);

	let mut parser = EventReader::new(reader);
	let mut tasks:Vec<XgTask> = vec![];
	let mut tools:HashMap<String, XgTool> = HashMap::new();
	for e in parser.events() {
		match e {
				XmlEvent::StartElement {name, attributes, ..} => {
				match name.local_name.as_slice() {
						"Task" =>
						{
							match xg_parse_task(&attributes) {
									Ok(task) =>
									{
											tasks.push(task);
									}
									Err(msg) =>
									{
										panic!(msg);
									}
								};
						}
						"Tool" =>
						{
							match xg_parse_tool(&attributes) {
									Ok(tool) =>
									{
											tools.insert(tool.id.to_string(), tool);
									}
									Err(msg) =>
									{
										panic!(msg);
									}
								};
						}
						_ => {}
					}
			}
				XmlEvent::EndElement{..} => {
			}
				_ => {
			}
			}
	}
}

fn map_attributes (attributes: &Vec<xml::attribute::OwnedAttribute>) -> HashMap< String, String> {
	let mut attrs: HashMap<String, String> = HashMap::new();
	for attr in attributes.iter() {
			attrs.insert(attr.name.local_name.clone(), attr.value.clone());
	}
	attrs
}

fn xg_parse_task (attributes: & Vec<xml::attribute::OwnedAttribute>)->Result<XgTask, String> {
	let mut attrs = map_attributes(attributes);
	// Name
	let id: String;
	match attrs.remove("Name") {
			Some(v) => {id = v;}
			_ => {return Err("Invalid task data: attribute @Name not found.".to_string());}
		}
	// Tool
	let tool: String;
	match attrs.remove("Tool") {
			Some(v) => {tool = v;}
			_ => {return Err("Invalid task data: attribute @Tool not found.".to_string());}
		}
	// WorkingDir
	let working_dir: String;
	match attrs.remove("WorkingDir") {
			Some(v) => {working_dir = v;}
			_ => {return Err("Invalid task data: attribute @WorkingDir not found.".to_string());}
		}
	// DependsOn
	let mut depends_on : Vec<String> = vec![];
	match attrs.remove("DependsOn") {
			Some(v) =>
			{
				for item in v.split_str(";").collect::<Vec<&str>>().iter() {
						depends_on.push(item.to_string())
				}
			}
			_ =>
			{
			}
		};

		Ok(XgTask {
	id: id.to_string(),
	title: attrs.remove("Caption"),
	tool: tool,
	working_dir: working_dir,
	depends_on: depends_on,
	})
}
fn xg_parse_tool (attributes: &Vec<xml::attribute::OwnedAttribute>)->Result<XgTool, String> {
	let mut attrs = map_attributes(attributes);
	// Name
	let id: String;
	match attrs.remove("Name") {
			Some(v) => {id = v;}
			_ => {return Err("Invalid task data: attribute @Name not found.".to_string());}
		}
	// Path
	let path: String;
	match attrs.remove("Path") {
			Some(v) => {path = v;}
			_ => {return Err("Invalid task data: attribute @Name not found.".to_string());}
		}

	Ok(XgTool {
	id: id,
	path: path,
	params: match attrs.remove("Params") {
			Some(v) => {v}
			_ => {"".to_string()}
		},
	})
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate lazy_static;

extern crate clap;
extern crate qrcode;
extern crate termion;
extern crate image;
extern crate regex;

use clap::{App, Arg, SubCommand};
use qrcode::{QrCode, EcLevel};
use termion::color;

mod payloads;

const WIFI_COMMAND: &'static str = "wifi";
const MAIL_COMMAND: &'static str = "mail";
const SMS_COMMAND: &'static str = "sms";
const MMS_COMMAND: &'static str = "mms";
const GEO_COMMAND: &'static str = "geo";
const PHONE_COMMAND: &'static str = "phone";
const SKYPE_COMMAND: &'static str = "skype";
const URL_COMMAND: &'static str = "url";
const BOOKMARK_COMMAND: &'static str = "bookmark";
const BITCOIN_COMMAND: &'static str = "bitcoin";
const GIRO_COMMAND: &'static str = "giro";
const CALENDAR_COMMAND: &'static str = "calendar";

/*TODO: add arguments for:
- ec Level
- size of qr code
- implement different types of qr payloads
*/
fn main() {
    let app = App::new("qrterm")
        .version("0.1")
        .author("Lukas R. <lukas@bootsmann-games.de>")
        .about("Generates and displays terminal friendly QR-Codes from input strings")
        .arg(Arg::with_name("safe_zone") //TODO: change this into an off switch
            .global(true)
            .required(false)
            .short("s")
            .long("safe-zone")
            .help("Sets wether the safe zone around the code should be drawn or not.")
            .takes_value(false)
            )
            //TODO: subcmds are not working like expected, if you have one the system assumes you have many
        .subcommand(SubCommand::with_name(WIFI_COMMAND)
            .about("formats to a wifi access string")
            .arg(Arg::with_name("ssid").required(true))
            .arg(Arg::with_name("pwd").required(true))
            .arg(Arg::with_name("mode")
                .possible_values(&["WEP", "WPA", "nopass"])
                .default_value("WPA")
                .value_name("MODE"))
            .arg(Arg::with_name("hidden")
                .required(false)
                .possible_values(&["true", "false"])
                .default_value("false")
                .value_name("HIDDEN")))
        .subcommand(SubCommand::with_name(MAIL_COMMAND)
            .about("formats to a mail adress string")
            .arg(Arg::with_name("receiver").required(true))
            .arg(Arg::with_name("subject"))
            .arg(Arg::with_name("message"))
            .arg(Arg::with_name("encoding")
                .possible_values(&["MAILTO", "MATMSG", "SMTP"])
                .default_value("MAILTO")
                .value_name("ENCODING")))
        .subcommand(SubCommand::with_name(URL_COMMAND)
            .about("formats to an URL")
            .arg(Arg::with_name("url")
                .required(true)
                .value_name("URL")))
        .arg(Arg::with_name("INPUT")
            .help("The input string to use")
            .required_unless_one(&[WIFI_COMMAND, MAIL_COMMAND]));

    let matches = app.get_matches();

    let payload: String;
    if let Some(sub) = matches.subcommand_matches(WIFI_COMMAND) {
        let auth = match sub.value_of("mode") {
            Some("WEP") => payloads::Authentication::WEP,
            Some("WPA") => payloads::Authentication::WPA,
            _ => payloads::Authentication::nopass,
        };
        payload = payloads::wifi_string(sub.value_of("ssid").unwrap(),
                                        sub.value_of("pwd").unwrap(),
                                        &auth,
                                        sub.value_of("hidden").unwrap() == "true");
    } else if let Some(sub) = matches.subcommand_matches(MAIL_COMMAND) {
        let encoding = match sub.value_of("encoding") {
            Some("MAILTO") => payloads::MailEncoding::MAILTO,
            Some("MATMSG") => payloads::MailEncoding::MATMSG,
            Some("SMTP") => payloads::MailEncoding::SMTP,
            _ => payloads::MailEncoding::MAILTO,
        };
        payload = payloads::mail_string(sub.value_of("receiver").unwrap(),
                                        sub.value_of("subject").unwrap(),
                                        sub.value_of("message").unwrap(),
                                        &encoding);
    } else {
        payload = String::from(matches.value_of("INPUT").unwrap());
    }

    let safe: bool = match matches.occurrences_of("safe_zone") {
        0 => true,
        _ => false,
    };

    let code = QrCode::with_error_correction_level(payload, EcLevel::H).unwrap();

    let bit_array = code.to_vec();

    let w = code.width();
    let wide = w + 6;

    //Draw the first white safe zone
    if safe {
        for a in 1..(wide * 3) + 1 {
            print!("{}  ", color::Bg(color::LightWhite));
            if a % wide == 0 {
                println!("{}", color::Bg(color::Reset));
            }
        }
    }

    for (i, item) in bit_array.iter().enumerate() {
        //left safe zone
        if safe && i % w == 0 {
            print!("{}      ", color::Bg(color::LightWhite));
        }

        if *item {
            print!("{}  ", color::Bg(color::Black));
        } else {
            print!("{}  ", color::Bg(color::LightWhite));
        }

        if (i + 1) % w == 0 {
            if safe {
                //draw right safe zone
                println!("{}      {}",
                         color::Bg(color::LightWhite),
                         color::Bg(color::Reset));
            } else {
                println!("{}", color::Bg(color::Reset));
            }
        }
    }

    //Draw the last white safe zone
    if safe {
        for a in 1..(wide * 3) + 1 {
            print!("{}  ", color::Bg(color::LightWhite));
            if a % wide == 0 {
                println!("{}", color::Bg(color::Reset));
            }
        }
    }
}
<commit_msg>added phone and url commands<commit_after>#[macro_use]
extern crate lazy_static;

extern crate clap;
extern crate qrcode;
extern crate termion;
extern crate image;
extern crate regex;

use clap::{App, Arg, SubCommand};
use qrcode::{QrCode, EcLevel};
use termion::color;

mod payloads;

const WIFI_COMMAND: &'static str = "wifi";
const MAIL_COMMAND: &'static str = "mail";
const SMS_COMMAND: &'static str = "sms";
const MMS_COMMAND: &'static str = "mms";
const GEO_COMMAND: &'static str = "geo";
const PHONE_COMMAND: &'static str = "phone";
const SKYPE_COMMAND: &'static str = "skype";
const URL_COMMAND: &'static str = "url";
const BOOKMARK_COMMAND: &'static str = "bookmark";
const BITCOIN_COMMAND: &'static str = "bitcoin";
const GIRO_COMMAND: &'static str = "giro";
const CALENDAR_COMMAND: &'static str = "calendar";

/*TODO: add arguments for:
- ec Level
- size of qr code
- implement different types of qr payloads
*/
fn main() {
    let app = App::new("qrterm")
        .version("0.1")
        .author("Lukas R. <lukas@bootsmann-games.de>")
        .about("Generates and displays terminal friendly QR-Codes from input strings")
        .arg(Arg::with_name("safe_zone") //TODO: change this into an off switch
            .global(true)
            .required(false)
            .short("s")
            .long("safe-zone")
            .help("Sets wether the safe zone around the code should be drawn or not.")
            .takes_value(false)
            )
            //TODO: subcmds are not working like expected, if you have one the system assumes you have many
        .subcommand(SubCommand::with_name(WIFI_COMMAND)
            .about("formats to a wifi access string")
            .arg(Arg::with_name("ssid").required(true))
            .arg(Arg::with_name("pwd").required(true))
            .arg(Arg::with_name("mode")
                .possible_values(&["WEP", "WPA", "nopass"])
                .default_value("WPA")
                .value_name("MODE"))
            .arg(Arg::with_name("hidden")
                .required(false)
                .possible_values(&["true", "false"])
                .default_value("false")
                .value_name("HIDDEN")))
        .subcommand(SubCommand::with_name(MAIL_COMMAND)
            .about("formats to a mail adress string")
            .arg(Arg::with_name("receiver").required(true))
            .arg(Arg::with_name("subject"))
            .arg(Arg::with_name("message"))
            .arg(Arg::with_name("encoding")
                .possible_values(&["MAILTO", "MATMSG", "SMTP"])
                .default_value("MAILTO")
                .value_name("ENCODING")))
        .subcommand(SubCommand::with_name(URL_COMMAND)
            .about("formats to an URL")
            .arg(Arg::with_name("url")
                .required(true)
                .value_name("URL")))
        .subcommand(SubCommand::with_name(PHONE_COMMAND)
            .about("formats to a phone number")
            .arg(Arg::with_name("number")
                .required(true)
                .value_name("NUMBER")))
        .arg(Arg::with_name("INPUT")
            .help("The input string to use")
            .required_unless_one(&[WIFI_COMMAND, MAIL_COMMAND, URL_COMMAND, PHONE_COMMAND]));

    let matches = app.get_matches();

    let payload: String;
    if let Some(sub) = matches.subcommand_matches(WIFI_COMMAND) {
        let auth = match sub.value_of("mode") {
            Some("WEP") => payloads::Authentication::WEP,
            Some("WPA") => payloads::Authentication::WPA,
            _ => payloads::Authentication::nopass,
        };
        payload = payloads::wifi_string(sub.value_of("ssid").unwrap(),
                                        sub.value_of("pwd").unwrap(),
                                        &auth,
                                        sub.value_of("hidden").unwrap() == "true");
    } else if let Some(sub) = matches.subcommand_matches(MAIL_COMMAND) {
        let encoding = match sub.value_of("encoding") {
            Some("MAILTO") => payloads::MailEncoding::MAILTO,
            Some("MATMSG") => payloads::MailEncoding::MATMSG,
            Some("SMTP") => payloads::MailEncoding::SMTP,
            _ => payloads::MailEncoding::MAILTO,
        };
        payload = payloads::mail_string(sub.value_of("receiver").unwrap(),
                                        sub.value_of("subject").unwrap(),
                                        sub.value_of("message").unwrap(),
                                        &encoding);
    } else if let Some(sub) = matches.subcommand_matches(URL_COMMAND) {
        payload = payloads::url_string(sub.value_of("url").unwrap());
    } else if let Some(sub) = matches.subcommand_matches(PHONE_COMMAND) {
        payload = payloads::phone_string(sub.value_of("phone").unwrap());
    } else {
        payload = String::from(matches.value_of("INPUT").unwrap());
    }

    let safe: bool = match matches.occurrences_of("safe_zone") {
        0 => true,
        _ => false,
    };

    let code = QrCode::with_error_correction_level(payload, EcLevel::H).unwrap();

    let bit_array = code.to_vec();

    let w = code.width();
    let wide = w + 6;

    //Draw the first white safe zone
    if safe {
        for a in 1..(wide * 3) + 1 {
            print!("{}  ", color::Bg(color::LightWhite));
            if a % wide == 0 {
                println!("{}", color::Bg(color::Reset));
            }
        }
    }

    for (i, item) in bit_array.iter().enumerate() {
        //left safe zone
        if safe && i % w == 0 {
            print!("{}      ", color::Bg(color::LightWhite));
        }

        if *item {
            print!("{}  ", color::Bg(color::Black));
        } else {
            print!("{}  ", color::Bg(color::LightWhite));
        }

        if (i + 1) % w == 0 {
            if safe {
                //draw right safe zone
                println!("{}      {}",
                         color::Bg(color::LightWhite),
                         color::Bg(color::Reset));
            } else {
                println!("{}", color::Bg(color::Reset));
            }
        }
    }

    //Draw the last white safe zone
    if safe {
        for a in 1..(wide * 3) + 1 {
            print!("{}  ", color::Bg(color::LightWhite));
            if a % wide == 0 {
                println!("{}", color::Bg(color::Reset));
            }
        }
    }
}
<|endoftext|>


<commit_before>#![feature(plugin)]
#![plugin(clippy)]
// #![deny(clippy_pedantic)]
extern crate termion;
extern crate serde_json;
#[macro_use]
extern crate log;
extern crate log4rs;

mod core;

use termion::{clear, cursor};
use termion::raw::IntoRawMode;
use termion::input::TermRead;
use std::io::{stdout, Write, stdin};
use std::sync::mpsc;
use std::{thread, time};
use core::Core;

struct Screen {
    stdout: termion::raw::RawTerminal<std::io::Stdout>,
    size: (u16, u16),
}

impl Screen {

    fn new() -> Screen {
        let mut stdout = stdout().into_raw_mode().unwrap();
        write!(stdout, "{}", clear::All).unwrap();
        stdout.flush().unwrap();
        Screen {
            size: termion::terminal_size().unwrap(),
            stdout: stdout,
        }
    }

    fn redraw(&mut self, update: &Update) {
        write!(self.stdout, "{}", termion::clear::All).unwrap();
        write!(self.stdout, "{}", cursor::Up(self.size.1)).unwrap();
        for (_, line) in update.lines.iter().enumerate() {
            write!(self.stdout, "{}", cursor::Left(self.size.0)).unwrap();
            self.stdout.write_all(line.text.as_bytes()).unwrap();
        }
        // this is pretty weird
        write!(self.stdout, "{}", cursor::Goto(update.scroll_to.1 as u16 + 1, update.scroll_to.0 as u16 + 1)).unwrap();
        self.stdout.flush().unwrap();
    }

    fn init(&mut self) {
        write!(self.stdout, "{}", termion::clear::All).unwrap();
        write!(self.stdout, "{}", cursor::Up(self.size.1)).unwrap();
        self.stdout.flush().unwrap();
    }

}

struct Update {
    lines: Vec<Line>,
    height: u64,
    scroll_to: (u64, u64),
    first_line: u64
}

impl Update {
    fn from_value(value: &serde_json::Value) -> Update {
        let object = value.as_object().unwrap();
        let scroll_to = object.get("scrollto").unwrap().as_array().unwrap();
        let mut lines: Vec<Line> = vec![];
        for line in object.get("lines").unwrap().as_array().unwrap().iter() {
            lines.push(Line::from_value(line));
        }
        info!("{:?}", object);
        Update {
            height: object.get("height").unwrap().as_u64().unwrap(),
            first_line: object.get("first_line").unwrap().as_u64().unwrap(),
            lines: lines,
            scroll_to: (scroll_to[0].as_u64().unwrap(), scroll_to[1].as_u64().unwrap()),
        }
    }
}

struct Line {
    text: String,
    selection: Option<(u64, u64)>,
    cursor: Option<u64>,
}

impl Line {
    fn from_value(value: &serde_json::Value) -> Line {
        let line_arr = value.as_array().unwrap();
        let mut line = Line {
            text: line_arr[0].as_str().unwrap().to_string(),
            cursor: None,
            selection: None,
        };
        for annotation in line_arr.iter().skip(1).map(|a| a.as_array().unwrap()) {
            match annotation[0].as_str().unwrap() {
                "cursor" => {
                    line.cursor = Some(annotation[1].as_u64().unwrap());
                },
                "sel" => {
                    line.selection = Some((annotation[1].as_u64().unwrap(), annotation[2].as_u64().unwrap()));
                },
                _ => {
                    error!("unknown annotation");
                }
            }
        }
        line
    }
}

fn update_screen(core: &mut Core, screen: &mut Screen) {
    if let Ok(msg) = core.update_rx.try_recv() {
        let update = Update::from_value(msg.as_object().unwrap().get("update").unwrap());
        screen.redraw(&update);
    } else {
        thread::sleep_ms(10);
    }
}

pub struct Input {
    tx: mpsc::Sender<termion::event::Event>,
    rx: mpsc::Receiver<termion::event::Event>,
}

impl Input {
    pub fn new() -> Input {
        let (tx, rx) = mpsc::channel();
        Input {
            tx: tx,
            rx: rx,
        }
    }

    pub fn run(&mut self) {
        let tx = self.tx.clone();
        thread::spawn(move || {
            for event_res in stdin().events() {
                match event_res {
                    Ok(event) => {
                        info!("event: {:?}", event);
                        tx.send(event).unwrap();
                    },
                    Err(err) => {
                        error!("{:?}", err);
                    }
                }
            }
        });
    }
}

impl Default for Input {
	fn default() -> Self {
		Self::new()
	}
}

fn main() {
    log4rs::init_file("log_config.yaml", Default::default()).unwrap();
    let mut core = Core::new("../xi-editor/rust/target/debug/xi-core");
    let mut screen = Screen::new();
    let mut input = Input::new();
    input.run();
    screen.init();
    loop {
        if let Ok(event) = input.rx.try_recv() {
            match event {
                termion::event::Event::Key(key) => {
                    match key {
                        termion::event::Key::Char(c) => {
                            core.char(c);
                        },
                        termion::event::Key::Ctrl(c) => {
                            if c == 'c' {
                                info!("received ^C: exiting");
                                return;
                            }
                        },
                        _ => {
                            error!("unsupported key event");
                        }
                    }
                },
                termion::event::Event::Mouse(_) => {
                    error!("mouse events are not supported yet");
                }
                _ => {
                    error!("unsupported event");
                }
            }
        } else {
            update_screen(&mut core, &mut screen);
        }
    }
}
<commit_msg>fix deprecation warning: thread::sleep_ms -> thread::sleep<commit_after>#![feature(plugin)]
#![plugin(clippy)]
// #![deny(clippy_pedantic)]
extern crate termion;
extern crate serde_json;
#[macro_use]
extern crate log;
extern crate log4rs;

mod core;

use termion::{clear, cursor};
use termion::raw::IntoRawMode;
use termion::input::TermRead;
use std::io::{stdout, Write, stdin};
use std::sync::mpsc;
use std::{thread, time};
use core::Core;

struct Screen {
    stdout: termion::raw::RawTerminal<std::io::Stdout>,
    size: (u16, u16),
}

impl Screen {

    fn new() -> Screen {
        let mut stdout = stdout().into_raw_mode().unwrap();
        write!(stdout, "{}", clear::All).unwrap();
        stdout.flush().unwrap();
        Screen {
            size: termion::terminal_size().unwrap(),
            stdout: stdout,
        }
    }

    fn redraw(&mut self, update: &Update) {
        write!(self.stdout, "{}", termion::clear::All).unwrap();
        write!(self.stdout, "{}", cursor::Up(self.size.1)).unwrap();
        for (_, line) in update.lines.iter().enumerate() {
            write!(self.stdout, "{}", cursor::Left(self.size.0)).unwrap();
            self.stdout.write_all(line.text.as_bytes()).unwrap();
        }
        // this is pretty weird
        write!(self.stdout, "{}", cursor::Goto(update.scroll_to.1 as u16 + 1, update.scroll_to.0 as u16 + 1)).unwrap();
        self.stdout.flush().unwrap();
    }

    fn init(&mut self) {
        write!(self.stdout, "{}", termion::clear::All).unwrap();
        write!(self.stdout, "{}", cursor::Up(self.size.1)).unwrap();
        self.stdout.flush().unwrap();
    }

}

struct Update {
    lines: Vec<Line>,
    height: u64,
    scroll_to: (u64, u64),
    first_line: u64
}

impl Update {
    fn from_value(value: &serde_json::Value) -> Update {
        let object = value.as_object().unwrap();
        let scroll_to = object.get("scrollto").unwrap().as_array().unwrap();
        let mut lines: Vec<Line> = vec![];
        for line in object.get("lines").unwrap().as_array().unwrap().iter() {
            lines.push(Line::from_value(line));
        }
        info!("{:?}", object);
        Update {
            height: object.get("height").unwrap().as_u64().unwrap(),
            first_line: object.get("first_line").unwrap().as_u64().unwrap(),
            lines: lines,
            scroll_to: (scroll_to[0].as_u64().unwrap(), scroll_to[1].as_u64().unwrap()),
        }
    }
}

struct Line {
    text: String,
    selection: Option<(u64, u64)>,
    cursor: Option<u64>,
}

impl Line {
    fn from_value(value: &serde_json::Value) -> Line {
        let line_arr = value.as_array().unwrap();
        let mut line = Line {
            text: line_arr[0].as_str().unwrap().to_string(),
            cursor: None,
            selection: None,
        };
        for annotation in line_arr.iter().skip(1).map(|a| a.as_array().unwrap()) {
            match annotation[0].as_str().unwrap() {
                "cursor" => {
                    line.cursor = Some(annotation[1].as_u64().unwrap());
                },
                "sel" => {
                    line.selection = Some((annotation[1].as_u64().unwrap(), annotation[2].as_u64().unwrap()));
                },
                _ => {
                    error!("unknown annotation");
                }
            }
        }
        line
    }
}

fn update_screen(core: &mut Core, screen: &mut Screen) {
    if let Ok(msg) = core.update_rx.try_recv() {
        let update = Update::from_value(msg.as_object().unwrap().get("update").unwrap());
        screen.redraw(&update);
    } else {
        thread::sleep(time::Duration::from_millis(10));
    }
}

pub struct Input {
    tx: mpsc::Sender<termion::event::Event>,
    rx: mpsc::Receiver<termion::event::Event>,
}

impl Input {
    pub fn new() -> Input {
        let (tx, rx) = mpsc::channel();
        Input {
            tx: tx,
            rx: rx,
        }
    }

    pub fn run(&mut self) {
        let tx = self.tx.clone();
        thread::spawn(move || {
            for event_res in stdin().events() {
                match event_res {
                    Ok(event) => {
                        info!("event: {:?}", event);
                        tx.send(event).unwrap();
                    },
                    Err(err) => {
                        error!("{:?}", err);
                    }
                }
            }
        });
    }
}

impl Default for Input {
	fn default() -> Self {
		Self::new()
	}
}

fn main() {
    log4rs::init_file("log_config.yaml", Default::default()).unwrap();
    let mut core = Core::new("../xi-editor/rust/target/debug/xi-core");
    let mut screen = Screen::new();
    let mut input = Input::new();
    input.run();
    screen.init();
    loop {
        if let Ok(event) = input.rx.try_recv() {
            match event {
                termion::event::Event::Key(key) => {
                    match key {
                        termion::event::Key::Char(c) => {
                            core.char(c);
                        },
                        termion::event::Key::Ctrl(c) => {
                            if c == 'c' {
                                info!("received ^C: exiting");
                                return;
                            }
                        },
                        _ => {
                            error!("unsupported key event");
                        }
                    }
                },
                termion::event::Event::Mouse(_) => {
                    error!("mouse events are not supported yet");
                }
                _ => {
                    error!("unsupported event");
                }
            }
        } else {
            update_screen(&mut core, &mut screen);
        }
    }
}
<|endoftext|>