Add input::drop(), shift() operations
This commit is contained in:
parent
eebbde71b9
commit
c5f7d9d622
|
@ -1,7 +1,18 @@
|
|||
//! Data structures and operations for game inputs, particularly ones that induce
|
||||
//! movements to the current piece.
|
||||
|
||||
use crate::piece::Rot;
|
||||
use crate::matrix::Mat;
|
||||
use crate::piece::{Piece, Rot, Shape};
|
||||
|
||||
/// Represents a direction of horizontal movement.
|
||||
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug)]
|
||||
#[repr(i16)]
|
||||
pub enum Horizontal {
|
||||
/// Left.
|
||||
Left = -1,
|
||||
/// Right.
|
||||
Right = 1,
|
||||
}
|
||||
|
||||
/// Represents a rotating operation. Includes 180 degree "flips", which are non-standard
|
||||
/// for tetris but exist in many unofficial iterations of the game.
|
||||
|
@ -37,9 +48,55 @@ impl core::ops::AddAssign<Spin> for Rot {
|
|||
}
|
||||
}
|
||||
|
||||
/// Drops `piece` until it hits `mat`. Returns true if the piece fell at least one block.
|
||||
pub fn drop<'c, S>(piece: &mut Piece<S>, mat: &Mat) -> bool
|
||||
where
|
||||
S: Shape<'c>,
|
||||
{
|
||||
let mut cells = piece.cells();
|
||||
let mut did_fall = false;
|
||||
|
||||
// XXX(iitalics): optimization: if piece is above the top of the matrix, then
|
||||
// immediately drop it to the row containing data since all space above that is
|
||||
// guarunteed unoccupied.
|
||||
let y0 = cells.extents().1.start;
|
||||
if y0 > mat.rows() {
|
||||
let dy = mat.rows() - y0;
|
||||
cells = cells.translate(0, dy);
|
||||
piece.loc.y += dy;
|
||||
did_fall = true;
|
||||
}
|
||||
|
||||
loop {
|
||||
cells = cells.translate(0, -1);
|
||||
if cells.intersects(mat) {
|
||||
break;
|
||||
}
|
||||
piece.loc.y -= 1;
|
||||
did_fall = true;
|
||||
}
|
||||
did_fall
|
||||
}
|
||||
|
||||
/// Moves a piece horizontally. Returns true if it successfully shifted the piece.
|
||||
pub fn shift<'c, S>(piece: &mut Piece<S>, mat: &Mat, dir: Horizontal) -> bool
|
||||
where
|
||||
S: Shape<'c>,
|
||||
{
|
||||
let dx = dir as i16;
|
||||
if !piece.cells().translate(dx, 0).intersects(mat) {
|
||||
piece.loc.x += dx;
|
||||
return true;
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
use crate::mat;
|
||||
use crate::piece::test::Tri;
|
||||
use crate::piece::Loc;
|
||||
|
||||
#[test]
|
||||
fn test_angle_rotate() {
|
||||
|
@ -62,4 +119,64 @@ mod test {
|
|||
r += Ccw;
|
||||
assert_eq!(r, W);
|
||||
}
|
||||
|
||||
const MAT: &Mat = mat! {
|
||||
".........x";
|
||||
"..x.....xx";
|
||||
"xxx.xxx.xx";
|
||||
};
|
||||
|
||||
fn drop(x: i16, y: i16, r: Rot) -> i16 {
|
||||
let mut piece = Piece {
|
||||
shape: Tri,
|
||||
loc: Loc { x, y, r },
|
||||
};
|
||||
let did_fall = super::drop(&mut piece, MAT);
|
||||
assert_eq!(piece.loc.x, x);
|
||||
assert_eq!(did_fall, piece.loc.y != y, "{},{}", piece.loc.y, y);
|
||||
piece.loc.y
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_drop() {
|
||||
assert_eq!(drop(3, 2, Rot::N), 1);
|
||||
assert_eq!(drop(3, 8, Rot::N), 1);
|
||||
assert_eq!(drop(3, 1, Rot::N), 1);
|
||||
assert_eq!(drop(3, 8, Rot::E), 1);
|
||||
assert_eq!(drop(3, 1, Rot::E), 1);
|
||||
assert_eq!(drop(4, 8, Rot::E), 2);
|
||||
assert_eq!(drop(4, 2, Rot::E), 2);
|
||||
assert_eq!(drop(3, 8, Rot::S), 2);
|
||||
assert_eq!(drop(3, 2, Rot::S), 2);
|
||||
assert_eq!(drop(9, 8, Rot::W), 3);
|
||||
assert_eq!(drop(9, 4, Rot::W), 3);
|
||||
assert_eq!(drop(9, 3, Rot::W), 3);
|
||||
assert_eq!(drop(9, 8, Rot::S), 4);
|
||||
assert_eq!(drop(9, 5, Rot::S), 4);
|
||||
assert_eq!(drop(9, 4, Rot::S), 4);
|
||||
}
|
||||
|
||||
fn shift(x: i16, y: i16, r: Rot, dir: Horizontal) -> i16 {
|
||||
let mut piece = Piece {
|
||||
shape: Tri,
|
||||
loc: Loc { x, y, r },
|
||||
};
|
||||
let did_shift = super::shift(&mut piece, MAT, dir);
|
||||
assert_eq!(piece.loc.y, y);
|
||||
assert_eq!(did_shift, piece.loc.x != x, "{},{}", piece.loc.x, x);
|
||||
piece.loc.x
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_shift() {
|
||||
use Horizontal::*;
|
||||
assert_eq!(shift(0, 1, Rot::N, Left), 0);
|
||||
assert_eq!(shift(0, 1, Rot::N, Right), 0);
|
||||
assert_eq!(shift(0, 2, Rot::N, Left), 0);
|
||||
assert_eq!(shift(0, 2, Rot::N, Right), 1);
|
||||
assert_eq!(shift(1, 2, Rot::N, Left), 0);
|
||||
assert_eq!(shift(1, 2, Rot::N, Right), 2);
|
||||
assert_eq!(shift(3, 1, Rot::E, Left), 3);
|
||||
assert_eq!(shift(3, 1, Rot::E, Right), 3);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -191,7 +191,7 @@ pub mod test {
|
|||
// .XX origin at (1,1)
|
||||
// ...
|
||||
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
|
||||
struct Tri;
|
||||
pub struct Tri;
|
||||
|
||||
impl Shape<'static> for Tri {
|
||||
fn cells(&self, rot: Rot) -> Cells<'static> {
|
||||
|
|
Loading…
Reference in New Issue