Lab | Assigned | Design Due (Mondays 2 PM) |
Lab Due (Fridays 2 PM) |
|||
---|---|---|---|---|---|---|
16 | Apr | None | 26 | Apr (No late coupon) |
Zip includes:
Remember to type the following lines at the top of any files that use the terminal or canvas classes.
import cs101.terminal.*; import cs101.canvas.*;
The design of this lab is somewhat different than Lab 10. The notion of a Side is gone. The reason is that the tetris pieces will occupy space on a grid-like canvas. It is therefore the area of the squares that count, and not the inducing vector.
Thus, pieces are constructed differently than before. For examples, take a look at TetrisGamma and its antimatter twin TetrisAmmag. You will have to construct the other Tetris pieces yourself.
This document describes the design without telling you the coding details. That is, the overall structure of the solution is given, but actual code is provided by you.
It is helpful to think of a tetris shape as if it were constructed of squares that are glued together:
![]() |
![]() |
Above, you see a tetris piece (the Gamma piece, named for the shape of the Greek letter) in outline form, as you would see the piece when you play. | Above, you see how the piece is constructed
using four square blocks. Check out the constructor in
TetrisGamma.java .
You see that
one of the square blocks is distinguished. It is the main component,
an instance of |
A Tetris piece is constructed by gluing TetrisBlock
s together.
When
block B is glued to block A, block B must follow block A around,
wherever A might go. When block B is glued to block A, block B is told
its offset, grid-wise, from block A.
When a TetrisBlock
moves around, so must the blocks glued to it. The blocks glued to it
are listeners.
Since a block has four sides, it can have at most four listeners.
You will keep track of a block's listeners using an array .
A block is moved by calling its moved
method. That block, in turn, must call its listeners' moved
methods.
A block is rotated by calling its rotated
method.
That block, in turn, must call its listeners' rotated
methods.
CS101CanvasGrid
To ease the placement of tetris shapes, you will extend
CS101Canvas
to
CS101CanvasGrid
, so that
the space can be regarded as a grid of rectangles,
each of which is occupied or not occupied.
Additionally, this kind of canvas is setup so that it can listen to
key presses and call methods based on them. The class can register an
ArrowListener
, so that
methods of the listener are called based on key presses as follows:
On some computers, for some windowing systems, the arrow keypresses may not be transmitted. Thus, each gesture is duplicated by a text key. The keys are chosen to mimic the intended direction, based on the number keys' arrangement on the numeric keypad of most keyboards. | |
Key Press | Method Called |
2 Down Arrow | down() |
4 Left Arrow | left() |
6 Right Arrow | right() |
8 Up Arrow | rotate() |
Since TetrisGame
controls
the game, it will want to register itself as the
ArrowListener
of its CS101CanvasGrid
.
Here is the API:
CS101CanvasGrid(int nc, int nr)
CS101Canvas
.
Then, a grid (two-dimensional array)
of GridSquare
s is
set up. Initially, all grid locations are unoccupied
except those at the extreme
left, right, and bottom of the canvas.
setOccupied(int i, int j, boolean val)
i
and
row j
is occupied (if val
is true)
or unoccupied (if val
is false).
boolean isOccupied(int i, int j)
i
and
row j
.
GridSquare
Rect
so that a rectangle can remember whether
it is occupied or not. In the extension, the following methods must be
provided:
GridSquare(int col, int row, int squaresize)
Rect
at the desired column and row.
Remember to convert from column and row to pixel coordinates, using the
supplied square size.
public void setOccupied(boolean val)
public boolean isOccupied()
Color.red
. When the rectangle is unoccupied, it
sets its color to Color.white
.
Startup
TetrisGame
.
You will need to add
selfTest
calls for any classes you add.
TetrisGame
curPiece
is the piece currently being manipulated on the
screen.
TetrisGame(int cols, int rows, int pieces)
pieces
parameter could be used
to limit the number of pieces offered in a game. If your game continues
indefinitely, you may choose to ignore this parameter.
TetrisPiece genPiece()
Math.random()
so that the pieces are randomly
and uniformly distributed.
Note that polymorphism allows a particular shape (TetrisGamma
,
TetrisTee
, etc.) to be treated as the generic
TetrisPiece
.
void advance()
If we used Java threads and concurrency, we could advance the piece down the screen automatically even if the user didn't do anything. This is what a real game would do, and you will learn about concurrency in CS 102.
TetrisGame
is an
ArrowListener
, it must
implement the methods in that interface:
void left()
void right()
void down()
void up()
TetrisBlock
TetrisBlock(leader, canvas, dX, dY)
leader
, offset in grid positions by dX
and dy
.
addListener(TetrisBlock listener)
For each of the following methods, once "this" TetrisBlock has performed its intended action, the block should invoke the same method on each of its listeners.
rotated()
dX
and
dY
must be adjusted, as discussed in class.
moved()
dX
and
dY
to its leader's coordinates.
allClear()
allClear
.
pickUp()
putDown()
TetrisPiece
TetrisBlock
.
TetrisPiece(CS101CanvasGrid canvas, int col, int row)
dX
and
dY
of 0. The column and row for "this" block is then
established as the parameters' values.
boolean proposeMove(int newCol, int newRow, int oldCol, int oldRow)
allClear
at the new
location.
TetrisPiece
(and therefore, on "this" TetrisBlock
)
are propagated to all blocks making up this piece.
exercise
abstract String name()
Each of the following actions,
called from TetrisGame
, can
be reduced to a call to proposeMove
. Each returns
true if the move is successful; otherwise, false is returned.
boolean moveLeft()
boolean moveRight()
boolean moveUp()
boolean moveDown()
Rotation requires a little more work. We have to try the rotation, and if it doesn't work out, then we have to unrotate the piece. Hint: You can unrotate a piece by rotating it three more times counterclockwise.
boolean rotateCounterClockwise()
dX
and dY
values.
allClear
at the new
location.
boolean rotateClockwise()
rotateCounterClockwise
.
Each of the
following objects extends
TetrisPIece.java
to obtain a particular kind of Tetris piece.
TetrisSquare
TetrisGamma
TetrisAmmag
TetrisGamma
TetrisTee
TetrisZigZag
TetrisGazGiz
TetrisZigZag
TetrisStraight