Problem Solving Assignment 9
GameLogic.java
Overview
GameLogic.java is a static class that you will need to write. A static class
is a class that has NO instance variables. Therefore, EVERY
variable and method should be declared to be static.
Why is this a static class? Because in games especially we'd like to avoid
overhead calculations that could be taking away from animation or playability
Logic within tetris is pretty static (different instances of the same game should
in theory be doing the exact same things). Thus I used a static class to encapsulate
those ideas
The documentation description follows.
Static class that encapsulates almost all of the logic in the game.
Tetris logic can be broken into 2 parts. The part that moves the shapes and
looks for collisions, and the part that finds, removes, and lowers all of
the lines. This is an easier way to divide the problem between you and your
partner. The hardest methods are collisionDetect and moveRow. They are also
the crux of the game. I.E. You can't play tetris without those two methods.
The 11 methods that you're reponsible for are
Methods dealing with moving the piece:
Public:
- public static boolean moveShapeDown(int[][] theGame, TShape
currentShape)
- public static boolean moveShapeLeft(int[][] theGame, TShape
currentShape)
- public static boolean moveShapeRight(int[][] theGame, TShape
currentShape)
- public static boolean rotateCW(int[][] theGame, TShape currentShape)
- public static boolean rotateCCW(int[][] theGame, TShape
currentShape)
Private:
- private static boolean collisionDetect(int[][] theGame, TShape
currentShape)
- private static void moveShapeUp(int[][] theGame, TShape
currentShape)
Methods with finding, removing, and shifting lines:
Public:
- public static int findLines(int[][] theGame)
Private:
- private static boolean isEmptyLine(int lnum, int[][] theGame)
- private static boolean isFullLine(int lnum, int[][] theGame)
- private static void moveRow(int sourceRow, int targetRow, int[][]
theGame)
Methods that you need to write, and the descriptions that I had in mind:
Note that for any of the private methods, you can change the method names and parameters.
They are there to help you get the job done so you don't need to adhere to any sort of
form. But please adhere to the public method names.
What follows are the shape movement methods
public static boolean moveShapeDown(int[][] theGame, TShape currentShape)
/**
* This shifts the current shape down. You should call TShape's setPos
* method to move the piece down, then check for any collisions, if there
* are any collisions, you should reset the piece to the previous position.
*
* @param theGame 2D array representation of the current game board
* @param currentShape TShape that is currently falling on the board
* @return boolean false if the piece is "set", else true
*/
public static boolean moveShapeLeft(int[][] theGame, TShape currentShape)
/**
* Moves the shape to the left. You should call TShape's setPos method
* to move the Piece to the left then check for any collisions, if there
* are any collisions, you should reset the piece to the previous position.
*
* @param theGame 2D array representation of the current game board
* @param currentShape TShape that is currently falling on the board
* @return boolean true if the shape could be put else false
*/
public static boolean moveShapeRight(int[][] theGame, TShape currentShape)
/**
* Moves the shape to the right. You should call TShape's setPos method
* to move the Piece to the right then check for any collisions, if there
* are any collisions, you should reset the piece to the previous position.
*
* @param theGame 2D array representation of the current game board
* @param currentShape TShape that is currently falling on the board
* @return boolean true if the shape could be put else false
*/
public static boolean rotateCW(int[][] theGame, TShape currentShape)
/**
* Rotates the piece clockwise. You should call TShape's rotateCW method to
* rotate the piece then check for any collisions, if there
* are any collisions, you should reset the piece to the previous position.
*
* @param theGame 2D array representation of the current game board
* @param currentShape TShape that is currently falling on the board
* @return boolean true if the shape could be put else false
*/
public static boolean rotateCCW(int[][] theGame, TShape currentShape)
/**
* Rotates the piece counter clockwise. You should call TShape's rotateCCW
* method to rotate the piece then check for any collisions, if there
* are any collisions, you should reset the piece to the previous position.
*
* @param theGame 2D array representation of the current game board
* @param currentShape TShape that is currently falling on the board
* @return boolean true if the shape could be put else false
*/
public static boolean newShape(int[][] theGame, TShape currentShape)
/**
* Gets a new shape and tries to put it onto the screen
*
* @param theGame 2D array representation of the current game board
* @param currentShape TShape that is currently tried to be placed on
* the board, it's position has already been set to the position that
* it want's to be put on
* @return true for no collisions detected when trying to put the
* pieceon the screen (not game over) false for collision detected
* on the screen (game over)
*/
private static boolean collisionDetect(int[][] theGame, TShape currentShape)
/**
* Detects any collisions with other blocks or the edges of the game board.
* You'll need to check for collisions with other blocks, the left edge of
* the board, the right edge of the board, and the bottom of the board. To be
* safe you may want to check for collisions with the top of the board, but
* isn't necessary as in a real game, you shouldn't be able the move the piece
* up.
*
* @param theGame 2D array representation of the current game board
* @param currentShape TShape that is currently falling on the board
* @return boolean true for a collision, boolean false for no collision
* detected
*/
private static void moveShapeUp(int[][] theGame, TShape currentShape)
/**
* This shifts the current shape up, this should only be called on an unsuccessful
* moveBlockDown call
*
* @param theGame 2D array representation of the current game board
* @param currentShape TShape that is currently falling on the board
*/
What follows are the line logic methods
public static int findLines(int[][] theGame)
/**
* This finds all Full Lines and sets them to 0. The Easiest way to achieve this is to
* loop through the entire array and look for full lines (any row that is ALL non
* zero). And then after finding a full row, to zero it out by going back through
* the row, setting every entry to zero. It's recommended to write a helper method
* isFullLine(int row) which looks to see if a particular row is full and simply
* call that on every row, zeroing out the row if you find one.
*
* Finally, calculate the score however you want. The game is currently designed to
* gain a level every 10 lines. you can change this at will.
*
* @param theGame int[][] representing the game
* @return a score based on the number of filled lines
*/
public static void moveRows(int sourceRow, int targetRow, int[][] theGame)
/**
* A helper method for shiftLinesDown. Moves blocks and spaces from a source row to a target row,
* replacing what is in the target row and leaving the source row blank.
*
* @param sourceRow the row number to move blocks from
* @param targetRow the row number to move blocks to
* @param theGame int[][] representing the game
*/
private boolean isEmptyLine(int lnum, int[][] theGame)
/**
* A helper method to help with the line shifting. If every entry in the row lnum (theGame[i][lnum] for i
* in 0 to theGame.length) is 0 then it is considered an empty line. The easier thing is to take the
* compliment. If ANY entry in the row lnum is NOT 0 then it is NOT an empty line.
*
* @param lnum the line number to test for emptiness
* @param theGame int[][] representing the game
* @return a boolean true if the line is full else false
*/
private boolean isFullLine(int lnum, int[][] theGame)
/**
* A helper method to help with the line testing. If every entry in the row lnum
* (theGame[i][lnum] for i in 0 to theGame.length) is NOT 0 then it is considered
* a full line. The easier thing is to take the compliments. If ANY entry in the
* row lnum is 0 then it is NOT a full line
*
* @param lnum the line number to test for line fullness
* @param theGame int[][] representing the game
* @return a boolean true if the line is a full line else false
*/
As a start, here's the pseudocode for the findLines() method that I wrote:
score = 0
for i in 0 to theGame.height
do
if isFullLine(i) then
for j in 0 to theGame.width
do
theGame(i, j) = 0
done
done
if(score >= 4) score += score/4 //bonus every 4 lines
return score
Some Hints:
- A lot of the methods are minor modifications of one another. The general algorithm for them is to
move the piece, check for collisions, if collisions are detected then move the shape back to where it was
- rotateCW and rotateCCW are already (more or less) written for you in TShape as rotations can be a little
tricky and warrant almost no learning value at all. If you're curious about how to rotate the piece, you can
look in TShape. You should simply call the rotateCW and rotateCCW found in TShape.
- I've written a small main method within the class to help you test it a little easier. I've given you a small
demonstration of what the test code could look like.