CS 101 (Spring 1999)
Lab 10: The Penultimate Tetris Lab

Lab Assigned Design Due
(Mondays 2 PM)
Lab Due
(Fridays 2 PM)
9 Apr 12 Apr 16 Apr


Overview:

Tetris: (click the name to play)

Goals:

By the end of this lab, you should This lab contains two parts, design and implementation, due on the dates shown above by 2 PM.

The design will be discussed Monday in class. In Lab, your graded design will be returned. No other handouts or code will be issued. So, think carefully about your design!


Before starting:

[[[ Download PC zip ]]]

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.*;

Particulars

Although this lab does not involve a lot of coding, it is tricky. In the design, you apply (high-school) algebra to simplify what must be done in the lab.

This lab will combine with the next lab to make a Tetris game. The division of work is as follows:

  1. In this lab, you analyze how to construct, translate (move), and rotate Tetris shapes.
  2. In the next lab, you give control to a player, who can manipulate the shapes by hand, while the computer continuously lowers the piece down the screen.

What makes a tetris shape?

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.

You see that one of the square blocks is distinguished; it is the main component, or the first block put down to form this piece. The entire piece is constructed of such blocks, glued together. When block A is glued to block B, block A must follow the joined side around, wherever that side of block A might go. Each block is added to the piece in this way.

When the main block moves or rotates, so do its sides. Any piece joined to a side that moves also moves, which moves its sides. By moving one block of the piece, the entire piece eventually moves.

So, each block follows its glued side around. Even the first block of a Tetris piece is glued to a special side, known as the root side of the tetris piece. The root is invisible, but movement of the root side causes the main block to move, which causes the entire piece to move, as described above.

Above you see another kind of tetris piece, the zigzag piece. Zigzag is also constructed from four blocks, but glued together differently from the first piece you saw.

In this discussion, suppose the blocks in the above piece are placed in the order A, B, C, D.

When a block is placed, it must be glued to some side. A side is essentially a vector, with a length and direction. Above, you see a vector to the left of the partially constructed block A. The vector runs from South to North.

The vector that induces block A is shown to the left of block A, but really the vector conincides exactly with side 0 of block A. The sides of a block are established as follows:

  • Side 0 is drawn as the reverse of the inducing vector.

    Above, you see that side 0 of block A is the reverse of its inducing vector.

  • The square is completed by placing three more sides, proceeding counterclockwise to complete the square.

All squares are drawn in this manner. Side 0 is the first side drawn, side 1 is the next side drawn, and so on.

Thus, picture above shows sides 0, 1, and 2 completed for block A. Side 3 would be drawn next, closing the square.

When block C is glued to block A, side 1 of block A is chosen as the inducing vector. Thus, C's side 0 is drawn as the reverse of A's side 1. The remaining sides of B are drawn by moving counterclockwise to complete the square.

The picture above shows blocks A and C separated by space, but really they would abut. Side 0 of C would coincide with side 1 of A.

The zigzag piece is completed by
  1. inducing block B at A's side 0.
  2. inducing block D at C's side 3.

How do you determine a square from the inducing side?


(covered in class)

The side that induces a block always coincides with the block's Side 0, except that the inducing side runs the opposite direction. Once Side 0 of a block is determined, the other sides are given, since they proceed counterclockwise, they are are all the same size, and they form the sides of a square.

Side 0 of a block will either be horizontal or vertical, and will either point East, West, North, or South. Let us assume the side is drawn from

(x,y) to (x+h, y+k).
For any given Side 0: In other words, Side 0 must be one of the following vectors:
North (x,y) to (x,y-s)
East (x,y) to (x+s,y)
South (x,y) to (x,y+s)
West (x,y) to (x-s,y)
Based on the particular value of h and k, we can compute the four sides as follows:
Side From To
0 (x,y) (x+h, y+k)
1 (x+h,y+k) (x+h+k, y+k-h)
2 (x+h+k,y+k-h) (x+k, y-h)
3 (x+k,y-h) (x, y)

How do we rotate a side?

Translating (moving) a side is simple: we can change the coordinates of the side's starting and ending points by displacement.

Rotation is trickier. To rotate a tetris piece, we must rotate the side that induces its main piece.

Above, you see an inducing side in its original state, and then taken through 3 rotations. A fourth rotation would return it to its original state. Although the rotations are shown separated by space, they would really abut so that each rotation moves the vector to another side of a square.

The letter s refers to the length of the side. Thus, the original vector goes from (x,y) to (x,y-s) on a CS101 Graphics Canvas, because the "y" coordinate increases as you move down the screen.

We need a function that tells a side how to move when it is rotated. One part is easy. Note that when a vector rotates, its new ending position is its old starting position. But what about the new starting position?

Previous Next
start.x start.y start.x start.y
x y x+s y
x+s y x+s y-s
x+s y-s x y-s
x y-s x y
Let's assume that it is possible to obtain the new starting point from the old one in some linear way. If so, then the following linear system of equations will determine the next start.x from the previous start.x and start.y:
      previous                    next
start.x    start.y               start.x 
  |           |
  |           |
  V           V

  x   a   +   y   b   +   c   =  x+s
(x+s) a   +   y   b   +   c   =  x+s
(x+s) a   + (y-s) b   +   c   =  x
  x   a   + (y-s) b   +   c   =  x
Similarly, we can formulate equations for the next start.y from the previous start.x and start.y:
      previous                    next
start.x    start.y               start.y
  |           |
  |           |
  V           V

  x   d   +   y   e   +   f   =  y
(x+s) d   +   y   e   +   f   =  y-s
(x+s) d   + (y-s) e   +   f   =  y-s
  x   d   + (y-s) e   +   f   =  y

The code:

Point
This class is given and is self-explanatory. You might take a look at the phrase final public that declares x and y instance variables.
Startup
Contains the usual testing calls. You will need to add selfTest calls for any classes you add.
Side
This class is used to represent a side of a block. A side can also be stand-alone, in which case it probably controls a Tetris piece and is invisible.
Constructors
Self-explanatory. Optionally, a canvas and color can be provided, in which case the side is drawn on the canvas. Otherwise, the side is invsibile.
void displace(int shiftX, int shiftY)
Shifts the side by the specified amount. This should be accomplished by the appropriate call to moveTo, so that the listener can be informed of the move.
void registerSideListener(TetrisBlock)
Establishes the supplied TetrisBlock as the object that should be informed, via its sideMoved, whenever this side moves.
void notifyListener()
If there is a listener for this side, notify it that the side has potentially moved.
moveTo(Point start, Point end)
Any motion of the side funnels through this method. The provided code does the following:
  • Updates the side's start and end.
  • If the CS101Canvas canvas is not null, then the line previously depicting this side is removed, should it exist. Then, a new line is added to the canvas to show the current location of this side.
  • Notify the listener that the side may have moved.
TetrisBlock
This class represents a block (square) that can be part of a Tetris piece. You have to set up the block as a listener to its inducing side. You also have to place the block's four sides, given the analysis in this document.
getSide(int)
returns a reference to the desired side (0, 1, 2, or 3). This is handy for obtaining a side to be an inducer for yet another TetrisBlock.
sideMoved()
is called by the inducing side whenever the side potentially moves. Thus, a TetrisBlock is a listener of its inducing side.
TetrisPiece
This is the base class for all Tetris pieces. The inducer instance variable is the inducing side.
Constructor
Creates a piece whose inducing side goes from (x,y) to (x,y-size). The values for a,b,c and d,e,f need to be captured here.
exercise
This exercises a piece, moving it, rotating it, and then randomly applying those transformations.
You will have to complete the methods that cause movement and rotation, updating the inducing side approprately. Notice that clockwise rotation is taken care of for you.

This class is abstract, and its subclasses must provide a name for the piece.

TetrisSquare
This is the simplest tetris piece imaginable---just a single block. This is provided as an example for you.

What to turn in:

Design (due Monday)
Important reminder: Collaborate as much as you like on the conceptual and design aspects of labs. You can work together to solve the equations, too. But the write-up you turn in is to be your own work. For more information, consult the course's collaboration policy
  1. Complete a design cover sheet.
  2. Draw the blocks that comprise the Gamma tetris piece, labelling each with a letter A, B, C, and D that show the order in which they are placed. Number the sides within each piece as described in this document.
  3. Discover another tetris piece (if necessary, use the game linked at the top of this document). Name the piece and show how it is constructed using the technique presented here.
  4. In class, you are shown the computation for forming the sides of Block A (for zigzag) given its inducing vector. If the inducing vector for block A is (100,100)->(100,50), show the computation for the sides of block C of zigzag. Above, you see that block C's inducing vector is A's side 1.
  5. Analyze the equations for rotating the inducing side and determine the values of a,b,c and d,e,f that satisfy the equation. You can probably do this by inspection with some substitution: the equations are not all that intricate.
Implementation (due Friday)
  1. Complete a code cover sheet.
  2. Provide a transcript from your self-tests.
  3. Complete the classes as described above.
  4. Complete TetrisZigZag and TetrisGamma to make the appropriate shapes.
  5. Provide a printout of any files you have modified.
  6. Be prepared to demo in lab.


Last modified 14:00:17 CDT 17 April 1999 by Ron K. Cytron