Procházet zdrojové kódy

Tetris Types and implement

runningwater před 1 rokem
rodič
revize
6d6ab51f8a
3 změnil soubory, kde provedl 205 přidání a 2 odebrání
  1. 54 0
      Cargo.lock
  2. 1 0
      Cargo.toml
  3. 150 2
      src/main.rs

+ 54 - 0
Cargo.lock

@@ -15,6 +15,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
 
 [[package]]
+name = "getrandom"
+version = "0.2.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "wasi",
+]
+
+[[package]]
 name = "lazy_static"
 version = "1.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -27,6 +38,42 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "13e3bf6590cbc649f4d1a3eefc9d5d6eb746f5200ffb04e5e142700b8faa56e7"
 
 [[package]]
+name = "ppv-lite86"
+version = "0.2.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
+
+[[package]]
+name = "rand"
+version = "0.8.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
+dependencies = [
+ "libc",
+ "rand_chacha",
+ "rand_core",
+]
+
+[[package]]
+name = "rand_chacha"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
+dependencies = [
+ "ppv-lite86",
+ "rand_core",
+]
+
+[[package]]
+name = "rand_core"
+version = "0.6.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
+dependencies = [
+ "getrandom",
+]
+
+[[package]]
 name = "sdl2"
 version = "0.36.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -53,6 +100,7 @@ dependencies = [
 name = "tetris"
 version = "0.1.0"
 dependencies = [
+ "rand",
  "sdl2",
 ]
 
@@ -61,3 +109,9 @@ name = "version-compare"
 version = "0.1.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "579a42fc0b8e0c63b76519a339be31bed574929511fa53c1a3acae26eb258f29"
+
+[[package]]
+name = "wasi"
+version = "0.11.0+wasi-snapshot-preview1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"

+ 1 - 0
Cargo.toml

@@ -7,5 +7,6 @@ edition = "2021"
 
 [dependencies]
 sdl2 = "0.36.0"
+rand = "0.8.5"
 [features]
 #default = ["sdl2/image"]

+ 150 - 2
src/main.rs

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