use crate::playfield::{Matrix, PlayField}; use crate::tetromino::{Position, RotationState, Tetromino, TetrominoType}; use std::collections::HashMap; pub trait RotationSystem { fn default() -> Self; fn rotate_left(&self, playfield: &PlayField) -> Result; fn rotate_right(&self, playfield: &PlayField) -> Result; } pub struct SRS { jlstz_offset_data: HashMap>, i_offset_data: HashMap>, o_offset_data: HashMap>, } enum RotationDirection { Left, Right, } impl SRS { fn rotate_common( &self, playfield: &PlayField, rotation: RotationDirection, ) -> Result { let active_piece = match playfield.active_piece { Some(piece) => piece, None => return Err(()), }; let offset_data = match active_piece.piece_type { TetrominoType::I => &self.i_offset_data, TetrominoType::O => &self.o_offset_data, _ => &self.jlstz_offset_data, }; let prev_offsets = offset_data.get(&active_piece.rotation_state).unwrap(); let mut test_tetromino = active_piece.clone(); match rotation { RotationDirection::Left => test_tetromino.rotate_left(), RotationDirection::Right => test_tetromino.rotate_right(), } let cur_offsets = offset_data.get(&test_tetromino.rotation_state).unwrap(); let mut offsets = Vec::with_capacity(cur_offsets.len()); for i in 0..cur_offsets.len() { offsets.push(prev_offsets[i] - cur_offsets[i]); } for offset in offsets { let x = offset.x; let y = offset.y; let test_position = active_piece.position.offset(x, y); test_tetromino.position = test_position; if playfield.can_piece_be_at_position(&test_tetromino) { return Ok(offset); } } Err(()) } } impl RotationSystem for SRS { fn default() -> Self { let mut jlstz_offset_data = HashMap::with_capacity(4); let mut i_offset_data = HashMap::with_capacity(4); let mut o_offset_data = HashMap::with_capacity(4); jlstz_offset_data.insert(RotationState::O, vec![Position { x: 0, y: 0 }].repeat(5)); jlstz_offset_data.insert( RotationState::R, vec![ Position { x: 0, y: 0 }, Position { x: 1, y: 0 }, Position { x: 1, y: 1 }, Position { x: 0, y: -2 }, Position { x: 1, y: -2 }, ], ); jlstz_offset_data.insert(RotationState::U, vec![Position { x: 0, y: 0 }].repeat(5)); jlstz_offset_data.insert( RotationState::L, vec![ Position { x: 0, y: 0 }, Position { x: -1, y: 0 }, Position { x: -1, y: 1 }, Position { x: 0, y: -2 }, Position { x: -1, y: -2 }, ], ); i_offset_data.insert( RotationState::O, vec![ Position { x: 0, y: 0 }, Position { x: -1, y: 0 }, Position { x: 2, y: 0 }, Position { x: -1, y: 0 }, Position { x: 2, y: 0 }, ], ); i_offset_data.insert( RotationState::R, vec![ Position { x: -1, y: 0 }, Position { x: 0, y: 0 }, Position { x: 0, y: 0 }, Position { x: 0, y: -1 }, Position { x: 0, y: 2 }, ], ); i_offset_data.insert( RotationState::U, vec![ Position { x: -1, y: -1 }, Position { x: 1, y: -1 }, Position { x: -2, y: -1 }, Position { x: 1, y: 0 }, Position { x: -2, y: 0 }, ], ); i_offset_data.insert( RotationState::L, vec![ Position { x: 0, y: -1 }, Position { x: 0, y: -1 }, Position { x: 0, y: -1 }, Position { x: 0, y: 1 }, Position { x: 0, y: -2 }, ], ); o_offset_data.insert(RotationState::O, vec![Position { x: 0, y: 0 }]); o_offset_data.insert(RotationState::R, vec![Position { x: 0, y: 1 }]); o_offset_data.insert(RotationState::U, vec![Position { x: -1, y: 1 }]); o_offset_data.insert(RotationState::L, vec![Position { x: -1, y: 0 }]); SRS { jlstz_offset_data, i_offset_data, o_offset_data, } } fn rotate_left(&self, playfield: &PlayField) -> Result { self.rotate_common(playfield, RotationDirection::Left) } fn rotate_right(&self, playfield: &PlayField) -> Result { self.rotate_common(playfield, RotationDirection::Right) } }