307 lines
9.9 KiB
Rust
307 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)
|
|
}
|
|
}
|