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:
Private:

Methods with finding, removing, and shifting lines:

Public:
Private:

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:

  1. 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
  2. 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.
  3. 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.