tetris/src/tetromino.rs

308 lines
9.9 KiB
Rust

use crate::{
graphics::*,
playfield::{PLAYFIELD_HEIGHT, PLAYFIELD_WIDTH},
};
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum TetrominoType {
I,
O,
T,
S,
Z,
J,
L,
}
impl Into<MinoColor> for TetrominoType {
fn into(self) -> MinoColor {
match self {
Self::I => MinoColor::Cyan,
Self::O => MinoColor::Yellow,
Self::T => MinoColor::Purple,
Self::S => MinoColor::Green,
Self::Z => MinoColor::Red,
Self::J => MinoColor::Blue,
Self::L => MinoColor::Orange,
}
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum RotationState {
O, // initial state
R, // clockwise rotation
L, // counter-clockwise rotation
U, // 180 deg rotation
}
impl Default for RotationState {
fn default() -> Self {
RotationState::O
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub struct Position {
pub x: isize,
pub y: isize,
}
impl Position {
pub fn new(x: isize, y: isize) -> Position {
Self {
x: x as isize,
y: y as isize,
}
}
pub fn offset(&self, x: isize, y: isize) -> Position {
Self {
x: x + self.x,
y: y + self.y,
}
}
}
impl std::ops::Add for Position {
type Output = Self;
fn add(self, other: Self) -> Self {
Self {
x: self.x + other.x,
y: self.y + other.y,
}
}
}
impl std::ops::Sub for Position {
type Output = Self;
fn sub(self, other: Self) -> Self {
Self {
x: self.x - other.x,
y: self.y - other.y,
}
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub struct Tetromino {
pub position: Position,
pub piece_type: TetrominoType,
pub rotation_state: RotationState,
}
impl Tetromino {
pub fn new(tetromino_type: TetrominoType) -> Self {
Self {
position: Self::get_start_position(tetromino_type),
piece_type: tetromino_type,
rotation_state: RotationState::default(),
}
}
fn get_start_position(tetromino_type: TetrominoType) -> Position {
if tetromino_type == TetrominoType::I {
Position::new(
PLAYFIELD_WIDTH as isize / 2 - 1,
PLAYFIELD_HEIGHT as isize - 1,
)
} else {
Position::new(PLAYFIELD_WIDTH as isize / 2 - 1, PLAYFIELD_HEIGHT as isize)
}
}
pub fn get_falling_occupied_spaces(&self) -> Vec<Position> {
self.get_occupied_spaces(self.position.offset(0, 1))
}
pub fn get_cur_occupied_spaces(&self) -> Vec<Position> {
self.get_occupied_spaces(self.position)
}
pub fn get_occupied_spaces(&self, center: Position) -> Vec<Position> {
let mut spaces = vec![center];
match self.piece_type {
TetrominoType::I => match self.rotation_state {
RotationState::O => spaces.extend_from_slice(&[
center.offset(-1, 0),
center.offset(1, 0),
center.offset(2, 0),
]),
RotationState::R => spaces.extend_from_slice(&[
center.offset(0, -1),
center.offset(0, 1),
center.offset(0, 2),
]),
RotationState::U => spaces.extend_from_slice(&[
center.offset(-2, 0),
center.offset(-1, 0),
center.offset(1, 0),
]),
RotationState::L => spaces.extend_from_slice(&[
center.offset(0, -2),
center.offset(0, -1),
center.offset(0, 1),
]),
},
TetrominoType::J => match self.rotation_state {
RotationState::O => spaces.extend_from_slice(&[
center.offset(-1, -1),
center.offset(-1, 0),
center.offset(1, 0),
]),
RotationState::R => spaces.extend_from_slice(&[
center.offset(0, -1),
center.offset(1, -1),
center.offset(0, 1),
]),
RotationState::U => spaces.extend_from_slice(&[
center.offset(-1, 0),
center.offset(1, 0),
center.offset(1, 1),
]),
RotationState::L => spaces.extend_from_slice(&[
center.offset(0, -1),
center.offset(-1, 1),
center.offset(0, 1),
]),
},
TetrominoType::L => match self.rotation_state {
RotationState::O => spaces.extend_from_slice(&[
center.offset(1, -1),
center.offset(-1, 0),
center.offset(1, 0),
]),
RotationState::R => spaces.extend_from_slice(&[
center.offset(0, -1),
center.offset(0, 1),
center.offset(1, 1),
]),
RotationState::U => spaces.extend_from_slice(&[
center.offset(-1, 0),
center.offset(1, 0),
center.offset(-1, 1),
]),
RotationState::L => spaces.extend_from_slice(&[
center.offset(-1, -1),
center.offset(0, -1),
center.offset(0, 1),
]),
},
TetrominoType::O => match self.rotation_state {
RotationState::O => spaces.extend_from_slice(&[
center.offset(0, -1),
center.offset(1, -1),
center.offset(1, 0),
]),
RotationState::R => spaces.extend_from_slice(&[
center.offset(1, 0),
center.offset(0, 1),
center.offset(1, 1),
]),
RotationState::U => spaces.extend_from_slice(&[
center.offset(-1, 0),
center.offset(-1, 1),
center.offset(0, 1),
]),
RotationState::L => spaces.extend_from_slice(&[
center.offset(-1, -1),
center.offset(0, -1),
center.offset(-1, 0),
]),
},
TetrominoType::S => match self.rotation_state {
RotationState::O => spaces.extend_from_slice(&[
center.offset(0, -1),
center.offset(1, -1),
center.offset(-1, 0),
]),
RotationState::R => spaces.extend_from_slice(&[
center.offset(0, -1),
center.offset(1, 0),
center.offset(1, 1),
]),
RotationState::U => spaces.extend_from_slice(&[
center.offset(0, 1),
center.offset(1, 0),
center.offset(-1, 1),
]),
RotationState::L => spaces.extend_from_slice(&[
center.offset(-1, -1),
center.offset(-1, 0),
center.offset(0, 1),
]),
},
TetrominoType::T => match self.rotation_state {
RotationState::O => spaces.extend_from_slice(&[
center.offset(0, -1),
center.offset(-1, 0),
center.offset(1, 0),
]),
RotationState::R => spaces.extend_from_slice(&[
center.offset(0, -1),
center.offset(0, 1),
center.offset(1, 0),
]),
RotationState::U => spaces.extend_from_slice(&[
center.offset(0, 1),
center.offset(-1, 0),
center.offset(1, 0),
]),
RotationState::L => spaces.extend_from_slice(&[
center.offset(0, -1),
center.offset(-1, 0),
center.offset(0, 1),
]),
},
TetrominoType::Z => match self.rotation_state {
RotationState::O => spaces.extend_from_slice(&[
center.offset(-1, -1),
center.offset(0, -1),
center.offset(1, 0),
]),
RotationState::R => spaces.extend_from_slice(&[
center.offset(1, -1),
center.offset(1, 0),
center.offset(0, 1),
]),
RotationState::U => spaces.extend_from_slice(&[
center.offset(-1, 0),
center.offset(0, 1),
center.offset(1, 1),
]),
RotationState::L => spaces.extend_from_slice(&[
center.offset(0, -1),
center.offset(-1, 0),
center.offset(-1, 1),
]),
},
}
spaces
}
pub fn rotate_left(&mut self) {
self.rotation_state = match self.rotation_state {
RotationState::O => RotationState::L,
RotationState::L => RotationState::U,
RotationState::U => RotationState::R,
RotationState::R => RotationState::O,
}
}
pub fn rotate_right(&mut self) {
self.rotation_state = match self.rotation_state {
RotationState::O => RotationState::R,
RotationState::R => RotationState::U,
RotationState::U => RotationState::L,
RotationState::L => RotationState::O,
}
}
}
impl From<TetrominoType> for Tetromino {
fn from(tetromino_type: TetrominoType) -> Self {
Self::new(tetromino_type)
}
}