// BlueBlox applet source // Author Vjekoslav Nesek 1996 import java.util.*; import java.awt.*; import java.applet.*; import java.net.*; public class BlueBlox extends Applet implements Runnable { Thread dropper; byte[][] board; byte[] piece; boolean[][] deleted; static Random generator = new Random(); int sizeX, sizeY, cellSize; boolean gameOver = true, paused = false; int score, posX, posY, level, piecesDroped; String status; Color[] color, backColor; AudioClip explode; public void init() { cellSize = Integer.parseInt(getParameter("cellsize")); sizeX = Integer.parseInt(getParameter("pgwidth")); sizeY = Integer.parseInt(getParameter("pgheight")); piece = new byte[pieceSize]; for (int i = 0; i < pieceSize; i++) piece[i] = EMPTY; board = new byte[sizeX][sizeY]; deleted = new boolean[sizeX][sizeY]; color = new Color[6]; backColor = new Color[sizeX + sizeY]; for (int i = 0; i < sizeX; i++) for (int j = 0; j < sizeY; j++) { board[i][j] = EMPTY; deleted[i][j] = false; } explode = getAudioClip(getCodeBase(), "BlueBlox.au"); setBackground(Color.white); color[0] = Color.red; color[1] = Color.blue; color[2] = Color.green; color[3] = Color.cyan; color[4] = new Color(255, 51, 255); color[5] = Color.yellow; for (int i = 0; i < sizeY + sizeX; i++) { int c = 255 - (int)(64.0 * i / (sizeY + sizeX)); backColor[i] = new Color(c, c, 255); } status = "Click to start (use J, K, L to move piece)"; } public void start() { dropper = new Thread(this); dropper.start(); } public void stop() { dropper.stop(); } public void run() { long toSleep; while (true) { showStatus(status); Graphics g = getGraphics(); try { movePieceDown(g); } finally { getToolkit().sync(); g.dispose(); } toSleep = (11 - level) * 32; if (toSleep > 0) try { Thread.sleep(toSleep); } catch (InterruptedException e) {} } } synchronized boolean movePieceLeft(Graphics g) { if (gameOver || paused || posX == 0) return false; for (int i = 0; i < pieceSize; i++) if (board[posX - 1][posY - i] != EMPTY) return false; for (int i = 0; i < pieceSize; i++) drawEmptyCell(g, posX, posY - i); posX--; drawPiece(g); return true; } synchronized boolean movePieceRight(Graphics g) { if (gameOver || paused || posX >= sizeX - 1) return false; for (int i = 0; i < pieceSize; i++) if (board[posX + 1][posY - i] != EMPTY) return false; for (int i = 0; i < pieceSize; i++) drawEmptyCell(g, posX, posY - i); posX++; drawPiece(g); return true; } synchronized boolean movePieceDown(Graphics g) { if (gameOver || paused) return false; if (posY < sizeY - 1 && board[posX][posY + 1] == EMPTY) { drawEmptyCell(g, posX, posY - pieceSize + 1); posY++; drawPiece(g); return true; } mergePiece(g); return false; } synchronized void rotatePiece(Graphics g) { if (gameOver || paused) return; byte temp = piece[0]; for (int i = 0; i < pieceSize - 1; i++) piece[i] = piece[i + 1]; piece[pieceSize - 1] = temp; drawPiece(g); } boolean markForErasing() { boolean flag = false; for (int i = 0; i < sizeX - 2; i++) for (int j = sizeY - 1; j > 0 ; j--) if (board[i][j] != EMPTY && board[i][j] == board[i + 1][j] && board[i + 1][j] == board[i + 2][j]) { for (int k = 0; k < 3; k++) deleted[i + k][j] = true; incScore(3); flag = true; } for (int i = 0; i < sizeX; i++) for (int j = sizeY - 3; j > 0 ; j--) if (board[i][j] != EMPTY && board[i][j] == board[i][j + 1] && board[i][j + 1] == board[i][j + 2]) { for (int k = 0; k < 3; k++) deleted[i][j + k] = true; incScore(3); flag = true; } for (int i = 0; i < sizeX - 2; i++) for (int j = sizeY - 3; j > 0 ; j--) if (board[i][j] != EMPTY && board[i][j] == board[i + 1][j + 1] && board[i + 1][j + 1] == board[i + 2][j + 2]) { for (int k = 0; k < 3; k++) deleted[i + k][j + k] = true; incScore(3); flag = true; } for (int i = 2; i < sizeX; i++) for (int j = sizeY - 3; j > 0 ; j--) if (board[i][j] != EMPTY && board[i][j] == board[i - 1][j + 1] && board[i - 1][j + 1] == board[i - 2][j + 2]) { for (int k = 0; k < 3; k++) deleted[i - k][j + k] = true; incScore(3); flag = true; } return flag; } void removeErasedCells(Graphics g) { for (int i = 0; i < sizeX; i++) { int k = 0; for (int j = sizeY - 1; j >= 0 ; j--) { if (deleted[i][j]) k++; else { if (k > 0) { board[i][j + k] = board[i][j]; deleted[i][j + k] = false; if (board[i][j + k] == EMPTY) drawEmptyCell(g, i, j + k); else drawCellAt(g, i, j + k, board[i][j + k]); } } if (k > 0 && board[i][j] != EMPTY) { board[i][j] = EMPTY; deleted[i][j] = false; drawEmptyCell(g, i, j); } } } } final private void incScore(int delta) { score += delta * (level * 2 + 7); } synchronized void mergePiece(Graphics g) { for (int i = 0; i < pieceSize; i++) board[posX][posY - i] = piece[i]; piecesDroped++; if (level <= piecesDroped / 40) { level++; drawLevel(g); incScore(5); } incScore(2); while (markForErasing()) { explode.play(); drawImplosion(g); removeErasedCells(g); } drawScore(g); if (!makeNewPiece()) { gameOver = true; status = "Game Over"; } else drawPiece(g); } public void drawImplosion(Graphics g) { for (int i = 0; i < cellSize / 2; i++) { for (int x = 0; x < sizeX; x++) for (int y = 0; y < sizeY; y++) if (deleted[x][y]) { int p = 0, r = 0; switch (level % 3) { case 0: p = i; r = i; break; case 1: p = 0; r = i; break; case 2: p = i; r = 0; break; } setCellBgColor(g, x, y); g.drawRect(x * cellSize + p, y * cellSize + r, cellSize - 2 * p - 2, cellSize - 2 * r - 2); } try { Thread.sleep(40 / (i + 1)); } catch (InterruptedException e) {} } } boolean makeNewPiece() { posX = sizeX / 2; posY = pieceSize - 1; if (board[posX][posY] != EMPTY) return false; for (int i = 0; i < pieceSize; i++) piece[i] = (byte)((generator.nextFloat() * 6) + 1); return true; } public void newGame(Graphics g) { if (!gameOver) return; for (int i = 0; i < sizeX; i++) for (int j = 0; j < sizeY; j++) if (board[i][j] != EMPTY) deleted[i][j] = true; score = 0; level = 1; piecesDroped = 0; explode.play(); drawImplosion(g); removeErasedCells(g); makeNewPiece(); gameOver = false; paused = false; status = ""; paint(g); } void drawPiece(Graphics g) { for (int i = 0; i < pieceSize; i++) drawCellAt(g, posX, posY - i, piece[i]); } void setCellBgColor(Graphics g, int x, int y) { g.setColor(backColor[x + y]); } void setCellFgColor(Graphics g, int x, int y) { g.setColor(color[board[x][y] - 1]); } void drawEmptyCell(Graphics g, int x, int y) { setCellBgColor(g, x, y); g.fillRect(x * cellSize, y * cellSize, cellSize, cellSize); } void drawCellAt(Graphics g, int x, int y, byte arg) { g.setColor(color[arg - 1]); g.fill3DRect(x * cellSize, y * cellSize, cellSize - 1, cellSize - 1, true); } public void drawScore(Graphics g) { int y = cellSize * sizeY + 2; int s = score; g.setColor(Color.blue); g.clearRect(0, y, 5 * 20, 28); for (int x = 80; x >= 0; x -= 20) { drawNumber(g, s % 10, x, y); s /= 10; } } public void drawLevel(Graphics g) { int y = cellSize * sizeY + 2; int xOffset = cellSize * sizeX - 36; int l = level; if (xOffset < 110) xOffset = 110; g.setColor(Color.gray); g.clearRect(xOffset, y, 40, 28); for (int x = xOffset + 20; x >= xOffset; x -= 20) { drawNumber(g, l % 10, x, y); l /= 10; } } void drawNumber(Graphics g, int n, int x, int y) { if ((1 & nu[n]) != 0) g.fillRect(x, y, 4, 16); if ((2 & nu[n]) != 0) g.fillRect(x, y, 16, 4); if ((4 & nu[n]) != 0) g.fillRect(x + 12, y, 4, 16); if ((8 & nu[n]) != 0) g.fillRect(x, y + 12, 16, 4); if ((16 & nu[n]) != 0) g.fillRect(x, y + 12, 4, 16); if ((32 & nu[n]) != 0) g.fillRect(x, y + 24, 16, 4); if ((64 & nu[n]) != 0) g.fillRect(x + 12, y + 12, 4, 16); } public synchronized void paint(Graphics g) { for (int i = 0; i < sizeX; i++) for (int j = 0; j < sizeY; j++) { drawEmptyCell(g, i, j); if (board[i][j] != EMPTY) drawCellAt(g, i, j, board[i][j]); } if (!gameOver) drawPiece(g); drawScore(g); drawLevel(g); } public void pauseGame() { if (!gameOver) paused = !paused; if (paused) status = "Paused"; else status = ""; } public boolean keyUp(Event evt, int key) { if ("sSyYeEpPrR ".indexOf(key) != -1) { Graphics g = getGraphics(); try { switch (key) { case 's': case 'S': newGame(g); break; case 'y': case 'Y': if (!gameOver) { level++; drawLevel(g); } break; case 'e': case 'E': cellSize++; repaint(); break; case 'p': case 'P': pauseGame(); break; case 'r': case 'R': cellSize--; repaint(); break; case ' ': while (movePieceDown(g)) {}; incScore(3); break; default: } } finally { getToolkit().sync(); g.dispose(); } } return super.keyUp(evt, key); } public boolean keyDown(Event evt, int key) { if ("kK8jJ7lL9".indexOf(key) != -1) { Graphics g = getGraphics(); try { switch (key) { case 'k': case 'K': case '8': rotatePiece(g); break; case 'j': case 'J': case '7': movePieceLeft(g); break; case 'l': case 'L': case '9': movePieceRight(g); break; default: } } finally { getToolkit().sync(); g.dispose(); } } return super.keyDown(evt, key); } public boolean mouseUp(Event evt, int x, int y) { if (gameOver) { Graphics g = getGraphics(); try { newGame(g); } finally { getToolkit().sync(); g.dispose(); } } if (paused) pauseGame(); return super.mouseUp(evt, x, y); } public boolean lostFocus(Event evt, Object what) { if (!paused && !gameOver) pauseGame(); return super.lostFocus(evt, what); } static final byte[] nu = { 119, 68, 62, 110, 77, 107, 123, 70, 127, 111 }; static final byte EMPTY = 0; static final int pieceSize = 3; }