Now that the piece can move, we should try rotation. Given the hard-coded initial state of having T piece at (5, 17)
and a block at (0, 0)
, here’s the spec:
s2"""
Rotating the current piece should
change the blocks in the view. $rotate1
"""
...
def rotate1 =
rotateCW(s1).blocks map {_.pos} must contain(exactly(
(0, 0), (5, 18), (5, 17), (5, 16), (6, 17)
)).inOrder
This shouldn’t even compile because Stage
class doesn’t have rotateCW()
method yet.
[error] /Users/eed3si9n/work/tetrix.scala/library/src/test/scala/StageSpec.scala:33: value rorateCCW is not a member of com.eed3si9n.tetrix.Stage
[error] stage.rotateCW().view.blocks map {_.pos} must contain(
[error] ^
[error] one error found
[error] (library/test:compile) Compilation failed
Stub it out:
def rotateCW() = this
and we’re back to a failing test case.
First, we implement the rotation at the piece level:
def rotateBy(theta: Double): Piece = {
val c = math.cos(theta)
val s = math.sin(theta)
def roundToHalf(v: (Double, Double)): (Double, Double) =
(math.round(v._1 * 2.0) * 0.5, math.round(v._2 * 2.0) * 0.5)
copy(locals = locals map { case(x, y) => (x * c - y * s, x * s + y * c) } map roundToHalf)
}
And then we copy-paste (!) the moveBy
method and make it into rotateBy
:
def rotateCW() = rotateBy(-math.Pi / 2.0)
private[this] def rotateBy(theta: Double): this.type = {
validate(
currentPiece.rotateBy(theta),
unload(currentPiece, blocks)) map { case (moved, unloaded) =>
blocks = load(moved, unloaded)
currentPiece = moved
}
this
}
This now passes the test:
[info] Rotating the current piece should
[info] + change the blocks in the view.