// Author: Krishnan Pillaipakkamnatt (csckzp@hofstra.edu) // Date: Jan 16, 1997 import java.awt.*; import java.applet.*; public class Tetris extends Applet implements Runnable { private TetrisFrame frame; private TetrisBlock block; private Graphics g; public void start ( ) { ( new Thread ( this ) ).start ( ); } public void update ( Graphics g ) { if ( frame != null ) frame.redraw ( ); if ( block != null ) block.redraw ( ); } public void run ( ) { g = getGraphics ( ); frame = new TetrisFrame ( g, this ); while ( frame.isNotFull ( ) ) { block = new TetrisBlock ( frame, g ); while ( block.canFall ( ) ) { block.down ( ); repaint ( ); try { Thread.sleep ( 400 ); } catch ( Exception e ) { } } frame.update ( block ); repaint ( ); block = null; } } public boolean keyDown ( Event event, int key ) { char c = ( char ) key; if ( block != null ) { switch ( c ) { case 'h': block.moveLeft ( ); break; case 'l': block.moveRight ( ); break; case 'j': block.rotateLeft ( ); break; case 'k': block.rotateRight ( ); break; case ' ': while ( block.canFall ( ) ) block.down ( ); break; } } return true; } } class TetrisFrame { private boolean grid [ ] [ ] = new boolean [ 20 ] [ 10 ]; private Graphics g, my_g; Image side; Applet p; public TetrisFrame ( Graphics gr, Applet parent ) { g = gr; g.setColor ( Color.white ); g.fillRect ( 0, 0, 100, 200 ); side = parent.createImage(105,205); my_g = side.getGraphics(); p = parent; } public boolean isNotFull ( ) { return ! grid [ 0 ] [ 4 ] ; } public void update ( TetrisBlock block ) { int i, j, k, r, c; boolean rowfull; r = block.getRow ( ); c = block.getCol ( ); for ( i = 0; i <= 3; i ++ ) for ( j = 0; j <= 3; j ++ ) if ( ( i + r >= 0 ) && ( j +c >= 0 ) && ( i + r <= 19 ) && ( j + c <= 9 ) ) grid [ i + r ] [ j + c ] |= block.getCellValue (i,j); for ( i = 19; i >= 0; i -- ) { rowfull = true; for ( j = 0; j <= 9; j++ ) if ( ! grid [ i ] [ j ] ) rowfull = false; if ( rowfull ){ for ( k = i - 1 ; k >= 1 ; k -- ) for ( j = 0; j <= 9; j ++ ) grid [ k + 1 ] [ j ] = grid [ k ] [ j ]; for ( j = 0; j <= 9; j ++ ) grid [ 0 ] [ j ] = false; i = i + 1; } } } public void redraw ( ) { int i, j; // g.setColor ( Color.white ); // g.fillRect ( 0, 0, 100, 200 ); my_g.setColor ( Color.black ); for ( i = 0; i <= 19; i ++) for ( j = 0; j <= 9; j ++){ if ( grid [ i ] [ j ] ) my_g.setColor ( Color.black ); else my_g.setColor ( Color.white ); my_g.fillRect ( 10 * j + 1, 10 * i + 1, 8, 8 ); } g.drawImage(side,0,0,p); } public boolean getRowCol ( int Row, int Col ) { return grid [ Row ] [ Col ]; } } class TetrisBlock { private boolean cells [ ] [ ] = new boolean [ 4 ] [ 4 ]; private Graphics g; private TetrisFrame f; private int row, col; public TetrisBlock ( TetrisFrame fr, Graphics gr ) { double flip = 7 * Math.random ( ); f = fr; g = gr; col = 4; if ( flip <= 1 ) { cells [ 0 ] [ 1 ] = true; cells [ 1 ] [ 1 ] = true; cells [ 2 ] [ 1 ] = true; cells [ 3 ] [ 1 ] = true; } else if ( flip <= 2 ) { cells [ 0 ] [ 0 ] = true; cells [ 0 ] [ 1 ] = true; cells [ 0 ] [ 2 ] = true; cells [ 1 ] [ 2 ] = true; } else if ( flip <= 3 ) { cells [ 0 ] [ 1 ] = true; cells [ 0 ] [ 2 ] = true; cells [ 0 ] [ 3 ] = true; cells [ 1 ] [ 1 ] = true; } else if ( flip <= 4 ) { cells [ 0 ] [ 0 ] = true; cells [ 0 ] [ 1 ] = true; cells [ 1 ] [ 1 ] = true; cells [ 1 ] [ 2 ] = true; } else if ( flip <= 5 ) { cells [ 0 ] [ 2 ] = true; cells [ 0 ] [ 3 ] = true; cells [ 1 ] [ 1 ] = true; cells [ 1 ] [ 2 ] = true; } else if ( flip <= 6 ) { cells [ 1 ] [ 1 ] = true; cells [ 1 ] [ 2 ] = true; cells [ 2 ] [ 1 ] = true; cells [ 2 ] [ 2 ] = true; } else { cells [ 0 ] [ 1 ] = true; cells [ 1 ] [ 0 ] = true; cells [ 1 ] [ 1 ] = true; cells [ 1 ] [ 2 ] = true; } } public boolean canFall ( ) { return isValid ( cells , row + 1, col); } public void down ( ) { if ( isValid ( cells, row + 1, col ) ){ erase ( cells, row , col ); row ++; draw ( cells, row, col ); } } public void moveLeft ( ) { if ( isValid ( cells, row, col - 1 ) ){ erase ( cells, row, col ); col --; draw ( cells, row, col ); } } public void moveRight ( ) { if ( isValid ( cells, row, col + 1 ) ){ erase ( cells, row, col ); col ++; draw ( cells, row, col ); } } public void rotateRight ( ) { int i, j; boolean config [ ] [ ] = new boolean [ 4 ] [ 4 ]; for ( i = 0; i <= 3; i ++ ) for ( j = 0; j <= 3; j ++ ) config [ j ] [ 3 - i ] = cells [ i ] [ j ]; if ( isValid ( config, row, col ) ){ erase ( cells, row, col ); cells = config; draw ( cells, row, col ); } } public void rotateLeft ( ) { int i, j; boolean config [ ] [ ] = new boolean [ 4 ] [ 4 ]; for ( i = 0; i <= 3; i ++ ) for ( j = 0; j <= 3; j ++ ) config [ i ] [ j ] = cells [ j ] [ 3 - i ]; if ( isValid ( config, row, col ) ){ erase ( cells, row, col ); cells = config; draw ( cells, row, col ); } } private boolean isValid ( boolean config [ ] [ ], int r, int c ) { int i, j; for ( i = 0; i <= 3; i ++ ){ for ( j = 0; j <= 3; j ++ ){ if ( config [ i ] [ j ] ) { if ( ( r + i > 19 ) || ( c + j > 9 ) || ( c + j < 0 ) || f.getRowCol ( r + i, c + j ) ) return false; } } } return true; } synchronized private void display ( boolean config [ ] [ ], int r, int c, Color color ) { int i, j; g.setColor ( color ); for ( i = 0; i <= 3; i ++) for ( j = 0; j <= 3; j ++) if ( config [ i ] [ j ] ) g.fillRect ( 10 * ( j + c ) + 1, 10 * ( i + r ) + 1, 8, 8 ); } private void erase ( boolean config [ ] [ ], int r, int c ) { display ( config, r, c, Color.white ); } private void draw ( boolean config [ ] [ ], int r, int c ) { display ( config, r, c, Color.black ); } public void redraw ( ) { erase ( cells, row, col ); draw ( cells, row, col ); } public int getRow ( ) { return row; } public int getCol ( ) { return col; } public boolean getCellValue ( int r, int c ) { return cells [ r ] [ c ]; } }