161 lines
5 KiB
Rust
161 lines
5 KiB
Rust
use crate::playfield::PlayField;
|
|
use crate::tetromino::{Position, RotationState, TetrominoType};
|
|
use std::collections::HashMap;
|
|
|
|
pub trait RotationSystem {
|
|
fn default() -> Self;
|
|
|
|
fn rotate_left(&self, playfield: &PlayField) -> Result<Position, ()>;
|
|
|
|
fn rotate_right(&self, playfield: &PlayField) -> Result<Position, ()>;
|
|
}
|
|
|
|
#[derive(Clone)]
|
|
pub struct SRS {
|
|
jlstz_offset_data: HashMap<RotationState, Vec<Position>>,
|
|
i_offset_data: HashMap<RotationState, Vec<Position>>,
|
|
o_offset_data: HashMap<RotationState, Vec<Position>>,
|
|
}
|
|
|
|
enum RotationDirection {
|
|
Left,
|
|
Right,
|
|
}
|
|
|
|
impl SRS {
|
|
fn rotate_common(
|
|
&self,
|
|
playfield: &PlayField,
|
|
rotation: RotationDirection,
|
|
) -> Result<Position, ()> {
|
|
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)
|
|
.is_none()
|
|
{
|
|
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<Position, ()> {
|
|
self.rotate_common(playfield, RotationDirection::Left)
|
|
}
|
|
|
|
fn rotate_right(&self, playfield: &PlayField) -> Result<Position, ()> {
|
|
self.rotate_common(playfield, RotationDirection::Right)
|
|
}
|
|
}
|