|
|
@@ -1,9 +1,10 @@
|
|
|
+extern crate rand;
|
|
|
extern crate sdl2;
|
|
|
|
|
|
+use std::{io, thread};
|
|
|
use std::fs::File;
|
|
|
use std::io::{Read, Write};
|
|
|
use std::time::{Duration, SystemTime};
|
|
|
-use std::{io, thread};
|
|
|
|
|
|
use sdl2::event::Event;
|
|
|
use sdl2::keyboard::Keycode;
|
|
|
@@ -24,6 +25,52 @@ struct Tetrimino {
|
|
|
current_state: u8,
|
|
|
}
|
|
|
|
|
|
+impl Tetrimino {
|
|
|
+ fn rotate(&mut self, game_map: &[Vec<u8>]) {
|
|
|
+ let mut tmp_state = self.current_state + 1;
|
|
|
+ if tmp_state as usize >= self.states.len() {
|
|
|
+ tmp_state = 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ let x_pos = [0, -1, 1, -2, 2, -3];
|
|
|
+ for x in x_pos.iter() {
|
|
|
+ if self.test_position(game_map, tmp_state as usize, self.x + x, self.y) == true {
|
|
|
+ self.current_state = tmp_state;
|
|
|
+ self.x += *x;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ fn change_position(&mut self, game_map: &[Vec<u8>], new_x: isize, new_y: usize) -> bool {
|
|
|
+ if self.test_position(game_map, self.current_state as usize, new_x, new_y) == true {
|
|
|
+ self.x = new_x;
|
|
|
+ self.y = new_y;
|
|
|
+ true
|
|
|
+ } else {
|
|
|
+ false
|
|
|
+ }
|
|
|
+ }
|
|
|
+ fn test_position(&self, game_map: &[Vec<u8>], tmp_state: usize, x: isize, y: usize) -> bool {
|
|
|
+ for decal_y in 0..4 {
|
|
|
+ for decal_x in 0..4 {
|
|
|
+ let x = x + decal_x;
|
|
|
+ if self.states[tmp_state][decal_y][decal_x as usize] != 0
|
|
|
+ && (y + decal_y >= game_map.len()
|
|
|
+ || x < 0
|
|
|
+ || x as usize >= game_map[y + decal_y].len()
|
|
|
+ || game_map[y + decal_y][x as usize] != 0)
|
|
|
+ {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ fn test_current_position(&self, game_map: &[Vec<u8>]) -> bool {
|
|
|
+ self.test_position(game_map, self.current_state as usize, self.x, self.y)
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
trait TetriminoGenerator {
|
|
|
fn new() -> Tetrimino;
|
|
|
}
|
|
|
@@ -128,7 +175,7 @@ impl TetriminoGenerator for TetriminoL {
|
|
|
}
|
|
|
|
|
|
struct TetriminoO;
|
|
|
-impl TetriminoGenerator for Tetrimino {
|
|
|
+impl TetriminoGenerator for TetriminoO {
|
|
|
fn new() -> Tetrimino {
|
|
|
Tetrimino {
|
|
|
states: vec![vec![
|
|
|
@@ -231,6 +278,107 @@ impl TetriminoGenerator for TetriminoT {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+struct Tetris {
|
|
|
+ game_map: Vec<Vec<u8>>,
|
|
|
+ current_level: u32,
|
|
|
+ score: u32,
|
|
|
+ nb_lines: u32,
|
|
|
+ current_piece: Option<Tetrimino>,
|
|
|
+}
|
|
|
+
|
|
|
+impl Tetris {
|
|
|
+ fn new() -> Tetris {
|
|
|
+ let mut game_map = Vec::new();
|
|
|
+
|
|
|
+ // 16 行 10 列
|
|
|
+ for _ in 0..16 {
|
|
|
+ game_map.push(vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
|
|
|
+ }
|
|
|
+ Tetris {
|
|
|
+ game_map,
|
|
|
+ current_level: 1,
|
|
|
+ score: 0,
|
|
|
+ nb_lines: 0,
|
|
|
+ current_piece: None,
|
|
|
+ }
|
|
|
+ }
|
|
|
+ /// 随机创建 tetrimino
|
|
|
+ fn create_new_tetrimino(&self) -> Tetrimino {
|
|
|
+ static mut PREV: u8 = 7;
|
|
|
+ let mut rand_nb = rand::random::<u8>() % 7;
|
|
|
+ if unsafe { PREV } == rand_nb {
|
|
|
+ rand_nb = rand::random::<u8>() % 7;
|
|
|
+ }
|
|
|
+ unsafe {
|
|
|
+ PREV = rand_nb;
|
|
|
+ }
|
|
|
+
|
|
|
+ match rand_nb {
|
|
|
+ 0 => TetriminoI::new(),
|
|
|
+ 1 => TetriminoJ::new(),
|
|
|
+ 2 => TetriminoL::new(),
|
|
|
+ 3 => TetriminoO::new(),
|
|
|
+ 4 => TetriminoS::new(),
|
|
|
+ 5 => TetriminoZ::new(),
|
|
|
+ 6 => TetriminoT::new(),
|
|
|
+ _ => unreachable!(),
|
|
|
+ }
|
|
|
+ }
|
|
|
+ /// Remove lines when they're full
|
|
|
+ fn check_line(&mut self) {
|
|
|
+ let mut y = 0;
|
|
|
+
|
|
|
+ while y < self.game_map.len() {
|
|
|
+ let mut complete = true;
|
|
|
+
|
|
|
+ for x in &self.game_map[y] {
|
|
|
+ if *x == 0 {
|
|
|
+ complete = false;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if complete == true {
|
|
|
+ self.game_map.remove(y);
|
|
|
+ y -= 1;
|
|
|
+ // increase the number of self.lines
|
|
|
+ }
|
|
|
+ y += 1;
|
|
|
+ }
|
|
|
+ while self.game_map.len() < 16 {
|
|
|
+ self.game_map.insert(0, vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ fn make_permanent(&mut self) {
|
|
|
+ if let Some(ref mut piece) = self.current_piece {
|
|
|
+ let mut shift_y = 0;
|
|
|
+
|
|
|
+ while shift_y < piece.states[piece.current_state as usize].len()
|
|
|
+ && piece.y + shift_y < self.game_map.len()
|
|
|
+ {
|
|
|
+ let mut shift_x = 0;
|
|
|
+
|
|
|
+ while shift_x < piece.states[piece.current_state as usize][shift_y].len()
|
|
|
+ && (piece.x + shift_x as isize)
|
|
|
+ < self.game_map[piece.y + shift_y].len() as isize
|
|
|
+ {
|
|
|
+ if piece.states[piece.current_state as usize][shift_y][shift_x] != 0 {
|
|
|
+ let x = piece.x + shift_x as isize;
|
|
|
+ self.game_map[piece.y + shift_y][x as usize] =
|
|
|
+ piece.states[piece.current_state as usize][shift_y][shift_x];
|
|
|
+ }
|
|
|
+
|
|
|
+ shift_x += 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ shift_y += 1;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ self.check_line();
|
|
|
+ self.current_piece = None;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
#[derive(Clone, Copy)]
|
|
|
enum TextureColor {
|
|
|
Green,
|