diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/display.rs | 20 | ||||
-rw-r--r-- | src/lib.rs | 42 | ||||
-rw-r--r-- | src/tetris.rs | 20 | ||||
-rw-r--r-- | src/tetris/piece.rs | 232 |
4 files changed, 279 insertions, 35 deletions
diff --git a/src/display.rs b/src/display.rs index c3791f8..b57f68f 100644 --- a/src/display.rs +++ b/src/display.rs @@ -1,5 +1,21 @@ -pub fn display(grid: &Vec<Vec<i8>>) { +use crate::tetris::piece::{Piece, Pos}; + +pub fn display(grid: &Vec<Vec<i8>>, piece: &Piece) { + let piece_pos_vec = piece.get_bits_pos(); + + let mut yc = 0; for y in grid { - println!("{:?}", y); + let mut xc = 0; + for mut x in y { + for bit in &piece_pos_vec { + if bit == &Pos(yc, xc) { + x = &1; + } + } + xc += 1; + print!("{} ", x); + } + print!("\n"); + yc += 1; } }
\ No newline at end of file @@ -1,6 +1,9 @@ pub mod input; mod tetris; +mod display; +use crate::tetris::piece; +use std::io::stdin; use crate::input::Input; pub struct Game { @@ -16,14 +19,37 @@ impl Game { } // The actual game loop - pub fn game_loop(&self, input: &Input) {} -} + pub fn game_loop(&self, input: &Input) { + let mut tetris = tetris::Tetris::new(); + let mut piece = piece::Piece::random(); + loop { + piece.r#move(piece::Dir::Down, &tetris); -#[cfg(test)] -mod tests { - #[test] - fn it_works() { - let result = 2 + 2; - assert_eq!(result, 4); + // Check if piece is dead + if piece.is_alive() == false { + piece.apply_to_grid(&mut tetris); + // piece = piece::Piece::random(); + piece = piece::Piece::new(piece::Pieces::Cube); + } + + let grid = tetris.return_grid(); + display::display(&grid, &piece); + + let mut input = String::new(); + + stdin().read_line(&mut input).expect("Could not read line"); + let input = input.get(0..1).expect("Nothing to get"); + match input { + "a" => piece.r#move(piece::Dir::Left, &tetris), + "d" => piece.r#move(piece::Dir::Right, &tetris), + "e" => piece.rotate(piece::Rotate::Right), + "q" => piece.rotate(piece::Rotate::Right), + " " => break, + _ => (), + } + } } } + +#[cfg(test)] +mod tests {} diff --git a/src/tetris.rs b/src/tetris.rs index 9f9cda8..aa9b883 100644 --- a/src/tetris.rs +++ b/src/tetris.rs @@ -1,6 +1,4 @@ -mod piece; - -use piece::Piece; +pub mod piece; #[derive(Debug)] pub struct Tetris { @@ -18,11 +16,23 @@ impl Tetris { &self.grid } - // Set the grid, given a piece - pub fn set_grid(&mut self, piece: Piece) {} + // Set the grid at a Pos + pub fn set_grid(&mut self, pos: piece::Pos, value: i8) { + if self.get_grid_pos(pos) != value { + self.grid[pos.0 as usize][pos.1 as usize] = value + } + } // Check each row of the grid // If one is full, remove it and drop // the rest of the grid down pub fn check_lines() {} + + pub fn get_grid_pos(&self, pos: piece::Pos) -> i8 { + match self.grid.get(pos.0 as usize) { + None => return 0, + _ => return *self.grid.get(pos.0 as usize).unwrap() + .get(pos.1 as usize).unwrap_or(&0) + } + } }
\ No newline at end of file diff --git a/src/tetris/piece.rs b/src/tetris/piece.rs index a57b2bb..ca93c59 100644 --- a/src/tetris/piece.rs +++ b/src/tetris/piece.rs @@ -1,9 +1,40 @@ -pub struct Pos(i8, i8); +use rand::Rng; +use std::ops::{AddAssign, Add}; +use crate::tetris::Tetris; -pub const UP: Pos = Pos(1,0); -pub const DOWN: Pos = Pos(-1,0); -pub const LEFT: Pos = Pos(0,-1); -pub const RIGHT: Pos = Pos(0,1); +#[derive(Copy)] +#[derive(Clone)] +#[derive(PartialEq)] +#[derive(Debug)] +pub struct Pos(pub i8, pub i8); +impl AddAssign for Pos { + fn add_assign(&mut self, other: Self) { + *self = Self { + 0: self.0 + other.0, + 1: self.1 + other.1, + }; + } +} +impl Add for Pos { + type Output = Self; + + fn add(self, other: Self) -> Self::Output { + Self { + 0: self.0 + other.0, + 1: self.1 + other.1, + } + } +} + +const UP: Pos = Pos(-1,0); +const DOWN: Pos = Pos(1,0); +const LEFT: Pos = Pos(0,-1); +const RIGHT: Pos = Pos(0,1); + +pub enum Rotate { + Left, + Right +} pub enum Dir { Up, @@ -11,6 +42,16 @@ pub enum Dir { Left, Right, } +impl Dir { + fn get(&self) -> Pos { + match self { + Dir::Up => UP, + Dir::Down => DOWN, + Dir::Left => LEFT, + Dir::Right => RIGHT, + } + } +} const NORMALL: [[i8; 3]; 3] = [[0,1,0],[0,1,0],[0,1,1]]; const REVERSEL: [[i8; 3]; 3] = [[0,1,0],[0,1,0],[1,1,0]]; @@ -19,7 +60,7 @@ const TEE: [[i8; 3]; 3] = [[0,1,0],[1,1,1],[0,0,0]]; const DIAG: [[i8; 3]; 3] = [[0,1,1],[1,1,0],[0,0,0]]; const REVERSEDIAG: [[i8; 3]; 3] = [[1,1,0],[0,1,1],[0,0,0]]; -enum Pieces { +pub enum Pieces { NormalL, ReverseL, Cube, @@ -27,6 +68,45 @@ enum Pieces { Diag, ReverseDiag, } +impl Pieces { + pub fn random() -> Pieces { + use Pieces::*; + let mut rand = rand::thread_rng(); + match rand.gen_range(0..6) { + 0 => NormalL, + 1 => ReverseL, + 2 => Cube, + 3 => Tee, + 4 => Diag, + 5 => ReverseDiag, + _ => NormalL, + } + } + + fn get(&self) -> [[i8; 3]; 3] { + use Pieces::*; + match &self { + NormalL => NORMALL, + ReverseL => REVERSEL, + Cube => CUBE, + Tee => TEE, + Diag => DIAG, + ReverseDiag => REVERSEDIAG, + } + } + + fn get_origin(&self) -> Pos { + use Pieces::*; + match &self { + NormalL => Pos(0,0), + ReverseL => Pos(0,0), + Cube => Pos(0,0), + Tee => Pos(0,0), + Diag => Pos(0,0), + ReverseDiag => Pos(0,0), + } + } +} pub struct Piece { area: [[i8; 3]; 3], // A static 3x3 area @@ -35,22 +115,23 @@ pub struct Piece { alive: bool, } impl Piece { - pub fn new() -> Piece { + pub fn new(p: Pieces) -> Piece { Piece{ - area: NORMALL, + area: p.get(), position: Pos(0,5), - origin: Pos(1,1), + origin: p.get_origin(), alive: true, } } - - // Like new(), but return a random piece + + // Return a random piece // out of the enum Pieces pub fn random() -> Piece { + let piece = Pieces::random(); Piece{ - area: NORMALL, - position: Pos(0,5), - origin: Pos(1,1), + area: piece.get(), + position: Pos(0,4), + origin: piece.get_origin(), alive: true, } } @@ -58,14 +139,125 @@ impl Piece { // Using a grid and a direction; // See if the new position would hit // something in the grid - // If so, return err - // otherwise return Some(Pos) - fn hit_detect(&self, grid: &Vec<Vec<i8>>) -> Option<Pos> { - None + // If so, return Err + // otherwise return Ok + fn hit_detect(&mut self, dir: &Dir, grid: &Tetris) -> Result<(), ()> { + for pos in self.get_bits_pos() { + let new_pos = pos + dir.get(); + + // Detect blocks and kill + if grid.get_grid_pos(new_pos) == 1 { + self.kill(); + return Err(()) + } else if new_pos.0 > 19 { // Detect bottom and kill + self.kill(); + return Err(()) + } else if new_pos.1 > 9 || new_pos.1 < 0 { // Detect sides + return Err(()) + } + } + Ok(()) + } + + pub fn apply_to_grid(&self, grid: &mut Tetris) { + for pos in self.get_bits_pos() { + grid.set_grid(pos, 1) + } + } + + fn apply_dir(&mut self, dir: &Dir) { + self.position += dir.get(); + } + + pub fn get_bits_pos(&self) -> Vec<Pos> { + let mut piece_pos_vec = vec![]; + + let mut y = -1; + for posy in self.get_area() { + let mut x = -1; + for posx in posy { + x += 1; + if posx == 1 { + piece_pos_vec.push(self.get_pos() + Pos(y, x) + self.origin) + } + } + y += 1; + } + + return piece_pos_vec + } + + pub fn rotate(&mut self, r: Rotate) { + // Must call hit detect before applying + } + + pub fn get_pos(&self) -> Pos { + self.position + } + + pub fn get_area(&self) -> [[i8; 3]; 3] { + self.area + } + + pub fn is_alive(&self) -> bool { + self.alive + } + + fn kill(&mut self) { + self.alive = false } // Return false if the piece cannot move - pub fn r#move(&self, dir: Dir) -> bool { - false + pub fn r#move(&mut self, dir: Dir, grid: &Tetris) { + // If a hit is detected, don't move + // Otherwise move + match self.hit_detect(&dir, &grid) { + Ok(_) => self.apply_dir(&dir), + Err(_) => (), + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn apply_down() { + let mut p = Piece::new(Pieces::Cube); + let d = Dir::Down; + p.apply_dir(&d); + + if p.get_pos() != Pos(1,5) { + panic!("{:?} did not move down properly", p.get_pos()) + } + } + + #[test] + fn hit_test() { + let mut p = Piece::new(Pieces::Cube); + let d = Dir::Down; + + let tetris = Tetris::new(); + + p.r#move(d, &tetris); + + if p.is_alive() != false { + panic!("Piece did not die, is_alive == {}", p.is_alive()) + } + + } + #[test] + fn hit_nothing_test() { + let mut p = Piece::new(Pieces::Cube); + let d = Dir::Down; + + let tetris = Tetris::new(); + + p.r#move(d, &tetris); + + if p.is_alive() == false { + panic!("Piece died, is_alive == {}", p.is_alive()) + } } }
\ No newline at end of file |