Tetris/Java: Difference between revisions

From Rosetta Code
Content added Content deleted
(→‎{{headerJava}}: added Java)
 
m (→‎Code: Fixed syntax highlighting.)
 
(9 intermediate revisions by 2 users not shown)
Line 1: Line 1:
{{collection|Tetris}}
=={{header|Java}}==
===Code===
{{works with|java|8}}
{{works with|java|8}}
<lang java>import java.awt.*;
<syntaxhighlight lang="java">package tetris;

import java.awt.*;
import java.awt.event.*;
import java.awt.event.*;
import static java.lang.Math.*;
import static java.lang.String.format;
import static java.lang.String.format;
import java.util.Arrays;
import java.util.*;
import javax.swing.*;
import javax.swing.*;
import static tetris.Config.*;


public class Tetris extends JPanel implements Runnable {
public class Tetris extends JPanel implements Runnable {
enum Dir {
right(1, 0), down(0, 1), left(-1, 0);

Dir(int x, int y) {
this.x = x;
this.y = y;
}
final int x, y;
};

public static final int EMPTY = -1;
public static final int EMPTY = -1;
public static final int BORDER = -2;
public static final int BORDER = -2;


Shape fallingShape;
final Color[] colors = {Color.green, Color.red, Color.blue, Color.pink,
Shape nextShape;
Color.orange, Color.cyan, Color.magenta};


// position of falling shape
// for centering the shapes in the preview window
int fallingShapeRow;
final int[][] previewOffets = {{16, 15}, {-15, 15}, {0, 0}, {0, 0},
int fallingShapeCol;
{-15, 5}, {16, 15}, {-15, 15}};


int[][] grid;
final int[][] grid = new int[nRows][nCols];

Shape selectedShape;
Shape preSelectedShape;

int blockSize = 30;
int nRows = 18;
int nCols = 12;
int shapeRow;
int shapeCol;
int topMargin = 50;
int leftMargin = 20;


Thread fallingThread;
Thread fallingThread;
Scoreboard scoreboard;
final Scoreboard scoreboard = new Scoreboard();
static final Random rand = new Random();

Font smallFont;
Rectangle gridRect, previewRect;


public Tetris() {
public Tetris() {
setPreferredSize(new Dimension(640, 640));
setPreferredSize(dim);
setBackground(new Color(0xDDEEFF));
setBackground(bgColor);
setFont(new Font("Monospaced", Font.BOLD, 48));
setFocusable(true);
setFocusable(true);


smallFont = getFont().deriveFont(Font.BOLD, 18);

gridRect = new Rectangle(46, 47, 308, 517);
previewRect = new Rectangle(387, 47, 200, 200);

scoreboard = new Scoreboard();
grid = new int[nRows][nCols];
initGrid();
initGrid();
selectShape();
selectShape();
Line 75: Line 69:


case KeyEvent.VK_UP:
case KeyEvent.VK_UP:
if (canRotate(selectedShape))
if (canRotate(fallingShape))
rotate(selectedShape);
rotate(fallingShape);
break;
break;


case KeyEvent.VK_LEFT:
case KeyEvent.VK_LEFT:
if (canMove(selectedShape, -1, 0))
if (canMove(fallingShape, Dir.left))
move(selectedShape, -1, 0);
move(Dir.left);
break;
break;


case KeyEvent.VK_RIGHT:
case KeyEvent.VK_RIGHT:
if (canMove(selectedShape, 1, 0))
if (canMove(fallingShape, Dir.right))
move(selectedShape, 1, 0);
move(Dir.right);
break;
break;


Line 92: Line 86:
if (!fastDown) {
if (!fastDown) {
fastDown = true;
fastDown = true;
while (canMove(selectedShape, 0, 1)) {
while (canMove(fallingShape, Dir.down)) {
move(selectedShape, 0, 1);
move(Dir.down);
repaint();
repaint();
}
}
Line 110: Line 104:


void selectShape() {
void selectShape() {
shapeRow = 1;
fallingShapeRow = 1;
shapeCol = 5;
fallingShapeCol = 5;
selectedShape = preSelectedShape;
fallingShape = nextShape;
preSelectedShape = Shape.values()[(int) (Math.random() * colors.length)];
Shape[] shapes = Shape.values();
nextShape = shapes[rand.nextInt(shapes.length)];
if (selectedShape != null)
selectedShape.reset();
if (fallingShape != null)
fallingShape.reset();
}
}


Line 151: Line 146:
try {
try {
Thread.sleep(scoreboard.getSpeed());
Thread.sleep(scoreboard.getSpeed());
} catch (InterruptedException ignored) {
} catch (InterruptedException e) {
return;
}
}


if (!scoreboard.isGameOver()) {
if (!scoreboard.isGameOver()) {
if (canMove(selectedShape, 0, 1)) {
if (canMove(fallingShape, Dir.down)) {
move(selectedShape, 0, 1);
move(Dir.down);
} else {
} else {
shapeHasLanded();
shapeHasLanded();
Line 166: Line 162:


void drawStartScreen(Graphics2D g) {
void drawStartScreen(Graphics2D g) {
g.setFont(getFont());
g.setFont(mainFont);


g.setColor(new Color(0xFFFFFF));
g.setColor(titlebgColor);
g.fillRect(leftMargin + 80, topMargin + 35, 252, 100);
g.fill(titleRect);
g.fillRect(leftMargin + 30, topMargin + 325, 252, 40);
g.fill(clickRect);


g.setColor(Color.black);
g.setColor(textColor);
g.drawString("Tetris", leftMargin + 110, topMargin + 100);
g.drawString("Tetris", titleX, titleY);


g.setFont(smallFont);
g.setFont(smallFont);
g.drawString("click to start", leftMargin + 100, topMargin + 350);
g.drawString("click to start", clickX, clickY);
}
}


void drawSquare(Graphics2D g, Color color, int r, int c) {
void drawSquare(Graphics2D g, int colorIndex, int r, int c) {
g.setStroke(new BasicStroke(2));
g.setColor(colors[colorIndex]);

g.setColor(color);
g.fillRect(leftMargin + c * blockSize, topMargin + r * blockSize,
g.fillRect(leftMargin + c * blockSize, topMargin + r * blockSize,
blockSize, blockSize);
blockSize, blockSize);


g.setColor(Color.white);
g.setStroke(smallStroke);
g.setColor(squareBorder);
g.drawRect(leftMargin + c * blockSize, topMargin + r * blockSize,
g.drawRect(leftMargin + c * blockSize, topMargin + r * blockSize,
blockSize, blockSize);
blockSize, blockSize);
Line 192: Line 187:


void drawUI(Graphics2D g) {
void drawUI(Graphics2D g) {
g.setStroke(new BasicStroke(5));
// grid background
g.setColor(new Color(0xBECFEA));
g.setColor(gridColor);
g.fill(gridRect);
g.fill(gridRect);


// the blocks dropped in the grid
g.setColor(new Color(0x7788AA));
g.draw(gridRect);
g.draw(previewRect);

for (int r = 0; r < nRows; r++) {
for (int r = 0; r < nRows; r++) {
for (int c = 0; c < nCols; c++) {
for (int c = 0; c < nCols; c++) {
int id = grid[r][c];
int idx = grid[r][c];
if (id > EMPTY)
if (idx > EMPTY)
drawSquare(g, colors[id], r, c);
drawSquare(g, idx, r, c);
}
}
}
}


// the borders of grid and preview panel
g.setColor(Color.black);
g.setStroke(largeStroke);
g.setColor(gridBorderColor);
g.draw(gridRect);
g.draw(previewRect);

// scoreboard
int x = scoreX;
int y = scoreY;
g.setColor(textColor);
g.setFont(smallFont);
g.setFont(smallFont);
g.drawString(format("hiscore %6d", scoreboard.getTopscore()),400, 330);
g.drawString(format("hiscore %6d", scoreboard.getTopscore()), x, y);
g.drawString(format("level %6d", scoreboard.getLevel()), 400, 360);
g.drawString(format("level %6d", scoreboard.getLevel()), x, y + 30);
g.drawString(format("lines %6d", scoreboard.getLines()), 400, 390);
g.drawString(format("lines %6d", scoreboard.getLines()), x, y + 60);
g.drawString(format("score %6d", scoreboard.getScore()), 400, 420);
g.drawString(format("score %6d", scoreboard.getScore()), x, y + 90);
}


// preview
void drawPreview(Graphics2D g) {
int ord = preSelectedShape.ordinal();
int minX = 5, minY = 5, maxX = 0, maxY = 0;
for (int[] p : nextShape.pos) {
g.translate(previewOffets[ord][0], previewOffets[ord][1]);
for (int[] p : preSelectedShape.shapes[ord]) {
minX = min(minX, p[0]);
drawSquare(g, colors[ord], 2 + p[1], 15 + p[0]);
minY = min(minY, p[1]);
maxX = max(maxX, p[0]);
maxY = max(maxY, p[1]);
}
}
double cx = previewCenterX - ((minX + maxX + 1) / 2.0 * blockSize);
g.translate(-previewOffets[ord][0], -previewOffets[ord][1]);
double cy = previewCenterY - ((minY + maxY + 1) / 2.0 * blockSize);

g.translate(cx, cy);
for (int[] p : nextShape.shape)
drawSquare(g, nextShape.ordinal(), p[1], p[0]);
g.translate(-cx, -cy);
}
}


void drawFallingShape(Graphics2D g) {
void drawFallingShape(Graphics2D g) {
Color c = colors[selectedShape.ordinal()];
int idx = fallingShape.ordinal();
for (int[] p : selectedShape.pos)
for (int[] p : fallingShape.pos)
drawSquare(g, c, shapeRow + p[1], shapeCol + p[0]);
drawSquare(g, idx, fallingShapeRow + p[1], fallingShapeCol + p[0]);
}
}


Line 240: Line 248:
drawUI(g);
drawUI(g);


if (fallingThread == null) {
if (scoreboard.isGameOver()) {
drawStartScreen(g);
drawStartScreen(g);
} else {
} else {
drawFallingShape(g);
drawFallingShape(g);
}
}

drawPreview(g);
}
}


Line 265: Line 271:


for (int[] p : pos) {
for (int[] p : pos) {
int newCol = shapeCol + p[0];
int newCol = fallingShapeCol + p[0];
int newRow = shapeRow + p[1];
int newRow = fallingShapeRow + p[1];
if (grid[newRow][newCol] != EMPTY) {
if (grid[newRow][newCol] != EMPTY) {
return false;
return false;
Line 285: Line 291:
}
}


void move(Shape s, int xIncr, int yIncr) {
void move(Dir dir) {
shapeRow += yIncr;
fallingShapeRow += dir.y;
shapeCol += xIncr;
fallingShapeCol += dir.x;
}
}


boolean canMove(Shape s, int xIncr, int yIncr) {
boolean canMove(Shape s, Dir dir) {
for (int[] p : s.pos) {
for (int[] p : s.pos) {
int newCol = shapeCol + xIncr + p[0];
int newCol = fallingShapeCol + dir.x + p[0];
int newRow = shapeRow + yIncr + p[1];
int newRow = fallingShapeRow + dir.y + p[1];
if (grid[newRow][newCol] != EMPTY)
if (grid[newRow][newCol] != EMPTY)
return false;
return false;
Line 301: Line 307:


void shapeHasLanded() {
void shapeHasLanded() {
addShape(selectedShape);
addShape(fallingShape);
if (shapeRow < 2) {
if (fallingShapeRow < 2) {
scoreboard.setGameOver();
scoreboard.setGameOver();
scoreboard.setTopscore();
scoreboard.setTopscore();
Line 339: Line 345:
void addShape(Shape s) {
void addShape(Shape s) {
for (int[] p : s.pos)
for (int[] p : s.pos)
grid[shapeRow + p[1]][shapeCol + p[0]] = s.ordinal();
grid[fallingShapeRow + p[1]][fallingShapeCol + p[0]] = s.ordinal();
}
}


Line 354: Line 360:
});
});
}
}
}</syntaxhighlight>
}

<syntaxhighlight lang="java">package tetris;


class Scoreboard {
class Scoreboard {
Line 461: Line 469:
return score;
return score;
}
}
}</syntaxhighlight>
}

<syntaxhighlight lang="java">package tetris;


enum Shape {
enum Shape {
ZShape, SShape, Straight, TShape, Square, LShape, JShape;
ZShape(new int[][]{{0, -1}, {0, 0}, {-1, 0}, {-1, 1}}),
SShape(new int[][]{{0, -1}, {0, 0}, {1, 0}, {1, 1}}),
IShape(new int[][]{{0, -1}, {0, 0}, {0, 1}, {0, 2}}),
TShape(new int[][]{{-1, 0}, {0, 0}, {1, 0}, {0, 1}}),
Square(new int[][]{{0, 0}, {1, 0}, {0, 1}, {1, 1}}),
LShape(new int[][]{{-1, -1}, {0, -1}, {0, 0}, {0, 1}}),
JShape(new int[][]{{1, -1}, {0, -1}, {0, 0}, {0, 1}});


private Shape() {
private Shape(int[][] shape) {
this.shape = shape;
pos = new int[4][2];
pos = new int[4][2];
reset();
reset();
Line 473: Line 490:
void reset() {
void reset() {
for (int i = 0; i < pos.length; i++) {
for (int i = 0; i < pos.length; i++) {
pos[i] = shapes[ordinal()][i].clone();
pos[i] = shape[i].clone();
}
}
}
}


final int[][] pos;
final int[][] pos, shape;
}</syntaxhighlight>

<syntaxhighlight lang="java">package tetris;

import java.awt.*;

final class Config {
final static Color[] colors = {Color.green, Color.red, Color.blue,
Color.pink, Color.orange, Color.cyan, Color.magenta};

final static Font mainFont = new Font("Monospaced", Font.BOLD, 48);
final static Font smallFont = mainFont.deriveFont(Font.BOLD, 18);

final static Dimension dim = new Dimension(640, 640);

final static Rectangle gridRect = new Rectangle(46, 47, 308, 517);
final static Rectangle previewRect = new Rectangle(387, 47, 200, 200);
final static Rectangle titleRect = new Rectangle(100, 85, 252, 100);
final static Rectangle clickRect = new Rectangle(50, 375, 252, 40);

final static int blockSize = 30;
final static int nRows = 18;
final static int nCols = 12;
final static int topMargin = 50;
final static int leftMargin = 20;
final static int scoreX = 400;
final static int scoreY = 330;
final static int titleX = 130;
final static int titleY = 150;
final static int clickX = 120;
final static int clickY = 400;
final static int previewCenterX = 467;
final static int previewCenterY = 97;

final static Stroke largeStroke = new BasicStroke(5);
final static Stroke smallStroke = new BasicStroke(2);


final int[][][] shapes = {
final static Color squareBorder = Color.white;
final static Color titlebgColor = Color.white;
{{0, -1}, {0, 0}, {-1, 0}, {-1, 1}},
final static Color textColor = Color.black;
{{0, -1}, {0, 0}, {1, 0}, {1, 1}},
final static Color bgColor = new Color(0xDDEEFF);
{{0, -1}, {0, 0}, {0, 1}, {0, 2}},
final static Color gridColor = new Color(0xBECFEA);
{{-1, 0}, {0, 0}, {1, 0}, {0, 1}},
final static Color gridBorderColor = new Color(0x7788AA);
{{0, 0}, {1, 0}, {0, 1}, {1, 1}},
}</syntaxhighlight>
{{-1, -1}, {0, -1}, {0, 0}, {0, 1}},
{{1, -1}, {0, -1}, {0, 0}, {0, 1}}};
}</lang>

Latest revision as of 15:29, 29 August 2022

Tetris/Java is part of Tetris. You may find other members of Tetris at Category:Tetris.

Code

Works with: java version 8
package tetris;

import java.awt.*;
import java.awt.event.*;
import static java.lang.Math.*;
import static java.lang.String.format;
import java.util.*;
import javax.swing.*;
import static tetris.Config.*;

public class Tetris extends JPanel implements Runnable {
    enum Dir {
        right(1, 0), down(0, 1), left(-1, 0);

        Dir(int x, int y) {
            this.x = x;
            this.y = y;
        }
        final int x, y;
    };

    public static final int EMPTY = -1;
    public static final int BORDER = -2;

    Shape fallingShape;
    Shape nextShape;

    // position of falling shape
    int fallingShapeRow;
    int fallingShapeCol;

    final int[][] grid = new int[nRows][nCols];

    Thread fallingThread;
    final Scoreboard scoreboard = new Scoreboard();
    static final Random rand = new Random();

    public Tetris() {
        setPreferredSize(dim);
        setBackground(bgColor);
        setFocusable(true);

        initGrid();
        selectShape();

        addMouseListener(new MouseAdapter() {
            @Override
            public void mousePressed(MouseEvent e) {
                if (scoreboard.isGameOver()) {
                    startNewGame();
                    repaint();
                }
            }
        });

        addKeyListener(new KeyAdapter() {
            boolean fastDown;

            @Override
            public void keyPressed(KeyEvent e) {

                if (scoreboard.isGameOver())
                    return;

                switch (e.getKeyCode()) {

                    case KeyEvent.VK_UP:
                        if (canRotate(fallingShape))
                            rotate(fallingShape);
                        break;

                    case KeyEvent.VK_LEFT:
                        if (canMove(fallingShape, Dir.left))
                            move(Dir.left);
                        break;

                    case KeyEvent.VK_RIGHT:
                        if (canMove(fallingShape, Dir.right))
                            move(Dir.right);
                        break;

                    case KeyEvent.VK_DOWN:
                        if (!fastDown) {
                            fastDown = true;
                            while (canMove(fallingShape, Dir.down)) {
                                move(Dir.down);
                                repaint();
                            }
                            shapeHasLanded();
                        }
                }
                repaint();
            }

            @Override
            public void keyReleased(KeyEvent e) {
                fastDown = false;
            }
        });
    }

    void selectShape() {
        fallingShapeRow = 1;
        fallingShapeCol = 5;
        fallingShape = nextShape;
        Shape[] shapes = Shape.values();
        nextShape = shapes[rand.nextInt(shapes.length)];
        if (fallingShape != null)
            fallingShape.reset();
    }

    void startNewGame() {
        stop();
        initGrid();
        selectShape();
        scoreboard.reset();
        (fallingThread = new Thread(this)).start();
    }

    void stop() {
        if (fallingThread != null) {
            Thread tmp = fallingThread;
            fallingThread = null;
            tmp.interrupt();
        }
    }

    void initGrid() {
        for (int r = 0; r < nRows; r++) {
            Arrays.fill(grid[r], EMPTY);
            for (int c = 0; c < nCols; c++) {
                if (c == 0 || c == nCols - 1 || r == nRows - 1)
                    grid[r][c] = BORDER;
            }
        }
    }

    @Override
    public void run() {

        while (Thread.currentThread() == fallingThread) {

            try {
                Thread.sleep(scoreboard.getSpeed());
            } catch (InterruptedException e) {
                return;
            }

            if (!scoreboard.isGameOver()) {
                if (canMove(fallingShape, Dir.down)) {
                    move(Dir.down);
                } else {
                    shapeHasLanded();
                }
                repaint();
            }
        }
    }

    void drawStartScreen(Graphics2D g) {
        g.setFont(mainFont);

        g.setColor(titlebgColor);
        g.fill(titleRect);
        g.fill(clickRect);

        g.setColor(textColor);
        g.drawString("Tetris", titleX, titleY);

        g.setFont(smallFont);
        g.drawString("click to start", clickX, clickY);
    }

    void drawSquare(Graphics2D g, int colorIndex, int r, int c) {
        g.setColor(colors[colorIndex]);
        g.fillRect(leftMargin + c * blockSize, topMargin + r * blockSize,
                blockSize, blockSize);

        g.setStroke(smallStroke);
        g.setColor(squareBorder);
        g.drawRect(leftMargin + c * blockSize, topMargin + r * blockSize,
                blockSize, blockSize);
    }

    void drawUI(Graphics2D g) {
        // grid background
        g.setColor(gridColor);
        g.fill(gridRect);

        // the blocks dropped in the grid
        for (int r = 0; r < nRows; r++) {
            for (int c = 0; c < nCols; c++) {
                int idx = grid[r][c];
                if (idx > EMPTY)
                    drawSquare(g, idx, r, c);
            }
        }

        // the borders of grid and preview panel
        g.setStroke(largeStroke);
        g.setColor(gridBorderColor);
        g.draw(gridRect);
        g.draw(previewRect);

        // scoreboard
        int x = scoreX;
        int y = scoreY;
        g.setColor(textColor);
        g.setFont(smallFont);
        g.drawString(format("hiscore  %6d", scoreboard.getTopscore()), x, y);
        g.drawString(format("level    %6d", scoreboard.getLevel()), x, y + 30);
        g.drawString(format("lines    %6d", scoreboard.getLines()), x, y + 60);
        g.drawString(format("score    %6d", scoreboard.getScore()), x, y + 90);

        // preview
        int minX = 5, minY = 5, maxX = 0, maxY = 0;
        for (int[] p : nextShape.pos) {
            minX = min(minX, p[0]);
            minY = min(minY, p[1]);
            maxX = max(maxX, p[0]);
            maxY = max(maxY, p[1]);
        }
        double cx = previewCenterX - ((minX + maxX + 1) / 2.0 * blockSize);
        double cy = previewCenterY - ((minY + maxY + 1) / 2.0 * blockSize);

        g.translate(cx, cy);
        for (int[] p : nextShape.shape)
            drawSquare(g, nextShape.ordinal(), p[1], p[0]);
        g.translate(-cx, -cy);
    }

    void drawFallingShape(Graphics2D g) {
        int idx = fallingShape.ordinal();
        for (int[] p : fallingShape.pos)
            drawSquare(g, idx, fallingShapeRow + p[1], fallingShapeCol + p[0]);
    }

    @Override
    public void paintComponent(Graphics gg) {
        super.paintComponent(gg);
        Graphics2D g = (Graphics2D) gg;
        g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                RenderingHints.VALUE_ANTIALIAS_ON);

        drawUI(g);

        if (scoreboard.isGameOver()) {
            drawStartScreen(g);
        } else {
            drawFallingShape(g);
        }
    }

    boolean canRotate(Shape s) {
        if (s == Shape.Square)
            return false;

        int[][] pos = new int[4][2];
        for (int i = 0; i < pos.length; i++) {
            pos[i] = s.pos[i].clone();
        }

        for (int[] row : pos) {
            int tmp = row[0];
            row[0] = row[1];
            row[1] = -tmp;
        }

        for (int[] p : pos) {
            int newCol = fallingShapeCol + p[0];
            int newRow = fallingShapeRow + p[1];
            if (grid[newRow][newCol] != EMPTY) {
                return false;
            }
        }
        return true;
    }

    void rotate(Shape s) {
        if (s == Shape.Square)
            return;

        for (int[] row : s.pos) {
            int tmp = row[0];
            row[0] = row[1];
            row[1] = -tmp;
        }
    }

    void move(Dir dir) {
        fallingShapeRow += dir.y;
        fallingShapeCol += dir.x;
    }

    boolean canMove(Shape s, Dir dir) {
        for (int[] p : s.pos) {
            int newCol = fallingShapeCol + dir.x + p[0];
            int newRow = fallingShapeRow + dir.y + p[1];
            if (grid[newRow][newCol] != EMPTY)
                return false;
        }
        return true;
    }

    void shapeHasLanded() {
        addShape(fallingShape);
        if (fallingShapeRow < 2) {
            scoreboard.setGameOver();
            scoreboard.setTopscore();
            stop();
        } else {
            scoreboard.addLines(removeLines());
        }
        selectShape();
    }

    int removeLines() {
        int count = 0;
        for (int r = 0; r < nRows - 1; r++) {
            for (int c = 1; c < nCols - 1; c++) {
                if (grid[r][c] == EMPTY)
                    break;
                if (c == nCols - 2) {
                    count++;
                    removeLine(r);
                }
            }
        }
        return count;
    }

    void removeLine(int line) {
        for (int c = 0; c < nCols; c++)
            grid[line][c] = EMPTY;

        for (int c = 0; c < nCols; c++) {
            for (int r = line; r > 0; r--)
                grid[r][c] = grid[r - 1][c];
        }
    }

    void addShape(Shape s) {
        for (int[] p : s.pos)
            grid[fallingShapeRow + p[1]][fallingShapeCol + p[0]] = s.ordinal();
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> {
            JFrame f = new JFrame();
            f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            f.setTitle("Tetris");
            f.setResizable(false);
            f.add(new Tetris(), BorderLayout.CENTER);
            f.pack();
            f.setLocationRelativeTo(null);
            f.setVisible(true);
        });
    }
}
package tetris;

class Scoreboard {
    static final int MAXLEVEL = 9;

    private int level;
    private int lines;
    private int score;
    private int topscore;
    private boolean gameOver = true;

    void reset() {
        setTopscore();
        level = lines = score = 0;
        gameOver = false;
    }

    void setGameOver() {
        gameOver = true;
    }

    boolean isGameOver() {
        return gameOver;
    }

    void setTopscore() {
        if (score > topscore)
            topscore = score;
    }

    int getTopscore() {
        return topscore;
    }

    int getSpeed() {

        switch (level) {
            case 0:
                return 700;
            case 1:
                return 600;
            case 2:
                return 500;
            case 3:
                return 400;
            case 4:
                return 350;
            case 5:
                return 300;
            case 6:
                return 250;
            case 7:
                return 200;
            case 8:
                return 150;
            case 9:
                return 100;
            default:
                return 100;
        }
    }

    void addScore(int sc) {
        score += sc;
    }

    void addLines(int line) {

        switch (line) {
            case 1:
                addScore(10);
                break;
            case 2:
                addScore(20);
                break;
            case 3:
                addScore(30);
                break;
            case 4:
                addScore(40);
                break;
            default:
                return;
        }

        lines += line;
        if (lines > 10)
            addLevel();
    }

    void addLevel() {
        lines %= 10;
        if (level < MAXLEVEL)
            level++;
    }

    int getLevel() {
        return level;
    }

    int getLines() {
        return lines;
    }

    int getScore() {
        return score;
    }
}
package tetris;

enum Shape {
    ZShape(new int[][]{{0, -1}, {0, 0}, {-1, 0}, {-1, 1}}),
    SShape(new int[][]{{0, -1}, {0, 0}, {1, 0}, {1, 1}}),
    IShape(new int[][]{{0, -1}, {0, 0}, {0, 1}, {0, 2}}),
    TShape(new int[][]{{-1, 0}, {0, 0}, {1, 0}, {0, 1}}),
    Square(new int[][]{{0, 0}, {1, 0}, {0, 1}, {1, 1}}),
    LShape(new int[][]{{-1, -1}, {0, -1}, {0, 0}, {0, 1}}),
    JShape(new int[][]{{1, -1}, {0, -1}, {0, 0}, {0, 1}});

    private Shape(int[][] shape) {
        this.shape = shape;
        pos = new int[4][2];
        reset();
    }

    void reset() {
        for (int i = 0; i < pos.length; i++) {
            pos[i] = shape[i].clone();
        }
    }

    final int[][] pos, shape;
}
package tetris;

import java.awt.*;

final class Config {
    final static Color[] colors = {Color.green, Color.red, Color.blue,
        Color.pink, Color.orange, Color.cyan, Color.magenta};

    final static Font mainFont = new Font("Monospaced", Font.BOLD, 48);
    final static Font smallFont = mainFont.deriveFont(Font.BOLD, 18);

    final static Dimension dim = new Dimension(640, 640);

    final static Rectangle gridRect = new Rectangle(46, 47, 308, 517);
    final static Rectangle previewRect = new Rectangle(387, 47, 200, 200);
    final static Rectangle titleRect = new Rectangle(100, 85, 252, 100);
    final static Rectangle clickRect = new Rectangle(50, 375, 252, 40);

    final static int blockSize = 30;
    final static int nRows = 18;
    final static int nCols = 12;
    final static int topMargin = 50;
    final static int leftMargin = 20;
    final static int scoreX = 400;
    final static int scoreY = 330;
    final static int titleX = 130;
    final static int titleY = 150;
    final static int clickX = 120;
    final static int clickY = 400;
    final static int previewCenterX = 467;
    final static int previewCenterY = 97;

    final static Stroke largeStroke = new BasicStroke(5);
    final static Stroke smallStroke = new BasicStroke(2);

    final static Color squareBorder = Color.white;
    final static Color titlebgColor = Color.white;
    final static Color textColor = Color.black;
    final static Color bgColor = new Color(0xDDEEFF);
    final static Color gridColor = new Color(0xBECFEA);
    final static Color gridBorderColor = new Color(0x7788AA);
}