Tetris Applet Source Code

Applets are pretty much obsolete these days, but they can still be a good way to learn Java and coding. The following contains the code for a Tetris applet I made a long time ago in Eclipse.

But first, here’s a screenshot of the applet running:

If you don’t want to copy and paste the source code yourself, you can download a copy here for a small price (in the drop down menu under “Tetris Applet (source code)”):

Default Package:

TetrisMain.java

import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.geom.Rectangle2D;
import javax.swing.JApplet;
import javax.swing.Timer;
import pieces.PieceType;
@SuppressWarnings("serial")
public class TetrisMain extends JApplet implements KeyListener
{
  private Board board;
  private Rectangle2D back, scoreBoard;
  private Rectangle2D[][] squares, squaresNewPiece;
  private Color[][] oldColors;
  private Point[] oldPiecePoints, oldGhostPiecePoints;
  private PieceType oldNextPieceType;
  public static final int WIDTH = 240, HEIGHT = 480;
  private Timer timer;
  private boolean pauseMode, grid, pauseDisplay, lastPauseDisplay,
                  initialSetup, ghostPiece;
  private int oldLevel;
  private int oldScore;
  private int graphicsMode;
  public void init()
  {
    graphicsMode = 1;
    pauseDisplay = true;
    ghostPiece = false;
    grid = true;
    oldColors = new Color[Board.COLUMNS][Board.ROWS];
    oldPiecePoints = new Point[4];
    oldGhostPiecePoints = new Point[4];
    back = new Rectangle2D.Double(0, 0, WIDTH, HEIGHT);
    scoreBoard = new Rectangle2D.Double(20, 5, 115, 40);
    squares = new Rectangle2D[10][20];
    squaresNewPiece = new Rectangle2D[4][2];
    timer = new Timer(1000, new ActionListener(){
      public void actionPerformed(ActionEvent arg0)
      { board.moveDown(); repaint(); }});
    /*
     * Not sure if this is working.  Have to test it in a browser.
     */
    addFocusListener(new FocusListener(){
      @Override
      public void focusGained(FocusEvent arg0)
      { initialSetup = true; }
      @Override
      public void focusLost(FocusEvent arg0)
      {}});
    addComponentListener(new ComponentListener(){
      public void componentHidden(ComponentEvent arg0)
      {}
      @Override
      public void componentMoved(ComponentEvent arg0)
      {}
      @Override
      public void componentResized(ComponentEvent arg0)
      { initialSetup = true; }
      @Override
      public void componentShown(ComponentEvent arg0)
      {}});
    for (int x = 0; x < 10; x++)
    {
      for (int y = 0; y < 20; y++)
      {
        squares[x][y] = new Rectangle2D.Double(x * 20 + 20, y * 20 + 50, 20, 20);
      }
    }
    for (int x = 0; x < 4; x++)
    {
      for (int y = 0; y < 2; y++)
      {
        squaresNewPiece[x][y] = new Rectangle2D.Double(x * 20 + 140, y * 20 + 5, 20, 20);
      }
    }
    for (int x = 0; x < 4; x++)
    {
      oldPiecePoints[x] = new Point();
      oldGhostPiecePoints[x] = new Point();
    }
    setSize(WIDTH, HEIGHT);
    addKeyListener(this);
    setFocusable(true);
    newGame();
  }
  private void newGame()
  {
    pauseMode = false;
    initialSetup = true;
    board = new Board();
    timer.setDelay(1000);
    timer.start();
    for (int x = 0; x < 10; x++)
    {
      for (int y = 0; y < 20; y++)
      {
        oldColors[x][y] = Color.PINK;
      }
    }
  }
  public void paint(Graphics g)
  {
    final Graphics2D g2d = (Graphics2D) g;
    g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
    if (initialSetup)
    {
      initialSetup = false;
      g2d.setColor(new Color(125, 125, 125));
      g2d.fill(back);
      g2d.draw(back);
      oldLevel = 0;
      repaintBoard(g2d, true);
      repaintNextPieceDisplay(g2d, true);
      repaintPauseDisplay(g2d);
    }
    if (board.getLevel() != oldLevel || board.getScore() != oldScore)
    {
      oldLevel = board.getLevel();
      oldScore = board.getScore();
      int t = 1000;
      switch (board.getLevel())
      {
        case 2: t = 900;
          break;
        case 3: t = 800;
          break;
        case 4: t = 700;
          break;
        case 5: t = 600;
          break;
        case 6: t = 500;
          break;
        case 7: t = 400;
          break;
        case 8: t = 300;
          break;
        case 9: t = 200;
          break;
        case 10: t = 100;
      }
      timer.setDelay(t);
      g2d.setColor(Color.BLACK);
      g2d.fill(scoreBoard);
      g2d.draw(scoreBoard);
      g2d.setColor(Color.WHITE);
      g2d.setFont(new Font("TimesRoman", Font.PLAIN, 14));
      g2d.drawString("Level: " + board.getLevel(), 30, 22);
      g2d.drawString("Score: " + board.getScore(), 30, 38);
    }
    if (pauseMode)
    {
      g2d.setColor(Color.WHITE);
      g2d.setFont(new Font("TimesRoman", Font.PLAIN, 17));
      g2d.drawString("KEY", 105, 85);
      g2d.drawString("A/left = move left", 30, 125);
      g2d.drawString("D/right = move right", 30, 145);
      g2d.drawString("S/down = move down", 30, 165);
      g2d.drawString("W/Z/up = rotate", 30, 185);
      g2d.drawString("space = hard drop", 30, 205);
      g2d.drawString("N/F2 = new game", 30, 245);
      g2d.drawString("G = toggle ghost piece", 30, 265);
      g2d.drawString("H = toggle grid", 30, 285);
      g2d.drawString("P = pause/unpause", 30, 305);
      g2d.drawString("X = toggle pause display", 30, 325);
      g2d.drawString("J = graphics mode", 30, 345);
    }
    else
    {
      int counter = 0;
      boolean override;
      for (Point x : oldPiecePoints)
      {
        override = false;
        if (x.y < 0) continue;
        for (int y = 0; y < 4; y++)
        {
          if (x != board.getCurrentPiecePoints()[y]) override = true;
        }
        if (override)
        {
          g2d.setColor(Color.BLACK);
          g2d.fill(squares[x.x][x.y]);
          if (grid) g2d.setColor(new Color(50, 50, 50));
          g2d.draw(squares[x.x][x.y]);
        }
      }
      for (Point x : board.getCurrentPiecePoints())
      {
        if (x.y < 0) continue;
        g2d.setColor(board.getCurrentPieceColor());
        g2d.fill(squares[x.x][x.y]);
        if (grid) g2d.setColor(new Color(50, 50, 50));
        g2d.draw(squares[x.x][x.y]);
        oldPiecePoints[counter] = x;
        counter++;
        //temp
        if (graphicsMode == 1 || graphicsMode == 2)
        {
          g2d.setColor(Color.DARK_GRAY);
          //Rectangle2D r = ;
          g2d.draw(new Rectangle2D.Double(squares[x.x][x.y].getMinX() + 3, squares[x.x][x.y].getMinY() + 3, 14, 14));
          g2d.draw(new Rectangle2D.Double(squares[x.x][x.y].getMinX() + 5, squares[x.x][x.y].getMinY() + 5, 10, 10));
          //temp end
        }
        if (graphicsMode == 2)
        {
          g2d.setColor(Color.DARK_GRAY);
          g2d.draw(new Rectangle2D.Double(squares[x.x][x.y].getMinX() + 7, squares[x.x][x.y].getMinY() + 7, 6, 6));
          g2d.draw(new Rectangle2D.Double(squares[x.x][x.y].getMinX() + 9, squares[x.x][x.y].getMinY() + 9, 2, 2));
        }
      }
    }
    if (lastPauseDisplay != pauseDisplay)
    {
      lastPauseDisplay = pauseDisplay;
      g2d.setColor(Color.GREEN);
      repaintPauseDisplay(g2d);
    }
    if (board.isGameOver())
    {
      repaintBoard(g2d, true);
      timer.stop();
      g2d.setColor(Color.RED);
      g2d.setFont(new Font("TimesRoman", Font.BOLD, 28));
      g2d.drawString("GAME OVER", 35, 230);
    }
    repaintBoard(g2d, false);
    if (board.hasPieceDropped())
    {
      for (Point x : this.oldPiecePoints)
      {
        x.x = 1;
        x.y = -1;
      }
      board.resetPieceDropped();
    }
    repaintNextPieceDisplay(g2d, false);
    if (ghostPiece && !pauseMode)
    {
      int counter = 0;
      for (Point x : oldGhostPiecePoints)
      {
        g2d.setColor(Color.BLACK);
        if (grid) g2d.setColor(new Color(50, 50, 50));
        if (x.y >= 0)
        {
          g2d.draw(squares[x.x][x.y]);
        }
      }
      for (Point x : board.getGhostPiecePoints())
      {
        g2d.setColor(Color.WHITE);
        if (x.y >= 0) g2d.draw(squares[x.x][x.y]);
        oldGhostPiecePoints[counter] = x;
        counter++;
      }
    }
  }
  @Override
  public void keyPressed(KeyEvent arg0)
  {
    switch(arg0.getKeyCode())
    {
      case KeyEvent.VK_A:
      case KeyEvent.VK_LEFT:
        if (!pauseMode && !board.isGameOver()) board.moveLeft();
        repaint();
        break;
      case KeyEvent.VK_D:
      case KeyEvent.VK_RIGHT:
        if (!pauseMode && !board.isGameOver()) board.moveRight();
        repaint();
        break;
      case KeyEvent.VK_S:
      case KeyEvent.VK_DOWN:
        if (!pauseMode && !board.isGameOver()) board.moveDown();
        repaint();
        break;
      case KeyEvent.VK_UP:
      case KeyEvent.VK_W:
      case KeyEvent.VK_Z:
        if (!pauseMode && !board.isGameOver()) board.rotate();
        repaint();
        break;
      case KeyEvent.VK_SPACE:
        if (!pauseMode && !board.isGameOver()) board.hardDrop();
        repaint();
        break;
      case KeyEvent.VK_N:
      case KeyEvent.VK_F2:
        newGame();
        pauseMode = false;
        repaint();
        break;
      case KeyEvent.VK_P:
        initialSetup = true;
        if (!board.isGameOver())
        {
          pauseMode = !pauseMode;
          if (pauseMode)
            timer.stop();
          else
            timer.start();
        }
        repaint();
        break;
      case KeyEvent.VK_H:
        initialSetup = true;
        grid = !grid;
        repaint();
        break;
      case KeyEvent.VK_G:
        initialSetup = true;
        ghostPiece = !ghostPiece;
        repaint();
        break;
      case KeyEvent.VK_X:
        pauseDisplay = !pauseDisplay;
        if (!pauseDisplay)
        {
          initialSetup = true;
        }
        repaint();
        break;
      case KeyEvent.VK_J:
        graphicsMode++;
        if (graphicsMode == 3) graphicsMode = 0;
        initialSetup = true;
        repaint();
    }
  }
  @Override
  public void keyReleased(KeyEvent arg0)
  {
  }
  @Override
  public void keyTyped(KeyEvent arg0)
  {
  }
  private void repaintBoard(Graphics2D g2d, final boolean dontCheck)
  {
    for (int x = 0; x < 10; x++)
    {
      for (int y = 0; y < 20; y++)
      {
        if (oldColors[x][y] != board.getColor(x, y) || dontCheck)
        {
          oldColors[x][y] = board.getColor(x, y);
          g2d.setColor(board.getColor(x, y));
          if (pauseMode) g2d.setColor(Color.GRAY);
          g2d.fill(squares[x][y]);
          if (grid) g2d.setColor(new Color(50, 50, 50));
          g2d.draw(squares[x][y]);
          
          //temp
          if (graphicsMode == 1 || graphicsMode == 2)
          {
            if (board.getColor(x, y) != Color.BLACK)
            {
              g2d.setColor(Color.DARK_GRAY);
              g2d.draw(new Rectangle2D.Double(squares[x][y].getMinX() + 3, squares[x][y].getMinY() + 3, 14, 14));
              g2d.draw(new Rectangle2D.Double(squares[x][y].getMinX() + 5, squares[x][y].getMinY() + 5, 10, 10));
            }
          }
          if (graphicsMode == 2)
          {
            if (board.getColor(x, y) != Color.BLACK)
            {
              g2d.setColor(Color.DARK_GRAY);
              g2d.draw(new Rectangle2D.Double(squares[x][y].getMinX() + 7, squares[x][y].getMinY() + 7, 6, 6));
              g2d.draw(new Rectangle2D.Double(squares[x][y].getMinX() + 9, squares[x][y].getMinY() + 9, 2, 2));
            }
          }          //temp end
        }
      } 
    }
  }
  private void repaintNextPieceDisplay(Graphics2D g2d, final boolean dontCheck)
  {
    if (oldNextPieceType != board.getNextPieceType() || dontCheck)
    {
      oldNextPieceType = board.getNextPieceType();
      for (int x = 0; x < 4; x++)
      {
        for (int y = 0; y < 2; y++)
        {
          g2d.setColor(board.getNextPieceColor(x, y));
          if (pauseMode) g2d.setColor(Color.GRAY);
          g2d.fill(squaresNewPiece[x][y]);
          if (grid) g2d.setColor(new Color(50, 50, 50));
          g2d.draw(squaresNewPiece[x][y]);
          //temp
          if (graphicsMode == 1 || graphicsMode == 2)
          {
            if (board.getNextPieceColor(x, y) != Color.BLACK)
            {
              g2d.setColor(Color.DARK_GRAY);
              g2d.draw(new Rectangle2D.Double(squaresNewPiece[x][y].getMinX() + 3, squaresNewPiece[x][y].getMinY() + 3, 14, 14));
              g2d.draw(new Rectangle2D.Double(squaresNewPiece[x][y].getMinX() + 5, squaresNewPiece[x][y].getMinY() + 5, 10, 10));
            }
          }
          if (graphicsMode == 2)
          {
            if (board.getNextPieceColor(x, y) != Color.BLACK)
            {
              g2d.setColor(Color.DARK_GRAY);
              g2d.draw(new Rectangle2D.Double(squaresNewPiece[x][y].getMinX() + 7, squaresNewPiece[x][y].getMinY() + 7, 6, 6));
              g2d.draw(new Rectangle2D.Double(squaresNewPiece[x][y].getMinX() + 9, squaresNewPiece[x][y].getMinY() + 9, 2, 2));
            }
          }
          //temp end
         }
      }
    }
  }
  private void repaintPauseDisplay(Graphics2D g2d)
  {
    if (pauseDisplay)
    {
      g2d.setColor(Color.GREEN);
      g2d.drawString("P = PAUSE/KEY", 73, 470);
    }
    else
    {
      g2d.drawString("             ", 73, 470);      
    }
  }
}

Board.java

import java.awt.Color;
import java.awt.Point;
import java.util.Random;
import pieces.FourRotationPiece;
import pieces.OPiece;
import pieces.Piece;
import pieces.PieceType;
import pieces.TwoRotationPiece;
public class Board
{
  public static final int ROWS = 20, COLUMNS = 10;
  private int row, column;
  private boolean hardDrop, gameOver, hasPieceDropped;
  private Piece currentPiece, nextPiece;
  private Color[][] colors, nextPieceColors;
  private Point[] ghostPiecePoints;
  private int score;
  private int level;
  public Board()
  {
    score = 0;
    level = 1;
    hardDrop = false;
    gameOver = false;
    nextPiece = getRandomPiece();
    colors = new Color[COLUMNS][ROWS];
    nextPieceColors = new Color[4][2];
    ghostPiecePoints = new Point[4];
    for (int x = 0; x < 4; x++)
    {
      ghostPiecePoints[x] = new Point();
    }
    for (int x = 0; x < 4; x++)
    {
      for (int y = 0; y < 2; y++)
      {
        nextPieceColors[x][y] = Color.BLACK;
      }
    }
    for (int x = 0; x < COLUMNS; x++)
    {
      for (int y = 0; y < ROWS; y++)
      {
        colors[x][y] = Color.BLACK;
      }
    }
    addPiece();
  }
  private void addPiece()
  {
    recalculateLevel();
    hardDrop = false;
    currentPiece = nextPiece;
    nextPiece = getRandomPiece();
    Color color = nextPiece.getColor();
    for (int x = 0; x < 4; x++)
    {
      for (int y = 0; y < 2; y++)
      {
        nextPieceColors[x][y] = Color.BLACK;
      }
    }
    for (Point x : nextPiece.getPoints())
    {
      nextPieceColors[x.x][x.y] = color; 
    }
    row = -2;
    column = 4;
    determineGhostPiecePoints();
  }
  public Color getColor(final int x, final int y)
  {
    return colors[x][y];
  }
  public Color getNextPieceColor(final int x, final int y)
  {
    return nextPieceColors[x][y];
  }
  private Piece getRandomPiece()
  {
    Piece piece = null;
    switch(new Random().nextInt(7))
    {
      case 0:
        piece = new TwoRotationPiece(PieceType.I);
        break;
      case 1:
        piece = new FourRotationPiece(PieceType.J);
       break;
      case 2:
        piece = new FourRotationPiece(PieceType.L);
        break;
      case 3:
        piece = new OPiece();
        break;
      case 4:
        piece = new TwoRotationPiece(PieceType.S);
        break;
      case 5:
        piece = new FourRotationPiece(PieceType.T);
        break;
      case 6:
        piece = new TwoRotationPiece(PieceType.Z);
    }
    return piece;
  }
  public void moveLeft()
  {
    boolean go = true;
    for (Point x : getLeftMostPoints())
    {
      if (x.x > 0 && x.y > 0)
      {
        if (colors[x.x - 1][x.y] != Color.BLACK) go = false;
      }
    }
    if (go)
    {
      if (column > 0) column--;
      determineGhostPiecePoints();
    }
  }
  public void moveRight()
  {
    boolean go = true;
    for (Point x : getRightMostPoints())
    {
      if (x.x < 9 && x.y > 0)
      {
        if (colors[x.x + 1][x.y] != Color.BLACK) go = false;
      }
    }
    if (go)
    {
      if (column + getNumberOfColumns() < 9) column++;
      determineGhostPiecePoints();
    }
  }
  public void moveDown()
  {
    boolean go = true;
    for (Point x : getBottomMostPoints())
    {
      if (x.y >= 0 && x.y < 19)
      {
        if (colors[x.x][x.y + 1] != Color.BLACK) go = false;
      }
      else if (x.y > 18)
      {
        go = false;
      }
    }
    if (go)
    {
      row++;
    }
    else
    {
      for (Point x : getCurrentPiecePoints())
      {
        if (x.y >= 0)
          colors[x.x][x.y] = currentPiece.getColor();
        else
          gameOver = true;
      }
      clearLines();
      addPiece();
      hasPieceDropped = true;
      score += level * 5;
    }
    determineGhostPiecePoints();
  }
  public void hardDrop()
  {
    hardDrop = true;
    while(hardDrop)
    {
      moveDown();
    }
  }
  public void rotate()
  {
    boolean noGo = true;
    currentPiece.rotate();
    for (Point x : getCurrentPiecePoints())
    {
      if (x.x < 0 || x.x > 9 || x.y > 19)
      {
        noGo = false;
      }
      else
      {
        if (x.y >= 0)
        {
          if (colors[x.x][x.y] != Color.BLACK) noGo = false;
        }
      }
    }
    if (!noGo)
    {
      switch(currentPiece.getPieceType())
      {
      case I: case S: case Z:
        currentPiece.rotate();
        break;
      default:
        currentPiece.rotate();
        currentPiece.rotate();
        currentPiece.rotate();
      }
    }
    else
    {
      determineGhostPiecePoints();
    }
  }
  public Color getCurrentPieceColor()
  {
    return currentPiece.getColor();
  }
  public Point[] getCurrentPiecePoints()
  {
    return new Point[]{new Point(currentPiece.getPoints()[0].x + column, currentPiece.getPoints()[0].y + row),
                       new Point(currentPiece.getPoints()[1].x + column, currentPiece.getPoints()[1].y + row),
                       new Point(currentPiece.getPoints()[2].x + column, currentPiece.getPoints()[2].y + row),
                       new Point(currentPiece.getPoints()[3].x + column, currentPiece.getPoints()[3].y + row)};
  }
  private Point[] getBottomMostPoints()
  {
    Point[] points = new Point[4];
    for (int x = 0; x < 4; x++)
    {
      points[x] = new Point();
    }
    int current = 0;
    for (Point x : getCurrentPiecePoints())
    {
      points[current] = x;
      for (Point y : getCurrentPiecePoints())
      {
        if (x.x == y.x && y.y > x.y)
        {
          points[current] = y;
        }
      }
      current++;
    }
    return points;
  }
  private Point[] getLeftMostPoints()
  {
    Point[] points = new Point[4];
    for (int x = 0; x < 4; x++)
    {
      points[x] = new Point();
    }
    int current = 0;
    for (Point x : getCurrentPiecePoints())
    {
      points[current] = x;
      for (Point y : getCurrentPiecePoints())
      {
        if (x.y == y.y && y.x < x.x)
        {
          points[current] = y;
        }
      }
      current++;
    }
    return points;
  }
  private Point[] getRightMostPoints()
  {
    Point[] points = new Point[4];
    for (int x = 0; x < 4; x++)
    {
      points[x] = new Point();
    }
    int current = 0;
    for (Point x : getCurrentPiecePoints())
    {
      points[current] = x;
      for (Point y : getCurrentPiecePoints())
      {
        if (x.y == y.y && y.x > x.x)
        {
          points[current] = y;
        }
      }
      current++;
    }
    return points;
  }
  private int getNumberOfColumns()
  {
    int max = 0;
    for (Point x : currentPiece.getPoints())
    {
      if (x.x > max) max = x.x;
    }
    return max;
  }
  private void recalculateLevel()
  {
    long increment = 300;
    for (int x = 0; x < 10; x++)
    {
      if (score > increment) level = x + 1;
      increment += increment;
    }
  }
  public int getLevel()
  {
    return level;
  }
  public int getScore()
  {
    return score;
  }
  private void clearLines()
  {
    boolean clear;
    int num = 0;
    for (int y = 19; y >= 0; y--)
    {
      clear = true;
      for (int x = 0; x <= 9; x++)
      {
        if (colors[x][y] == Color.BLACK) clear = false;
      }
      if (clear)
      {
        for (int m = y; m > 0; m--)
        {
          for (int n = 0; n <= 9; n++)
          {
            colors[n][m] = colors[n][m - 1];
            colors[n][m - 1] = Color.BLACK;
          }
        }
        y++;
        num++;
      }
    }
    switch(num)
    {
    case 1:
      score += level * 25;
      break;
    case 2:
      score += level * 2 * 50;
      break;
    case 3:
      score += level * 3 * 100;
      break;
    case 4:
      score += level * 4 * 200;
      break;
    }
  }
  public boolean isGameOver()
  {
    return gameOver;
  }
  public void determineGhostPiecePoints()
  {
    int r = 0;
    boolean go = false;
    while(true)
    {
      go = true;
      for (Point x : getBottomMostPoints())
      {
        if (x.y + r >= 0 && x.y + r < 20)
        {
          if (colors[x.x][x.y + r] != Color.BLACK)
            go = false;
        }
        else if (x.y + r < 0)
        {
          go = true;
        }
        else
        {
          go = false;
        }
      }
      if (go) r++; else break;
    }
    for (int x = 0; x < 4; x++)
    {
      ghostPiecePoints[x] = new Point(getCurrentPiecePoints()[x].x, getCurrentPiecePoints()[x].y + r - 1);
    }
  }
  public Point[] getGhostPiecePoints()
  {
    return ghostPiecePoints;
  }
  public PieceType getNextPieceType()
  {
    return nextPiece.getPieceType();
  }
  public boolean hasPieceDropped()
  {
    return hasPieceDropped;
  }
  public void resetPieceDropped()
  {
    hasPieceDropped = false;
  }
}

package “pieces”

FourRotationPiece.java

package pieces;
import java.awt.Point;
public class FourRotationPiece extends Piece
{
  /*
   * X      X   X
   * XXX  XXX  XXX.
   *
   *  X  XX   X
   *  X   X  XX
   * XX   X   X.
   *
   * XXX  XXX  XXX
   *   X  X     X.
   *
   * XX  X   X
   * X   X   XX
   * X   XX  X.
   */
  private PiecePosition piecePosition;
  public FourRotationPiece(PieceType pType)
  {
    super(pType);
    piecePosition = PiecePosition.A;
    determinePiecePoints();
    determinePieceColor();
  }
  @SuppressWarnings("incomplete-switch")
  private void determinePiecePoints()
  {
    Point[] points = new Point[4];
    switch(super.getPieceType())
    {
      case L:
        switch(piecePosition)
        {
          case A:
            points = new Point[]{new Point(0, 0), new Point(0, 1), new Point(1, 1), new Point(2, 1)};
            break;
          case B:
            points = new Point[]{new Point(0, 2), new Point(1, 0), new Point(1, 1), new Point(1, 2)};
            break;
          case C:
            points = new Point[]{new Point(0, 0), new Point(1, 0), new Point(2, 0), new Point(2, 1)};
            break;
          case D:
            points = new Point[]{new Point(0, 0), new Point(0, 1), new Point(0, 2), new Point(1, 0)};
        }
        break;
      case J:
        switch(piecePosition)
        {
          case A:
            points = new Point[]{new Point(2, 0), new Point(0, 1), new Point(1, 1), new Point(2, 1)};
            break;
          case B:
            points = new Point[]{new Point(0, 0), new Point(1, 0), new Point(1, 1), new Point(1, 2)};
            break;
          case C:
            points = new Point[]{new Point(0, 0), new Point(1, 0), new Point(2, 0), new Point(0, 1)};
            break;
          case D:
            points = new Point[]{new Point(0, 0), new Point(0, 1), new Point(0, 2), new Point(1, 2)};
        }
        break;
      case T:
        switch(piecePosition)
        {
          case A:
            points = new Point[]{new Point(1, 0), new Point(0, 1), new Point(1, 1), new Point(2, 1)};
            break;
          case B:
            points = new Point[]{new Point(0, 1), new Point(1, 0), new Point(1, 1), new Point(1, 2)};
            break;
          case C:
            points = new Point[]{new Point(0, 0), new Point(1, 0), new Point(2, 0), new Point(1, 1)};
            break;
          case D:
            points = new Point[]{new Point(0, 0), new Point(0, 1), new Point(0, 2), new Point(1, 1)};
       }
    }
    super.setPoints(points);
  }
  public void rotate()
  {
    switch(piecePosition)
    {
      case A:
        piecePosition = PiecePosition.B;
        break;
      case B:
        piecePosition = PiecePosition.C;
        break;
      case C:
        piecePosition = PiecePosition.D;
        break;
      case D:
        piecePosition = PiecePosition.A;
    }
    determinePiecePoints();
  }
}

OPiece.java

package pieces;
import java.awt.Point;
public class OPiece extends Piece
{
  /*
   * XX
   * XX.
   */
  public OPiece()
  {
    super(PieceType.O);
    super.setPoints(new Point[]{new Point(0, 0), new Point(0, 1), new Point(1, 0), new Point(1, 1)});
    determinePieceColor();
  }
}

Piece.java

package pieces;
import java.awt.Color;
import java.awt.Point;
public class Piece
{
  PieceType pieceType;
  Point[] points;
  private Color color;
  public Piece(final PieceType pType)
  {
    pieceType = pType;
    points = new Point[4];
  }
  protected void setPoints(Point[] p)
  {
    points = p;
  }
  public Point[] getPoints()
  {
    return points;
  }
  public void rotate()
  {
    
  }
  public Color getColor()
  {
    return color;
  }
  protected void determinePieceColor()
  {
    switch(pieceType)
    {
      case I:
        color = Color.WHITE;
        break;
      case J:
        color = Color.BLUE;
        break;
      case L:
        color = Color.GREEN;
        break;
      case O:
        color = Color.YELLOW;
        break;
      case S:
        color = Color.CYAN;
        break;
      case T:
        color = Color.GRAY;
        break;
      case Z:
        color = Color.MAGENTA;
    }
  }
  public PieceType getPieceType()
  {
    return pieceType;
  }
}

PiecePosition.java

package pieces;
public enum PiecePosition
{
  A,B,C,D;
}

PieceType.java

package pieces;

public enum PieceType
{
I,J,L,O,S,T,Z
}

TwoRotationPiece.java

package pieces;
import java.awt.Point;
public class TwoRotationPiece extends Piece
{
  /*
   *       XX XX
   * XXXX XX   XX.
   *
   * X
   * X  X   X
   * X  XX XX
   * X   X X.
   */
  private PiecePosition piecePosition;
  public TwoRotationPiece(PieceType pType)
  {
    super(pType);
    piecePosition = PiecePosition.A;
    determinePiecePoints();
    determinePieceColor();
  }
  @SuppressWarnings("incomplete-switch")
  private void determinePiecePoints()
  {
    Point[] points = new Point[4];
    switch(super.getPieceType())
    {
      case I:
        switch(piecePosition)
        {
          case A:
            points = new Point[]{new Point(0, 0), new Point(1, 0), new Point(2, 0), new Point(3, 0)};
            break;
          case B:
            points = new Point[]{new Point(0, 0), new Point(0, 1), new Point(0, 2), new Point(0, 3)};
        }
        break;
      case S:
        switch(piecePosition)
        {
          case A:
            points = new Point[]{new Point(0, 1), new Point(1, 0), new Point(1, 1), new Point(2, 0)};
            break;
          case B:
            points = new Point[]{new Point(0, 0), new Point(0, 1), new Point(1, 1), new Point(1, 2)};
        }
        break;
      case Z:
        switch(piecePosition)
        {
          case A:
            points = new Point[]{new Point(0, 0), new Point(1, 0), new Point(1, 1), new Point(2, 1)};
            break;
          case B:
            points = new Point[]{new Point(0, 1), new Point(0, 2), new Point(1, 0), new Point(1, 1)};
       }
    }
    super.setPoints(points);
  }
  @SuppressWarnings("incomplete-switch")
  public void rotate()
  {
    switch(piecePosition)
    {
      case A:
        piecePosition = PiecePosition.B;
        break;
      case B:
        piecePosition = PiecePosition.A;
    }
    determinePiecePoints();
  }
}