Add input::drop(), shift() operations

This commit is contained in:
tali 2022-12-14 10:59:41 -05:00
parent eebbde71b9
commit c5f7d9d622
2 changed files with 119 additions and 2 deletions

View File

@ -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);
}
}

View File

@ -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> {