The basic portion of this final test program is a simple variant of the tetris game that we will call LineTris. The only real difference from tetris is that all of the pieces are the same shape. They are composed of four squares arranged vertically. When the game is played, pieces appear at the top of a playing field (like the field in Nibbles) and drop until they reach they reach the bottom of the field or until they are blocked by a piece that has fallen earlier. When a row of the field is completely filled then all of the squares in the row are deleted and all cells above that row fall exactly one row.
The user can control the way the piece falls by pressing the left or right arrow keys to move it from side to side or by pressing the up arrow to rotate it clockwise or the down arrow to rotate it counter-clockwise.
A runnable version of the game is shown below:
Your task is to design and implement a Java program to play LineTris. The program should present the user with a window that includes the playing field and should start the first piece falling.
The playing field has 30 rows and 10 columns. Each piece should start falling from the top of the playing field in the 5th column. The piece should make a move every 200 milliseconds.
When it is time to move, the piece is first erased from its current position.
Then the new position is determined by any keypresses that have occurred since its last move: If the up or down arrow keys have been pressed, the program should compute (in a temporary array) the new locations that the piece should occupy. It should then determine if those locations are legal (i.e., on the field and not occupied squares). If so, then the position of the piece should be updated, though the piece should not yet be added back to the field.
Then if the left or right arrow keys have been pressed, the program should compute the new locations that the piece would occupy. It should then determine if those locations are legal. If so, then the position should be updated (but again, don't add the piece back to the field).
Finally, the program should determine if the piece can move down one cell by computing the new positions and determining if they are legal. If so, the position should be updated. After all of this, the piece is inserted back into the playing field in its new position. If the piece bumps into an occupied cell while falling, it should stop moving, and a new piece should be created to fall once more. If a piece bumps into an occupied cell when rotating or shifting left or right, it does not stop the piece from falling.
When the new piece that is created starts in a cell that is already occupied then the game is over. The program should then report (either in a text object on the canvas or in a label at the bottom of the window) the number of pieces that were dropped before the game ended.
The above describes the base functionality for the program. The maximum score possible by implementing this base functionality is 90 points. You can earn final 10 points (and in fact, a few bonus points on top of that) by implementing some extended functionality. Some suggestions for this extended functionality are included in the "Advanced Features" section later in this document.
To implement this program you will need to write the following classes:
This is your WindowController class. It should set up the game and respond to keypress events. We have provided most of the functionality required. You must include the code for the startPiece() method, which should create a new piece and start it falling when the game begins.
This class represents the playing field. It is very similar to that provided for the "Nibbles" lab. The public methods include the following methods:
public void addItem (Position pos, Color theColor) public void removeItem (Position pos) public boolean isOccupied(Position pos) public boolean outOfBounds(Position pos)
You need to write the method removeRows(). It should sweep through the rows of the field, from top to bottom. If a row is found that is filled (i.e., no nulls) then that row should be removed and all of the pieces above that row should be dropped down by one row. We suggest using private methods to help you understand and code this. Think of it first in a high level way and separate the activities of finding a full row, removing all of the elements of that row, and dropping the pieces above that row.
This class represents positions on the field. Methods include getRow() and getCol(). It is the same as the class provided for Nibbles, and is provided for you.
This is the most important class in this program. It is an ActiveObject whose constructor creates a new piece on the board and whose run method moves the piece down the board. The positions of the squares in the piece should be kept in an instance variable that will be an array. All pieces start out in the same place on the field, and begin falling immediately.
We have included some private helper methods that you should find useful. The method moveToNewPositions should be called repeatedly in the run method to move the piece to its next position. It first should remove the piece from the field in preparation for a move to a new position. If a key press has occurred to rotate the piece or to move it sideways, then the program should create a new array that will hold the new positions the piece would be in if it were a legal move. It should then check to see if the new positions are legal, and, if so, update the piece to hold those new positions.
Then the method should attempt to move the piece down one row by creating a new array of positions representing where the piece would move to. If those are legal then it should update the piece to hold those new positions. At this point the piece should be added back to the field, whether it has successfully moved or not.
We have included the code for method tryRotate as an example to help you see how the code for moving left or right and the code for moving the piece down can look. You are responsible for writing the rest of that code as well as the code to check that an array holding the new positions represents a legal move (i.e., is on the board and does not overlap with other filled positions on the board).
When the piece would fall down to the bottom of the field or to a position where it overlaps with an occupied cell, the piece should stop moving. The last thing that should occur in the run method is that a new piece should be generated, which will again start falling.
As indicated in the heading of this document, you will need to turn in a design for your LineTris program well before the program itself. You should keep a copy for yourself as we will not hand the design back until after the complete program is graded. This design should be a clear and concise description of your planned organization of the program.
You should include in your design a sketch of each class including the types and names of all instance variables you plan to use, and the headers of all methods you expect to write. You should write a brief description of the purpose/function of each instance variable and method.
In addition, you should provide pseudocode for any method whose implementation is at all complicated. In particular, if a method is complicated enough that it will invoke other methods you write (rather than invoking methods provided by Java or by our library), then include pseudocode for the method so that we will see how you expect to use your own methods.
Your design should include all of the base functionality. It need not include the enhanced functionality.
There are many ways you could approach this problem. Here is one possible plan of attack:
Do not worry if you cannot implement all of the functionality. Get as much of it working as you can. At the end of this handout we have included the grading guidelines for this test program. You should note the large number of points assigned to issues of style. It is always best to have full functionality, but you are better off having most of the functionality and a beautifully organized program than all of the functionality with a program that is sloppy, poorly commented, etc.
As you can see in the grading guidelines at the end of this handout, the base functionality described above can earn at most 90 points. To earn the last 10 points (and possibly a few bonus points) you will need to implement a number of extra features.
Important: include a comment at the top of your LineTris program that describes any advanced features you would like us to consider when grading your program.
Here are some possibilities. Feel free to invent your own enhancements, but see one of us first.
This test program should be treated like an open-book take-home examination, as described in the Academic Honesty Guidelines handed out at the beginning of the semester. You may consult your text, your notes, your lab work, or the code provided in human readable form in our on-line examples, but use of any other source for code is forbidden. Any questions you have regarding this assignment or the particulars of your program should be addressed only to an instructor. The TA's can only answer questions involving incorrect functioning of your computer or Java compiler. When in doubt, they will refer you to an instructor.
Please turn in a printed copy of your design document (worth 10% of the grade) at the beginning of your lecture section on Wednesday, April 29. To get full credit, the design document should include all of the basic game features. However, partial credit will be given for designs that include fewer features. The final program is due at 4 PM on Wednesday, May 6. You should turn in the program as usual by creating a folder that includes your name and the phrase "Test Program 2 - LineTris" and depositing it in the dropoff folder for the course.
Good luck and have fun!
Grading Point AllocationsValue | Feature |
Design preparation (10 points total) | |
2 points | Variable and constant names and types |
2 points | Method signatures |
2 points | English descriptions |
2 points | Pseudocode |
2 points | Plausibility |
Code Quality (38 points total) | |
6 points | Descriptive and helpful comments |
2 points | Good names |
2 points | Good use of constants |
2 points | Appropriate formatting |
2 points | Appropriate use of public/private qualifiers |
4 points | Conditionals and loops |
10 points | Parameters, variables, and scoping |
10 points | Appropriate public/private methods for each class |
Efficiency (4 points) | |
Basic Piece Functionality (22 points total) | |
4 points | Creation of one piece |
6 points | One piece falls correctly |
4 points | Creation of subsequent pieces |
4 points | Piece stops when it encounters an obstacle |
4 points | Shifting of pieces left and right |
Basic LineTris Functionality (16 points total) | |
6 points | Remove a filled row correctly |
4 points | Move rows down when a filled row is removed |
4 points | Detect end of game |
2 points | Maintain and report count of pieces fallen |
Advanced Functionality (maximum of 12 points total) | |
5 points | Real tetris pieces |
1 point | Space bar drops piece immediately |
1 point | GUI "New Game" button |
1 point | GUI "Level of difficulty" selection (affecting speed) |
2 points | Running display of pieces dropped and/or rows removed |
2 points | Pieces fall faster as more rows are removed |
2 points | Allow multiple rotations/shifts on each "row drop" |
? points | check with us if you have other ideas for advanced features |