Electronic handin will be available Mon, Nov 23.
In this assignment, you will implement a basic version of the game of Tetris.
DOWNLOAD THE FOLLOWING JAVA PROJECT: Tetris.zip
This Java project contains the starting code for your Tetris game.
Refer to Program 9 for documentation for the following classes: Location, Color, Grid
The Game class represents a game of Tetris. It has three fields: one holds a reference to the Grid used for the game, another holds a reference to the current Block falling from the sky, and the third field is a boolean variable to determine when the game is over. The game of Tetris consists of a 20 × 10 grid of squares.
A block has three fields: a reference to the grid that it appears in, its color and an array holding the locations (on the grid) of the squares of that make up the block.
When a block is constructed using its constructor, it assumes one of 3 shapes (arrangements of squares) at random. Note how for each shape, we have to create an array of Location to hold the locations of the squares of the block, and then we initialize the array with the initial locations of the 3 or 4 square for the block, depending on its shape.
Complete drawSelf method of the Block class so that it sets the colors of the block's locations in the grid to be the given color. For example, if the given color is magenta and locs contains (0, 4), then set the color of the grid at location (0, 4) to be magenta. (Of course, you'll need to do this for every location in locs.) NOTE: Remember that the block might have 3 or 4 (or some other number of) locations so you should write this method so it works in general for any shape.
The main method is in the Game class. Run the program several times and you should see one of the following three screens:
Shapes for Tetris: shapeNum = 0 (left), shapeNum = 1 (center), shapeNum = 2
(right)
The drawSelf method is called from the revealSelf method that draws the block only if the locations of the block are on the grid and are black (i.e. valid and empty). Complete areValidAndEmpty method of the Block class so that it returns true only if all of the given locations are valid (on the grid) and empty (black), false otherwise.
Complete the shift method in the Block class, which should attempt to move this block deltaRow rows down and deltaCol columns to the right. For example, a deltaRow of 2 and a deltaCol of -1 would be used to shift this block 2 rows down and 1 column to the left. Implement shift as follows:
In the Game class, the play method has a loop that checks the last key pressed to see which way we want to move the current block. The key is an integer that is initialized based on the key pressed:
KEY VALUE KEY PRESSED 37 left arrow 38 up arrow 39 right arrow 40 down arrow
Where the comment says "left arrow pressed", call the current block's shift method to move block one column to the left. Do likewise for "right" and "down". (Ignore the "up" case for now.)
Run your code, and test that you can now move the block around with the arrow keys. Make sure that your code prevents you from moving the block off the screen.
Complete the rotate method of the Block class, which should attempt to rotate the shape clockwise by 90 degrees around locs[0]. Given a square at location (row, col), there is a simple formula to find its new location (row', col'), following a 90 degree clockwise rotation about the square at (row0, col0):
row' = row0 + col - col0
col' = col0 + row0 - row
Other than this calculation, your code for rotate should be nearly identical to the code you wrote for shift (except that rotate shouldn't return a value).
Modify the play method in the Game class so that it calls rotate whenever the "up" arrow is pressed. Test that you can now rotate a block (when it has room to rotate).
In play method, inside the while loop, after the for loop, call the shift method to move block down one row. Test that the block now falls automatically every half-a-second, until it reaches the bottom.
Modify the play method of the Game class to test the value returned by the call to shift that you just inserted in the previous step. If the shift was unsuccessful, then we know the block cannot fall any further. In this case, create a new Block and store a reference to it in the block field. Make sure you call the revealSelf method on this block so it appears. Test that, whenever a block cannot fall any further, a new block appears at the top. You should now be able to play a simple game of Tetris (except that completed rows will not disappear).
Complete isCompletedRow method, which should return true if there are no black squares in the given row.
Next, complete the removeSquare method in the Game class, which should remove the square at the given location, by shifting each of the colors above it down one row, and setting the location at the top of the column to black. For example, removing the square on the grid at (3, 5) should first copy the color from (2, 5) into (3, 5), and then copy the color from (1, 5) into (2, 5), and then copy the color from (0, 5) into (1, 5), and finally set the color of (0, 5) to black.
Then, complete the removeRow method of the Game class, which should call removeSquare to remove every square in the given row.
Finally, complete the removeCompletedRows method, which should remove all completed rows. Modify the play method, so that every time a block can no longer shift down, you remove all completed rows before creating a new block. Test your program now, and you should be able to play a regular game of Tetris, except that it will never end.
Modify the play method so that when a new block is created, if the block cannot reveal itself (since it is on top of another block), the game is over. Now you have your final version of Tetris!
You may add additional features to the game if you wish (e.g. scoring, additional shapes, new key actions, faster falling as the game goes on, etc.), but you must have the basic core as described above to get full credit for your program.
Make sure you save your work often as you progress so you don't lose a lot of hard work by accident. At each stage of the program development, do the suggested testing thoroughly, looking for odd behavior. If necessary, print information to the console window as your grade plays so you can trace what's happening in the code.
As usual, your code should be well documented and should demonstrate proper Java formatting style. Be sure to name your variables appropriately and indent properly.
See the course website for instructions on how to hand in your program. Please zip your project folder that is created in Eclipse. This makes it easier for us to grade your work.
Remember that the work you submit must be your own. Also, late hand-ins are not accepted. Please plan ahead and submit early to avoid server overload at the deadline. The deadline is based on the server's clock, not your clock. Please do not email your code to your instructor or course assistant as your official hand-in; these will not be graded.