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 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 { self.get_occupied_spaces(self.position.offset(0, 1)) } pub fn get_cur_occupied_spaces(&self) -> Vec { self.get_occupied_spaces(self.position) } pub fn get_occupied_spaces(&self, center: Position) -> Vec { 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 for Tetromino { fn from(tetromino_type: TetrominoType) -> Self { Self::new(tetromino_type) } }