/** * Game "Bed-Bugs" * The idea of the game belongs to A. Ogourtsov (Moscow, 1986) * Written by V.Borisenko, vvb@mech.math.msu.su, Moscow State Univ., 1998 * * * */ import java.awt.*; import java.awt.event.*; import java.applet.Applet; import java.lang.Math; import java.util.Date; //... import java.text.NumberFormat; // Alas, not all browsers support // modern JDK :-( public class BedBugs extends Applet implements Runnable { static final int WIDTH = 60; static final int HEIGHT = 21; static final String wordTable[] = new String[] { //--- Java keywords "public", "class", "static", "protected", "final", "extends", "implements", "import", "if", "while", "finally", "try", "catch", "synchronized", "double", "int", "byte", "char", "private", "float", "interface", "boolean", "float", "new", "short", "long", "package", "throw", "throws", "continue", "abstract", "default", "do", "native", "void", "volatile", "true", "false", "super", "outer", "const", "null", "switch", "return" //--- }; final int MAX_NUM_WORDS = 4; int numWords = 2; Word words[] = new Word[MAX_NUM_WORDS]; byte field[][] = new byte[WIDTH][HEIGHT]; // Bits in field elements static final byte BIT_OFFSET_IN_WORD = (byte) 0x1f; // 0..31 static final byte BIT_WORD_NUMBER = (byte) 0x60; // Max. number of words = 4 static final byte CUR_POS = (byte) 0x80; // Current position static final byte EMPTY = (byte) 0xff; // Empty cell // Layout constants static final int LEFT_MARGIN = 5; static final int TOP_MARGIN = 5; static final int DX = 10; static final int DY = 16; static final int X_OFFSET = 2; // Offset for a character in a cell static final int Y_OFFSET = 12; // (DX, DY) static final int VERT_SKIP = 5; static final int HOR_SKIP = 4; static final int BUTTON_HEIGHT = 22; // Directions static final int DIR_RIGHT = 0; static final int DIR_UP = 1; static final int DIR_LEFT = 2; static final int DIR_DOWN = 3; static final int DIR_UNDEFINED = (-1); // Score constants static final int KILL_WORD_BONUS = 2; static final int KILL_LETTER_BONUS = 1; static final int BITE_BONUS = (-10); static final int ERROR_BONUS = (-2); // Score, time, etc. int nPoints; int nWordsKilled; int nErrors; int nChars; long startTime; // ms long curTime; // ms long finishTime; // ms int timeLeft; // sec //... NumberFormat numFormat = NumberFormat.getInstance(); final static int SESSION_TIME = 60; // Session in seconds // Window elements Label pointsLabel; Label points; Label timeLabel; Label time; Label wordsKilledLabel; Label wordsKilled; Label errorsLabel; Label errors; Label charsLabel; Label chars; Button start; Button stop; // Fonts Font bugFont = new Font("Courier", Font.BOLD, 14); Font myFont = new Font("Courier", Font.BOLD, 14); Font labelFont = new Font("TimesRoman", Font.BOLD, 14); Font gameOverFont = new Font("TimesRoman", Font.BOLD, 18); // Colors Color bugColor = Color.blue; Color myColor = Color.black; Color errorsColor = Color.blue; Color printedColor = Color.magenta; Color labelColor = Color.black; Color scoreColor = Color.blue; Color timeColor = Color.blue; Color charsColor = Color.blue; Color gameOverColor = Color.red; Color bloodColor = Color.red; String gameOverString = "Game over!"; // My position, printed word int posX = WIDTH / 2; int posY = HEIGHT / 2; long myMoveTime = 0; String printedWord = ""; String MY_LOCATION = "+"; int myDirection = DIR_UNDEFINED; // Temporary variables char curChar[] = new char[2]; boolean started = false; boolean gameOver = false; // Thread Thread gameThread = null; long dt = 125; // Time interval in ms (drop move) long moveDt = 2 * dt; // Word move interval static final long BLOODY_TIME = 500; // How long a bloody work lives boolean terminateGame = false; // Terminate a running thread // Blood drops static final int MAX_DROPS = 3; static final int DROP_RADIUS = DX * 2 / 5; static final int DROP_ARC_RADIUS = 2 * DROP_RADIUS; static final int DROP_ARC_START_ANGLE = 240; static final int DROP_ARC_SWEEP_ANGLE = 60; int dropsX[] = new int[MAX_DROPS]; int dropsY[] = new int[MAX_DROPS]; public static void main(String[] args) { class MyFrame extends Frame { MyFrame(String headline) { super(headline); } public boolean action(Event e, Object arg) { if (e.target instanceof MenuItem) { // We have only one "Quit" menu item... System.exit(0); } return false; } public boolean handleEvent(Event e) { if (e.id == Event.WINDOW_DESTROY) { System.exit(0); } return super.handleEvent(e); } }; Frame f = new MyFrame("Bed-Bugs"); f.setFont(new Font("Helvetica", Font.PLAIN, 14)); MenuBar mb = new MenuBar(); f.setMenuBar(mb); Menu fileMenu = new Menu("File"); fileMenu.add(new MenuItem("Quit")); mb.add(fileMenu); BedBugs bb = new BedBugs(); f.add("Center", bb); bb.init(); bb.start(); f.resize( 2*LEFT_MARGIN + WIDTH * DX + 16, // ??? 2*TOP_MARGIN + HEIGHT * DY + VERT_SKIP + BUTTON_HEIGHT + 24 // ??? + 30 // Menu bar width ); f.show(); } public void BedBugs() { //... numFormat.setMinimumFractionDigits(2); //... numFormat.setMaximumFractionDigits(2); initialize(false); } public void initialize(boolean putWords) { for (int x = 0; x < WIDTH; x++) { for (int y = 0; y < HEIGHT; y++) { field[x][y] = EMPTY; } } posX = WIDTH / 2; posY = HEIGHT / 2; field[posX][posY] = CUR_POS; printedWord = ""; myDirection = DIR_UNDEFINED; nPoints = 0; nWordsKilled = 0; nErrors = 0; nChars = 0; timeLeft = SESSION_TIME; points.setText("0"); time.setText("" + timeLeft); wordsKilled.setText("0"); errors.setText("0"); chars.setText("0"); start.enable(); stop.disable(); if (putWords) { curTime = (new Date()).getTime(); for (int i = 0; i < numWords; i++) { newWord(i); } } gameOver = false; for (int i = 0; i < MAX_DROPS; i++) dropsX[i] = (-1); myMoveTime = 0; repaint(); } public void init() { setLayout(null); resize( 2*LEFT_MARGIN + WIDTH * DX, 2*TOP_MARGIN + HEIGHT * DY + VERT_SKIP + BUTTON_HEIGHT ); setBackground(Color.lightGray); setForeground(Color.blue); setFont(bugFont); // Window elements int buttonY0 = TOP_MARGIN + HEIGHT * DY + VERT_SKIP; int x = LEFT_MARGIN; pointsLabel = new Label("Score:", Label.LEFT); pointsLabel.setFont(labelFont); pointsLabel.setForeground(labelColor); final int pointsLabelWidth = pointsLabel.getFontMetrics(labelFont).stringWidth("Score:") + 4; add(pointsLabel); pointsLabel.reshape(x, buttonY0, pointsLabelWidth, BUTTON_HEIGHT); x += pointsLabelWidth + HOR_SKIP; points = new Label("0", Label.LEFT); points.setFont(labelFont); points.setForeground(scoreColor); final int pointsWidth = points.getFontMetrics(labelFont).stringWidth("0000") + 4; add(points); points.reshape(x, buttonY0, pointsWidth, BUTTON_HEIGHT); x += pointsWidth + HOR_SKIP; wordsKilledLabel = new Label("Words killed:", Label.LEFT); wordsKilledLabel.setFont(labelFont); wordsKilledLabel.setForeground(labelColor); final int wordsKilledWidth = wordsKilledLabel.getFontMetrics(labelFont).stringWidth("Words killed:") + 4; add(wordsKilledLabel); wordsKilledLabel.reshape(x, buttonY0, wordsKilledWidth, BUTTON_HEIGHT); x += wordsKilledWidth + HOR_SKIP; wordsKilled = new Label("0", Label.LEFT); wordsKilled.setFont(labelFont); wordsKilled.setForeground(scoreColor); final int wordsWidth = wordsKilled.getFontMetrics(labelFont).stringWidth("000") + 4; add(wordsKilled); wordsKilled.reshape(x, buttonY0, wordsWidth, BUTTON_HEIGHT); x += wordsWidth + HOR_SKIP; errorsLabel = new Label("Errors:", Label.LEFT); errorsLabel.setFont(labelFont); errorsLabel.setForeground(labelColor); final int errorsLabelWidth = errorsLabel.getFontMetrics(labelFont).stringWidth("Errors:") + 4; add(errorsLabel); errorsLabel.reshape(x, buttonY0, errorsLabelWidth, BUTTON_HEIGHT); x += errorsLabelWidth + HOR_SKIP; errors = new Label("0", Label.LEFT); errors.setFont(labelFont); errors.setForeground(errorsColor); final int errorsWidth = errors.getFontMetrics(labelFont).stringWidth("000") + 4; add(errors); errors.reshape(x, buttonY0, errorsWidth, BUTTON_HEIGHT); x += errorsWidth + HOR_SKIP; timeLabel = new Label("Time left:", Label.LEFT); timeLabel.setFont(labelFont); timeLabel.setForeground(labelColor); final int timeLabelWidth = timeLabel.getFontMetrics(labelFont).stringWidth("Time left:") + 4; add(timeLabel); timeLabel.reshape(x, buttonY0, timeLabelWidth, BUTTON_HEIGHT); x += timeLabelWidth + HOR_SKIP; time = new Label("0", Label.LEFT); time.setFont(labelFont); time.setForeground(timeColor); final int timeWidth = time.getFontMetrics(labelFont).stringWidth("00") + 4; add(time); time.reshape(x, buttonY0, timeWidth, BUTTON_HEIGHT); x += errorsWidth + HOR_SKIP; charsLabel = new Label("Chars/sec:", Label.LEFT); charsLabel.setFont(labelFont); charsLabel.setForeground(labelColor); final int charsLabelWidth = charsLabel.getFontMetrics(labelFont).stringWidth("Time left:") + 4; add(charsLabel); charsLabel.reshape(x, buttonY0, charsLabelWidth, BUTTON_HEIGHT); x += charsLabelWidth + HOR_SKIP; chars = new Label("0.00", Label.LEFT); chars.setFont(labelFont); chars.setForeground(charsColor); final int charsWidth = chars.getFontMetrics(labelFont).stringWidth("00.00") + 4; add(chars); chars.reshape(x, buttonY0, charsWidth, BUTTON_HEIGHT); x += charsWidth + HOR_SKIP; int buttonX1 = LEFT_MARGIN + WIDTH * DX; stop = new Button("Stop"); stop.setFont(labelFont); stop.setForeground(labelColor); final int stopWidth = stop.getFontMetrics(labelFont).stringWidth("Stop") + 8; add(stop); x = buttonX1 - stopWidth; stop.reshape(x, buttonY0, stopWidth, BUTTON_HEIGHT); x -= HOR_SKIP; start = new Button("Start"); start.setFont(labelFont); start.setForeground(labelColor); final int startWidth = start.getFontMetrics(labelFont).stringWidth("Start") + 8; add(start); x -= startWidth; start.reshape(x, buttonY0, startWidth, BUTTON_HEIGHT); x -= HOR_SKIP; initialize(false); requestFocus(); } public boolean keyDown(Event e, int key) { if (e.id == Event.KEY_PRESS) { if (key == Event.BACK_SPACE) { onBackSpace(); } else if (key == Event.ENTER) { onEnter(); } else if (key < 32) { // System.out.println("Control character: key = " + key); } else { onKey((char) key); } } else if (e.id == Event.KEY_ACTION) { if (key == Event.BACK_SPACE) { onBackSpace(); } else if (key == Event.ENTER) { onEnter(); } else if (key == Event.RIGHT) { myDirection = DIR_RIGHT; } else if (key == Event.UP) { myDirection = DIR_UP; } else if (key == Event.LEFT) { myDirection = DIR_LEFT; } else if (key == Event.DOWN) { myDirection = DIR_DOWN; } } return false; } synchronized void onEnter() { if (!started && gameThread == null) { onStart(); return; } else if (gameThread == null) { return; } requestFocus(); long t = (new Date()).getTime(); boolean charsAdded = false; for (int i = 0; i < numWords; i++) { Word w = words[i]; if (printedWord.equalsIgnoreCase(w.getString())) { int l = w.length(); nWordsKilled++; wordsKilled.setText("" + nWordsKilled); nPoints += KILL_WORD_BONUS + l * KILL_LETTER_BONUS; points.setText("" + nPoints); if (!charsAdded) { nChars += l; //... double rate = ((double) nChars) / //... (((double)(t - startTime)) / 1000.); // Convert to string in the form ddd.dd //... chars.setText( //... numFormat.format(rate) //... ); chars.setText(charRate(t - startTime)); charsAdded = true; } System.out.println("Word killed: " + w.getString()); removeWord(i); newWord(i); w = words[i]; } w.setPrinted(0); } if (!charsAdded) { System.out.println("Word printed with mistake: " + printedWord); nErrors++; errors.setText("" + nErrors); nPoints += ERROR_BONUS; points.setText("" + nPoints); } printedWord = ""; repaintCell(posX, posY); } synchronized void onKey(char k) { if (gameThread == null) { return; } requestFocus(); char key = Character.toLowerCase(k); int l = printedWord.length(); printedWord += key; for (int i = 0; i < numWords; i++) { Word w = words[i]; int lw = w.length(); int p = w.getPrinted(); if (p == l && p < lw && w.charAt(p) == key) { w.setPrinted(p+1); repaintCell(w.coordx[p], w.coordy[p]); } else { if (p != 0) { w.setPrinted(0); repaintWord(i); } } } repaintCell(posX, posY); } synchronized void onBackSpace() { if (gameThread == null) { return; } requestFocus(); int l = printedWord.length(); if (l > 0) { try { printedWord = printedWord.substring(0, l-1); } catch (StringIndexOutOfBoundsException e) { printedWord = ""; } } repaintCell(posX, posY); l = printedWord.length(); for (int i = 0; i < numWords; i++) { Word w = words[i]; int lw = w.length(); if ( lw >= l && w.getString().substring(0, l).equalsIgnoreCase(printedWord) ) { w.setPrinted(l); } else { w.setPrinted(0); } repaintWord(i); } } public void start() { requestFocus(); } public boolean action(Event e, Object arg) { Object source = e.target; requestFocus(); if (source == start) { onStart(); } else if (source == stop) { onStop(); } else { return true; } return false; } public void onStart() { if (gameThread != null) { return; } requestFocus(); started = true; initialize(true); terminateGame = false; gameThread = new Thread(this, "Game_Thread"); start.disable(); stop.enable(); gameThread.start(); } public void onStop() { if (gameThread != null) { terminateGame = true; } } public void paint(Graphics g) { g.drawRect( LEFT_MARGIN, TOP_MARGIN, WIDTH * DX, HEIGHT * DY ); // Words for (int i = 0; i < numWords; i++) { paintWord(g, i); } // My position int lPrinted = 0; if (printedWord != null) lPrinted = printedWord.length(); g.setColor(myColor); g.setFont(myFont); int xpos = LEFT_MARGIN + posX * DX; int ypos = TOP_MARGIN + posY * DY; if (lPrinted == 0) { g.drawString( MY_LOCATION, xpos + X_OFFSET, ypos + Y_OFFSET ); } else { curChar[0] = printedWord.charAt(lPrinted - 1); g.drawChars( curChar, 0, 1, xpos + X_OFFSET, ypos + Y_OFFSET ); } paintDrops(g); // Message after end of game if (gameOver) { g.setFont(gameOverFont); g.setColor(gameOverColor); g.drawString( gameOverString, LEFT_MARGIN + (WIDTH / 2 - 10) * DX, TOP_MARGIN + 10 * DY ); } } synchronized void newWord(int i) { int x = 0, y = 0; // Select a random word from a table int n = (int)(Math.random() * wordTable.length - 0.001); Word w = new Word(wordTable[n], curTime); words[i] = w; int l = w.length(); // 10 attempts to put a word in the field boolean selected = false; for (int j = 0; !selected && j < 10; j++) { // Random coordinates x = (int)(Math.random() * HEIGHT - l - 0.001); if (x < 0) x = 0; y = (int)(Math.random() * HEIGHT - 0.001); // Check whether field is free selected = true; for (int k = 0; selected && k < l; k++) { selected = (field[x + k][y] == EMPTY); } } if (!selected) { System.out.println("Cannot put a word in the field"); return; } // Fill in the coordinates of letters and field entries int xx = x; byte wordBits = (byte)(i << 5); for (int k = 0; k < l; k++, xx++) { w.coordx[k] = (byte) xx; w.coordy[k] = (byte) y; byte b = (byte) k; b |= wordBits; field[xx][y] = b; } // redraw a word repaint( LEFT_MARGIN + x * DX, TOP_MARGIN + y * DY, DX * l + 4, DY ); } public void run() { System.out.println("Starting game session."); requestFocus(); startTime = (new Date()).getTime(); curTime = startTime; long endTime = startTime + SESSION_TIME * 1000; int tLeft; gameOver = false; requestFocus(); myMoveTime = startTime; while (!terminateGame && gameThread != null && curTime < endTime) { try { gameThread.sleep(dt); } catch (InterruptedException e) { System.out.println("" + e); } curTime = (new Date()).getTime(); for (int i = 0; i < numWords; i++) { if (!(words[i].bloody)) { moveWord(i); } else if (curTime - words[i].biteTime >= BLOODY_TIME) { removeWord(i); newWord(i); } } moveMe(); moveDrops(); tLeft = SESSION_TIME - (int)((curTime - startTime) / 1000); if (tLeft < 0) tLeft = 0; if (tLeft != timeLeft) { timeLeft = tLeft; time.setText("" + timeLeft); } } finishTime = (new Date()).getTime(); gameThread = null; terminateGame = false; onGameEnd(); } // Format double number to the form dd.ddd String charRate(long dt) { if (dt <= 0) dt = 1; double rate = ((double) nChars) / (((double) dt) / 1000.); int fract = (int)((rate - Math.floor(rate)) * 100. + 0.49); return ( "" + ((int) rate) + "." + (fract / 10) + (fract % 10) ); } void onGameEnd() { /*... System.out.println( "startTime=" + startTime + " finishTime=" + endTime ); ...*/ long dt = finishTime - startTime; if (dt <= 0) dt = 1; double rate = ((double) nChars) / (((double) dt) / 1000.); //... String rateText = numFormat.format(rate); String rateText = charRate(dt); gameOverString = "Game over!"; if (rate >= 2.) { gameOverString = "Game over, good result!"; } if (rate >= 2.5) { gameOverString = "Game over, excelent performance!"; } if (rate >= 3.) { gameOverString = "Game over, fantastic result!"; } System.out.println( "Game over. Points: " + nPoints + ". Chars typed: " + nChars + " (rate " + rateText + " chars/sec)." ); chars.setText(rateText); gameOver = true; start.enable(); stop.disable(); repaint(); } synchronized void moveWord(int i) { Word w = words[i]; if (w == null) return; int l = w.length(); if (l <= 0) return; if (curTime - w.moveTime < moveDt) return; int leftx = w.coordx[0]; int lefty = w.coordy[0]; int lDist = Math.abs(posX - leftx) + Math.abs(posY - lefty); int rightx = w.coordx[l - 1]; int righty = w.coordy[l - 1]; int rDist = Math.abs(posX - rightx) + Math.abs(posY - righty); if (rDist <= 1 || lDist <= 1) { bite(i); // Ouhh... return; } if (rDist <= lDist) { // Move right end of word int dx = posX - rightx; int dy = posY - righty; int newx = rightx; int newy = righty; if (posX > rightx || posY == righty) { // Move horizontally if (rightx < WIDTH - 1) newx = rightx + 1; if (posX < rightx) newx = rightx - 1; } else { // Move vertically if (righty < HEIGHT - 1) newy = righty + 1; if (posY < righty) newy = righty - 1; } byte b = field[newx][newy]; if (b == CUR_POS) { bite(i); return; } else if (b != EMPTY) { if (rightx < WIDTH - 1) { newx = rightx + 1; newy = righty; } else if (righty < HEIGHT - 1) { newy = righty + 1; newx = rightx; } b = field[newx][newy]; } if (b == EMPTY) { field[leftx][lefty] = EMPTY; repaintCell(leftx, lefty); w.moveRight(newx, newy, curTime); drawWord(i); } } else { // Move left end of word int dx = posX - leftx; int dy = posY - lefty; int newx = leftx; int newy = lefty; if (posX < leftx || posY == lefty) { // Move horizontally if (leftx > 0) newx = leftx - 1; if (posX > leftx) newx = leftx + 1; } else { // Move vertically if (lefty > 0) newy = lefty - 1; if (posY > lefty) newy = lefty + 1; } byte b = field[newx][newy]; if (b == CUR_POS) { bite(i); return; } else if (b != EMPTY) { if (leftx > 0) { newx = leftx - 1; newy = lefty; } else if (lefty > 0) { newy = lefty - 1; newx = leftx; } b = field[newx][newy]; } if (b == EMPTY) { field[rightx][righty] = EMPTY; repaintCell(rightx, righty); w.moveLeft(newx, newy, curTime); drawWord(i); } } } synchronized void drawWord(int i) { Word w = words[i]; if (w == null) return; int l = w.length(); byte wordBits = (byte)(i << 5); for (int k = 0; k < l; k++) { int x = w.coordx[k]; int y = w.coordy[k]; byte b = (byte) k; b |= wordBits; field[x][y] = b; repaintCell(x, y); } } synchronized void paintWord(Graphics g, int i) { Word w = words[i]; if (w == null) return; int l = w.length(); int p = w.getPrinted(); g.setFont(bugFont); g.setColor(printedColor); if (w.bloody) g.setColor(bloodColor); for (int k = 0; k < l; k++) { int xpos = LEFT_MARGIN + w.coordx[k] * DX; int ypos = LEFT_MARGIN + w.coordy[k] * DY; if (!w.bloody) { if (k < p) g.setColor(printedColor); else g.setColor(bugColor); } curChar[0] = w.charAt(k); g.drawChars( curChar, 0, 1, xpos + X_OFFSET, ypos + Y_OFFSET ); } } void repaintWord(int i) { Word w = words[i]; if (w == null) return; int l = w.length(); for (int k = 0; k < l; k++) { int x = w.coordx[k]; int y = w.coordy[k]; repaintCell(x, y); } } void repaintCell(int x, int y) { repaint( LEFT_MARGIN + x * DX, TOP_MARGIN + y * DY, DX + 4, DY ); } void paintDrops(Graphics g) { for (int i = 0; i < MAX_DROPS; i++) { if (dropsX[i] >= 0) paintDrop(g, i); } } void paintDrop(Graphics g, int i) { int x = dropsX[i]; int y = dropsY[i]; g.setColor(bloodColor); int xpos = LEFT_MARGIN + x * DX + DX / 2; int ypos = LEFT_MARGIN + (y + 1) * DY - DROP_RADIUS - 1; final int R2 = 2 * DROP_RADIUS; final int R4 = 2 * R2; g.fillOval( xpos - DROP_RADIUS, ypos - DROP_RADIUS, R2, R2 ); g.fillArc( xpos - R2, ypos - R4, 2 * R2, 2 * R2, DROP_ARC_START_ANGLE, DROP_ARC_SWEEP_ANGLE ); } synchronized void bite(int i) { // Oohh... System.out.println("Bite, oouhh..."); nPoints += BITE_BONUS; // Negative points.setText("" + nPoints); words[i].biteTime = (new Date()).getTime(); words[i].bloody = true; repaintWord(i); // Blood drop // Find an empty element in the array of drops int d = 0; while (d < MAX_DROPS && dropsX[d] >= 0) d++; if (d < MAX_DROPS) { dropsX[d] = posX; dropsY[d] = posY; } repaintCell(posX, posY); } synchronized void removeWord(int i) { Word w = words[i]; int l = w.length(); for (int k = 0; k < l; k++) { int x = (int) w.coordx[k]; int y = (int) w.coordy[k]; field[x][y] = EMPTY; repaintCell(x, y); } } synchronized void moveMe() { // Fly away from terrible bed-bugs if (myDirection == DIR_UNDEFINED) return; if (curTime - myMoveTime < moveDt) return; myMoveTime = curTime; int newx = posX; int newy = posY; if (myDirection == DIR_RIGHT && newx < WIDTH-1) newx++; if (myDirection == DIR_UP && newy > 0) newy--; if (myDirection == DIR_LEFT && newx > 0) newx--; if (myDirection == DIR_DOWN && newy < HEIGHT-1) newy++; if (newx != posX || newy != posY) { field[posX][posY] = EMPTY; repaintCell(posX, posY); posX = newx; posY = newy; field[posX][posY] = CUR_POS; repaintCell(posX, posY); } else { myDirection = DIR_UNDEFINED; } } synchronized void moveDrops() { for (int i = 0; i < MAX_DROPS; i++) { int x = dropsX[i]; if (x < 0) continue; int y = dropsY[i]; if (y >= HEIGHT - 1) { dropsX[i] = (-1); // Release the array element } else { dropsY[i]++; // Move the drop down } repaintCell(x, y); if (dropsX[i] >= 0) repaintCell(x, y + 1); } } } class Word { String word; int printed; // Length of the printed part of the word byte coordx[]; byte coordy[]; boolean bloody; long biteTime; long moveTime; public Word(String s, long curTime) { int l = s.length(); word = s; printed = 0; coordx = new byte[l]; coordy = new byte[l]; bloody = false; biteTime = 0; moveTime = curTime; } public char charAt(int i) { char c = ' '; try { c = word.charAt(i); } catch (StringIndexOutOfBoundsException e) { System.out.println("" + e); } return c; } public String getString() { return word; } public int getPrinted() { return printed; } public void setPrinted(int l) { printed = l; } public void moveRight(int newx, int newy, long curTime) { int l = word.length(); for (int i = 0; i < l - 1; i++) { coordx[i] = coordx[i + 1]; coordy[i] = coordy[i + 1]; } coordx[l - 1] = (byte) newx; coordy[l - 1] = (byte) newy; moveTime = curTime; } public void moveLeft(int newx, int newy, long curTime) { int l = word.length(); for (int i = l - 1; i > 0; i--) { coordx[i] = coordx[i - 1]; coordy[i] = coordy[i - 1]; } coordx[0] = (byte) newx; coordy[0] = (byte) newy; moveTime = curTime; } public boolean isPrinted(int i) { return (i < printed); } public int length() { return word.length(); } }