Add input::rotate(), Kicks trait
This commit is contained in:
parent
c5f7d9d622
commit
6726326ec8
|
@ -48,6 +48,21 @@ impl core::ops::AddAssign<Spin> for Rot {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Interface for shapes that have a table of "kicks" to perform when checking if a
|
||||||
|
/// rotation is valid.
|
||||||
|
pub trait Kicks<'k> {
|
||||||
|
/// Returns the list of offsets to test when rotating from `r0` to `r1`. Offsets are
|
||||||
|
/// tested from left to right. If `r0` == `r1`, then this function is permitted to
|
||||||
|
/// return any list (incl. empty list) since that condition will never occur in
|
||||||
|
/// practice.
|
||||||
|
///
|
||||||
|
/// Note: `(0,0)` is not tested by default so it must be explicitly included if an
|
||||||
|
/// immobile test should be performed. In this implementation of SRS, the O piece
|
||||||
|
/// moves around an origin so its center must be corrected by a singular "kick" for
|
||||||
|
/// each rotation, thus the O piece never tests `(0,0)` during a rotation.
|
||||||
|
fn kicks(&self, r0: Rot, r1: Rot) -> &'k [(i16, i16)];
|
||||||
|
}
|
||||||
|
|
||||||
/// Drops `piece` until it hits `mat`. Returns true if the piece fell at least one block.
|
/// 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
|
pub fn drop<'c, S>(piece: &mut Piece<S>, mat: &Mat) -> bool
|
||||||
where
|
where
|
||||||
|
@ -91,6 +106,32 @@ where
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Rotates a piece, performing kicks to find a final location. Returns `Some(idx)` if
|
||||||
|
/// successful, where `idx` is the index into the kick table performed. Index `0` means it
|
||||||
|
/// was not kicked. Returns `None` if the rotation failed.
|
||||||
|
pub fn rotate<'c, 'k, S>(piece: &mut Piece<S>, mat: &Mat, dir: Spin) -> Option<usize>
|
||||||
|
where
|
||||||
|
S: Shape<'c> + Kicks<'k>,
|
||||||
|
{
|
||||||
|
let r0 = piece.loc.r;
|
||||||
|
let r1 = piece.loc.r + dir;
|
||||||
|
let kicks = piece.shape.kicks(r0, r1);
|
||||||
|
|
||||||
|
piece.loc.r = r1;
|
||||||
|
let cells = piece.cells();
|
||||||
|
|
||||||
|
for (i, &(dx, dy)) in kicks.iter().enumerate() {
|
||||||
|
if !cells.translate(dx, dy).intersects(mat) {
|
||||||
|
piece.loc.x += dx;
|
||||||
|
piece.loc.y += dy;
|
||||||
|
return Some(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
piece.loc.r = r0;
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
@ -179,4 +220,46 @@ mod test {
|
||||||
assert_eq!(shift(3, 1, Rot::E, Left), 3);
|
assert_eq!(shift(3, 1, Rot::E, Left), 3);
|
||||||
assert_eq!(shift(3, 1, Rot::E, Right), 3);
|
assert_eq!(shift(3, 1, Rot::E, Right), 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Kicks<'static> for Tri {
|
||||||
|
fn kicks(&self, r0: Rot, r1: Rot) -> &'static [(i16, i16)] {
|
||||||
|
match (r0, r1) {
|
||||||
|
(Rot::N, Rot::E) => &[(0, 0), (0, 1)],
|
||||||
|
(Rot::N, Rot::W) => &[(0, 0), (1, 0)],
|
||||||
|
(Rot::E, Rot::S) => &[(0, 0), (1, 0)],
|
||||||
|
(Rot::E, Rot::N) => &[(0, 0), (0, -1)],
|
||||||
|
(Rot::S, Rot::W) => &[(0, 0), (0, -1)],
|
||||||
|
(Rot::S, Rot::E) => &[(0, 0), (-1, 0)],
|
||||||
|
(Rot::W, Rot::N) => &[(0, 0), (-1, 0)],
|
||||||
|
(Rot::W, Rot::S) => &[(0, 0), (0, 1)],
|
||||||
|
(_, _) => &[(0, 0)], // flip or non rotation
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn rotate(x: i16, y: i16, r: Rot, dir: Spin) -> (i16, i16, Rot, Option<usize>) {
|
||||||
|
let loc = Loc { x, y, r };
|
||||||
|
let mut piece = Piece { shape: Tri, loc };
|
||||||
|
let result = super::rotate(&mut piece, MAT, dir);
|
||||||
|
assert_eq!(result.is_some(), piece.loc != loc, "{:?},{:?}", piece, loc);
|
||||||
|
(piece.loc.x, piece.loc.y, piece.loc.r, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_rotate() {
|
||||||
|
use Rot::*;
|
||||||
|
use Spin::*;
|
||||||
|
assert_eq!(rotate(3, 2, N, Cw), (3, 2, E, Some(0)));
|
||||||
|
assert_eq!(rotate(3, 2, E, Cw), (3, 2, S, Some(0)));
|
||||||
|
assert_eq!(rotate(3, 2, S, Cw), (3, 2, W, Some(0)));
|
||||||
|
assert_eq!(rotate(3, 2, W, Cw), (3, 2, N, Some(0)));
|
||||||
|
assert_eq!(rotate(3, 2, N, Ccw), (3, 2, W, Some(0)));
|
||||||
|
assert_eq!(rotate(3, 2, W, Ccw), (3, 2, S, Some(0)));
|
||||||
|
assert_eq!(rotate(3, 2, S, Ccw), (3, 2, E, Some(0)));
|
||||||
|
assert_eq!(rotate(3, 2, E, Ccw), (3, 2, N, Some(0)));
|
||||||
|
assert_eq!(rotate(7, 1, S, Cw), (7, 1, W, Some(0)));
|
||||||
|
assert_eq!(rotate(7, 1, S, Ccw), (7, 1, S, None)); // locked in
|
||||||
|
assert_eq!(rotate(0, 1, N, Ccw), (1, 1, W, Some(1))); // kicks right
|
||||||
|
assert_eq!(rotate(0, 1, N, Cw), (0, 2, E, Some(1))); // kicks up
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue