1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
extern crate graphics;
extern crate opengl_graphics;
extern crate piston;
extern crate piston_window;

extern crate rand;

use opengl_graphics::GlGraphics;
use piston::input::*;

use self::{
    food::Food,
    snake::{Direction, Snake},
};

pub mod food;
pub mod snake;

pub struct Game {
    pub gl: GlGraphics,
    pub rows: u32,
    pub cols: u32,
    pub snake: Snake,
    pub just_eaten: bool,
    pub square_width: u32,
    pub food: Food,
    pub score: u32,
}

impl Game {
    pub fn render(&mut self, args: &RenderArgs) {
        const BLACK: [f32; 4] = [0.0, 0.0, 0.0, 1.0];

        self.gl.draw(args.viewport(), |_, gl| {
            graphics::clear(BLACK, gl);
        });

        self.snake.render(args);
        self.food.render(&mut self.gl, args, self.square_width);
    }

    pub fn update(&mut self, _: &UpdateArgs) -> bool {
        if !self.snake.update(self.just_eaten, self.cols, self.rows) {
            return false;
        }

        if self.just_eaten {
            self.score += 1;
            self.just_eaten = false;
        }

        self.just_eaten = self.food.update(&self.snake);
        if self.just_eaten {
            use rand::{thread_rng, Rng};

            let mut r = thread_rng();
            loop {
                let new_x: u32 = r.gen_range(0..self.cols);
                let new_y: u32 = r.gen_range(0..self.rows);
                if !self.snake.is_collide(new_x, new_y) {
                    self.food = Food { x: new_x, y: new_y };
                    break;
                }
            }
        }

        true
    }

    pub fn pressed(&mut self, btn: &Button) {
        let last_direction = self.snake.d.clone();
        self.snake.d = match btn {
            &Button::Keyboard(Key::Up) if last_direction != Direction::DOWN => Direction::UP,
            &Button::Keyboard(Key::Down) if last_direction != Direction::UP => Direction::DOWN,
            &Button::Keyboard(Key::Left) if last_direction != Direction::RIGHT => Direction::LEFT,
            &Button::Keyboard(Key::Right) if last_direction != Direction::LEFT => Direction::RIGHT,
            _ => last_direction,
        };
    }
}