detectTSpin method
Classifies a T piece that has just been rotated into place using the Guideline 3-corner rule.
kickIndex is the kick test used by the last rotation; a T-Spin that
needed the final kick (e.g. a T-Spin Triple setup) always counts as full.
Walls and floor count as occupied corners.
Implementation
TSpinType detectTSpin(
Tetromino piece,
BoardState board, {
int kickIndex = 0,
}) {
if (piece.type != TetrominoType.T) return TSpinType.none;
bool occupied(int dr, int dc) {
final r = piece.position.row + dr;
final c = piece.position.col + dc;
if (r < 0 || r >= board.rows || c < 0 || c >= board.cols) return true;
return board.cellAt(r, c).filled;
}
// Corners around the T's center cell at offset (1, 1).
final topLeft = occupied(0, 0);
final topRight = occupied(0, 2);
final bottomLeft = occupied(2, 0);
final bottomRight = occupied(2, 2);
final count = [
topLeft,
topRight,
bottomLeft,
bottomRight,
].where((c) => c).length;
if (count < 3) return TSpinType.none;
// The two corners on the side the T is pointing towards.
final (frontA, frontB) = switch (piece.rotation % 4) {
0 => (topLeft, topRight),
1 => (topRight, bottomRight),
2 => (bottomLeft, bottomRight),
_ => (topLeft, bottomLeft),
};
if ((frontA && frontB) || kickIndex == 4) return TSpinType.full;
return TSpinType.mini;
}