//*********************** Copy right information ************************* // FAQ's // Q. Is this program copy right protected? // Ans. Yes and we won a million dollor from the person who copied our // last program // Q. What do I do if I find a bug? // Ans. You decide. You are a grown up person. // Q. Where is the code documentation? // Ans. Somebody robbed us of it. // Q. How was the code tested and to what degree? // Ans. This information is classified. If you ask that question again we // may have to report you to FBI // //************************************************************************ // Program: Reversi game program // Programmer: H K Gupta Date: 15 July 1997 // 02 Feb 1999 Modified //************************************************************************ import java.awt.*; import java.applet.Applet; import java.lang.Math; public class Reversi extends Applet implements Runnable { Panel pStatus; Label lReversi; // name label Label lLevel; Panel pLevel; Button[] bLevel; // Allow the user different complexities Button bHelp; Button bEasy; boolean easyFlag = true; Button bMoron; Button bNewGame; Label lUserColor; Button bPass; Label lComments; ReversiSelect pMain; // Main Panel Panel pSnake; // show percents Label lYouAndMe; HridayeshSnake pResult; int[][] bGrid; // n * n grid boolean[][] sGrid; // Shadow grid to show cascade effect int[][] tGrid; // temp buffer to hold bGrid int[][] rGrid; // for holding result matrix int minLevel = 8; // Minimum level int nLevel = minLevel; // Default level int totalLevels = 5; boolean userFirst = true; int userColor = 2; // first one to move uses blue boolean gameOver = true; boolean moronFlag = false; boolean firstTime = true; boolean pauseInEffect = false; Thread runThread = null; public void start() { if (firstTime) { setupDisplay() ; startNewGame(); firstTime = false; } if (runThread == null) { if(!pauseInEffect) { runThread = new Thread(this, "Reversi"); runThread.start(); } } } public void run() { while (Thread.currentThread() == runThread) { nextAction(); try {Thread.sleep(40);} catch (InterruptedException e){} } } int nextActionType = 0; int waitCount = 0; void nextAction() { if(waitCount > 0) { waitCount--; return; } switch (nextActionType) { case 1: //user Move wait break; case 2: // Convert After user move lComments.setText("***********"); removeHelpToMorons(); convert(lastX, lastY); // convert intervening tiles to this tile color saveLastMoveColor(); pMain.updateGrid(); waitCount = 5; nextActionType = 3; break; case 3: // Cascade after user move and convert if(!cascade()){ restoreLastMoveColor(); if(checkWinOrOver()) { updateResult(); nextActionType = 0; return; } waitCount = 15; updateResult(); nextActionType = 4; } break; case 4: // Computer move, check for pass lComments.setText("***********"); if(!computerMove()) { beNiceToMorons(); pMain.updateGrid(); nextActionType = 1; break; } pMain.updateGrid(); waitCount = 5; nextActionType = 5; break; case 5: // convert after computer move convert(lastX, lastY); // convert intervening tiles to this tile color saveLastMoveColor(); pMain.updateGrid(); waitCount = 5; nextActionType = 6; break; case 6: // Cascade after computer move and convert if(!cascade()){ restoreLastMoveColor(); if(checkWinOrOver()) { updateResult(); nextActionType = 0; break; } checkPass(); waitCount = 5; updateResult(); beNiceToMorons(); pMain.updateGrid(); nextActionType = 1; lComments.setText("Your move"); } break; default: } } public void stop() {runThread = null;} boolean cascade() { for(int i = 0; i < nLevel; i++) { for(int j = 0; j < nLevel; j++) { if(sGrid[i][j]) { sGrid[i][j] = false; pMain.updateGrid(); waitCount = 10; return true; } } } return false; } void setupDisplay() { setLayout(new BorderLayout()); pStatus = new Panel(); pStatus.setLayout(new GridLayout(0, 1)); add("West", pStatus); lReversi = new Label("REVERSI", Label.CENTER); lReversi.setFont(new Font("TimesRoman",Font.BOLD,30)); lReversi.setForeground(Color.blue); pStatus.add(lReversi); lLevel = new Label("Level", Label.CENTER); pStatus.add(lLevel); pLevel = new Panel(); pLevel.setLayout(new GridLayout(0, totalLevels)); pStatus.add(pLevel); bLevel = new Button[totalLevels]; for(int i = 0; i < totalLevels; i++) { bLevel[i] = new Button("" + (i + minLevel)); pLevel.add(bLevel[i]); } bHelp = new Button("Help"); pStatus.add(bHelp); bEasy = new Button("Make Life Difficult"); pStatus.add(bEasy); bMoron = new Button("Moron"); pStatus.add(bMoron); bNewGame = new Button("New Game"); pStatus.add(bNewGame); lUserColor = new Label("", Label.CENTER); pStatus.add(lUserColor); bPass = new Button(""); bPass.disable(); pStatus.add(bPass); lComments = new Label("", Label.CENTER); pStatus.add(lComments); createGridBuffers(nLevel); pMain = new ReversiSelect(this); add("Center", pMain); pSnake = new Panel(); pSnake.setLayout(new BorderLayout()); add("East", pSnake); lYouAndMe = new Label("YOU ME", Label.CENTER); pSnake.add("North", lYouAndMe); pResult = new HridayeshSnake(); pSnake.add("Center", pResult); setUpGrid(); validate(); } public boolean action(Event e, Object arg) { Object target = e.target; for(int i = 0; i < totalLevels; i++) { if(target == bLevel[i]) { if(nLevel == i + minLevel) return true; nextActionType = 0; nLevel = i + minLevel; createGridBuffers(nLevel); pMain.changeSize(); startNewGame(); return true; } } if(target == bNewGame) { startNewGame(); return true; } if(target == bHelp) { processHelp(); return true; } if(target == bEasy) { if(easyFlag) { bEasy.setLabel("Make it easy PLEASE"); } else { bEasy.setLabel("Make life difficult"); } easyFlag = !easyFlag; return true; } if(target == bMoron) { moronFlag = !moronFlag; if(moronFlag) { bMoron.setLabel("I am a MORON"); } else { bMoron.setLabel("Moron"); } beNiceToMorons(); pMain.updateGrid(); } if(target == bPass) { bPass.setLabel(""); bPass.disable(); nextActionType = 4; // Computer move return true; } return false; } void createGridBuffers(int nLevel) { bGrid = new int[nLevel][nLevel]; sGrid = new boolean[nLevel][nLevel]; tGrid = new int[nLevel][nLevel]; rGrid = new int[nLevel][nLevel]; } int lastX = 0; int lastY = 0; void userMove(int x, int y) { if(nextActionType != 1) return; if(!verifyMove(userColor, x, y)) return; bGrid[x][y] = userColor; lastX = x; lastY = y; nextActionType = 2; pMain.updateGrid(); } int lastColor = 0; void saveLastMoveColor() { lastColor = bGrid[lastX][lastY]; bGrid[lastX][lastY] = 3; // black color } void restoreLastMoveColor() { bGrid[lastX][lastY] = lastColor; } void checkPass() { for(int i = 0; i < nLevel; i++) { for(int j = 0; j < nLevel; j++) { if(bGrid[i][j] < 1) { if(verifyMove(userColor, i, j)) { return; // user has a move } } } } bPass.setLabel("Pass"); bPass.enable(); lComments.setText("No move. You must Pass"); } void beNiceToMorons() { // Morons are essential part of our society. HELP them understand this game if(gameOver) return; removeHelpToMorons(); if(moronFlag) { for(int i = 0; i < nLevel; i++) { for(int j = 0; j < nLevel; j++) { // draw a big green dot to help our friends if(bGrid[i][j] < 1) { if(verifyMove(userColor, i, j)) bGrid[i][j] = 0; } } } } } void removeHelpToMorons() { for(int i = 0; i < nLevel; i++) { for(int j = 0; j < nLevel; j++) { // remove old help if(bGrid[i][j] == 0) bGrid[i][j] = -1; } } } void convert(int x, int y) { for(int i = -1; i < 2; i++) { for(int j = -1; j < 2; j++) { if(tryMove(bGrid[x][y], x, y, i, j)) { // we see a tile of same color on the distant horizon convertNow(bGrid[x][y], x, y, i, j); } } } } void convertNow(int type, int x, int y, int iInc, int jInc) { int i, j; for(int k = 1; k < nLevel; k++) { // try till end of grid i = x + k * iInc; j = y + k * jInc; // we are lazy. do not want to write again and again if((i < 0) || (i >= nLevel) || (j < 0) || (j >= nLevel)) return; if(bGrid[i][j] == type) return ; if(bGrid[i][j] < 1) return ; bGrid[i][j] = type; sGrid[i][j] = true; // set up for cascade effect } } boolean verifyMove(int type, int x, int y) { if(bGrid[x][y] > 0) return false; // spot occupied for(int i = -1; i < 2; i++) for(int j = -1; j < 2; j++) if(tryMove(type, x, y, i, j)) return true; return false; } boolean tryMove(int type, int x, int y, int iInc, int jInc) { if((iInc == 0) && (jInc == 0)) return false; boolean oppFlag = false; int i, j; for(int k = 1; k < nLevel; k++) { // try till end of grid i = x + k * iInc; j = y + k * jInc; // we are lazy. do not want to write again and again if((i < 0) || (i >= nLevel) || (j < 0) || (j >= nLevel)) return false; if(bGrid[i][j] == type) return oppFlag; if(bGrid[i][j] < 1) return false; oppFlag = true; } return false; } boolean checkWinOrOver() { int totalOnes = 0; int totalTwos = 0; for(int i = 0; i < nLevel; i++) { for(int j = 0; j < nLevel; j++) { if(bGrid[i][j] == 1) totalOnes++; if(bGrid[i][j] == 2) totalTwos++; } } if(totalOnes == 0) return won(2); // 2's won if(totalTwos == 0) return won(1); // 1's won if((totalOnes + totalTwos) == nLevel * nLevel) { if(totalOnes > totalTwos) return won(1); if(totalOnes < totalTwos) return won(2); return won(0); // Draw } return false; } boolean won(int type) { switch(type) { case 0: lComments.setText("Game Draw"); break; case 1: if (userColor == 1) { lComments.setText("You WON"); } else { lComments.setText("You LOST"); } break; case 2: if (userColor == 2) { lComments.setText("You WON"); } else { lComments.setText("You LOST"); } break; default: } gameOver = true; return true; } boolean computerMove() { // scratching our brain on how best to move for(int i = 0; i < nLevel; i++) // save bGrid for(int j = 0; j < nLevel; j++) tGrid[i][j] = bGrid[i][j]; int type = 3 - userColor; for(int i = 0; i < nLevel; i++) { for(int j = 0; j < nLevel; j++) { rGrid[i][j] = -50000; // useless place if(bGrid[i][j] < 1) { if(verifyMove(type, i, j)) { bGrid[i][j] = type; convert(i, j); calculateValue(type, i, j); restoreBGrid(); } } } } for(int i = 0; i < nLevel; i++) { for(int j = 0; j < nLevel; j++) { sGrid[i][j] = false; } } int bestValue = rGrid[0][0]; int bestCount = 1; for(int i = 0; i < nLevel; i++) { for(int j = 0; j < nLevel; j++) { if(bestValue < rGrid[i][j]) { bestValue = rGrid[i][j]; bestCount = 1; } else { if(bestValue == rGrid[i][j]) bestCount++; } } } if(bestValue == -50000) { // No move possible so pass lComments.setText("I pass. Your move"); return false; } int nSelect = (int)(Math.random() * bestCount) + 1; // some element of randomness for(int i = 0; i < nLevel; i++) { for(int j = 0; j < nLevel; j++) { if(rGrid[i][j] == bestValue) { nSelect--; if(nSelect < 1) { // this is our move bGrid[i][j] = type; lastX = i; lastY = j; return true; } } } } return true; } void calculateValue(int type, int x, int y) { // Phew! we managed to write this int val = 0; for(int i = 0; i < nLevel; i++) { for(int j = 0; j < nLevel; j++) { if(bGrid[i][j] == type) val++; if(bGrid[i][j] > 0) val--; } } if(((x == 0) && (y == 0)) || ((x == 0) && (y == (nLevel - 1))) || ((x == (nLevel - 1)) && (y == 0)) || ((x == (nLevel - 1)) && (y == (nLevel - 1)))) val += 500; // We like corner spot if(((x == 0) && ((y == 1) || (y == (nLevel - 2)))) || (((x == 1) || (x == (nLevel - 2))) && (y == (nLevel - 1))) || (((x == 1) || (x == (nLevel - 2))) && (y == 0)) || ((x == (nLevel - 1)) && ((y == 1) || (y == (nLevel - 2))))) val -= 500; // We do not like next to corner if(!easyFlag) { // make life hell for user if(((x == 1) && (y == 1)) || ((x == 1) && (y == (nLevel - 2))) || ((x == (nLevel - 2)) && (y == 1)) || ((x == (nLevel - 2)) && (y == (nLevel - 2)))) val -= 500; } rGrid[x][y] = val; } void restoreBGrid() { for(int i = 0; i < nLevel; i++) for(int j = 0; j < nLevel; j++) bGrid[i][j] = tGrid[i][j]; } void updateResult() { int totalOnes = 0; int totalTwos = 0; for(int i = 0; i < nLevel; i++) { for(int j = 0; j < nLevel; j++) { if(bGrid[i][j] == 1) totalOnes++; if(bGrid[i][j] == 2) totalTwos++; } } if(userColor == 1) { pResult.updateResult(Color.blue, Color.red, totalOnes, totalTwos); } else { pResult.updateResult(Color.red, Color.blue, totalTwos, totalOnes); } } void startNewGame() { setUpGrid(); bPass.setLabel(""); bPass.disable(); pMain.changeSize(); gameOver = false; updateResult(); pMain.repaint(); if(userFirst) { nextActionType = 1; } else { nextActionType = 4; } } void setUpGrid() { userFirst = !userFirst; if(userFirst) { userColor = 1; lUserColor.setText("Your color is BLUE"); } else { userColor = 2; lUserColor.setText("Your color is Red"); } for(int i = 0; i < nLevel; i++) { for(int j = 0; j < nLevel; j++) { bGrid[i][j] = -1; sGrid[i][j] = false; // Not flipped recently } } int iMid = (nLevel + 1) / 2; bGrid[iMid - 1][iMid - 1] = userColor; // set intial filled tiles bGrid[iMid ][iMid - 1] = 3 - userColor; bGrid[iMid - 1][iMid ] = 3 - userColor; bGrid[iMid ][iMid ] = userColor; } void processHelp() { HridayeshHelp window = null; try { window = new HridayeshHelp(); } catch (Exception e) { bHelp.setLabel("Error"); bHelp.disable(); return; } window.setTitle("ReversiHelp"); window.setText( "REVERSI the game practiced by morons to kill time" + "\nAre you one of them and want to learn the rules" + "\nHere they are:" + "\n You are either red or blue depending on the computers mood" + "\n You can place a colored circle so that there is atleast one" + "\n tile of opponent between your current tile and some ancient" + "\n tile belonging to you. If you successfully do that all intervening" + "\n tiles are converted to your colour so you get richer" + "\n In the end winner is the one with more number of tiles" + "\n BEFORE you start playing let us warn you that a situation " + "\n may arise where there is no legal move for you. And You will " + "\n have to press the pass button as we do not give you any other choice. " + "\n Good luck and join the ranks of great MORONS who practiced this game" + "\n And if you think you are SMART try 'Make Life Difficult' button" + "\n" + "\n And YES we do have a MORON button to tell you the legal moves " ); window.pack(); window.show(); } } class ReversiSelect extends Canvas { private Reversi parent; private boolean firstTime = true; // to force the recalculation of sizes private int w; // grid width private boolean flagCurr = false; private int xOff, yOff; // The display area may not be a perfect square ReversiSelect(Reversi parent) { super(); this.parent = parent; } public void changeSize() { // Recalculate the sizes if user changes the grid n * n firstTime = true; } public void updateGrid() { flagCurr = true; repaint(); } private Image offImage; private Graphics o; public void update(Graphics g) { if(!flagCurr) firstTime = true; Dimension d = size(); if(firstTime) { offImage = createImage(d.width, d.height); o = offImage.getGraphics(); w = d.width / parent.nLevel; if(w > (d.height / parent.nLevel)) w = d.height / parent.nLevel; xOff = (d.width - w * parent.nLevel) / 2; yOff = (d.height - w * parent.nLevel) / 2; for(int i = 0; i < parent.nLevel; i++) { for(int j = 0; j < parent.nLevel; j++) { gridDraw(o, i, j); } } firstTime = false; } if(flagCurr) { for(int i = 0; i < parent.nLevel; i++) { for(int j = 0; j < parent.nLevel; j++) gridDraw(o, i, j); } flagCurr = false; } g.drawImage(offImage, 0, 0, this); } public boolean mouseDown(Event event, int x, int y) { int i = (x - xOff)/ w; int j = (y - yOff)/ w; if((i < parent.nLevel) && (j < parent.nLevel)) { parent.userMove(i, j); return true; } return false; } private void gridDraw(Graphics o, int i, int j) { o.setColor(Color.white); o.fillRect(xOff + i * w, yOff + j * w, w, w); o.setColor(Color.black); o.drawRect(xOff + i * w, yOff + j * w, w, w); switch(parent.bGrid[i][j]) { case -1: return; case 0: o.setColor(Color.green); o.fillOval(xOff + i * w + w / 4, yOff + j * w + w / 4, w / 2, w / 2); return; case 1: if (parent.sGrid[i][j]) { o.setColor(Color.red); } else { o.setColor(Color.blue); } break; case 2: if (parent.sGrid[i][j]) { o.setColor(Color.blue); } else { o.setColor(Color.red); } break; case 3: o.setColor(Color.black); break; default: } o.fillOval(xOff + i * w + 2, yOff + j * w + 2, w - 4, w - 4); } public void paint(Graphics g) { update(g); } }