//*********************** Copy right information ************************* // FAQ's // Q. Is this program copy right protected? // Ans. No. Even if it was you will copy it anyway so what is the point // Q. Can I use it for commercial purposes? // Ans. Yes and let us know for what purpose. // Q. How do You feel about my copying this software? // Ans. We think that you are doing us a great honour by copying this // software. We are not worthy of this honour but we will appreciate // your generousity if you will simply e-mail us a thank you note // Q. What do I do if I find a bug? // Ans. Call 911 // Q. Where is the code documentation? // Ans. At Fort Knox. // 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: Quarto game program // Programmer: H K Gupta Date: 30 July 1997 //************************************************************************ import java.awt.*; import java.applet.Applet; import java.lang.Math; public class Quarto extends Applet { Panel pStatus; Label lQuarto; // name label Button bStart; Panel pHelpEtc; Button bHelp; Label lChoice; QuartoButton qChoice; // show the selected object Label lCommand; Panel pMain; // Main Panel QuartoButton[][] qMain; // 4 * 4 grid Panel pPick; // Panel for picking items QuartoButton[][] qPick; // grid for picking items boolean userFirst = false; boolean bGameOver = true; boolean flagPick = true; // temp variables for calculating moves int[][] iTemp; int[][] iDamage; public void init() { iTemp = new int[4][4]; iDamage = new int[4][4]; setLayout(new GridLayout(0, 3, 5, 5)); pStatus = new Panel(); pStatus.setLayout(new GridLayout(0, 1, 1, 3)); add(pStatus); lQuarto = new Label("QUARTO", Label.CENTER); lQuarto.setFont(new Font("TimesRoman",Font.BOLD,30)); lQuarto.setForeground(Color.red); pStatus.add(lQuarto); bStart = new Button("Start"); pStatus.add(bStart); pHelpEtc = new Panel(); pHelpEtc.setLayout(new GridLayout(0, 3, 5, 5)); pStatus.add(pHelpEtc); bHelp = new Button("Help"); pHelpEtc.add(bHelp); lChoice = new Label("Choice", Label.CENTER); pHelpEtc.add(lChoice); qChoice = new QuartoButton(-1); qChoice.disable(); pHelpEtc.add(qChoice); lCommand = new Label("", Label.CENTER); pStatus.add(lCommand); pMain = new Panel(); pMain.setLayout(new GridLayout(0, 4, 1, 1)); add(pMain); int i, j; qMain = new QuartoButton[4][4]; for(i = 0; i < 4; i++) { for(j = 0; j < 4; j++) { qMain[i][j] = new QuartoButton(-1); pMain.add(qMain[i][j]); } } pPick = new Panel(); pPick.setLayout(new GridLayout(0, 4, 1, 1)); add(pPick); qPick = new QuartoButton[4][4]; for(i = 0; i < 4; i++) { for(j = 0; j < 4; j++) { qPick[i][j] = new QuartoButton(i * 4 + j); pPick.add(qPick[i][j]); } } validate(); startNewGame(); } public boolean action(Event e, Object arg) { Object target = e.target; int i, j; for(i = 0; i < 4; i++) { for(j = 0; j < 4; j++) { if(!bGameOver) { if (flagPick) { if(target == qPick[i][j]) if(-1 != qPick[i][j].type) return processPick(i, j); } else { if(target == qMain[i][j]) if(-1 == qMain[i][j].type) return processPlace(i, j); } } } } if(target == bStart) { startNewGame(); return true; } if(target == bHelp) { processHelp(); return true; } return false; } boolean processPick(int i, int j) { // select an item from Pick grid place(qPick[i][j].type); // Place user choice on main qPick[i][j].setValue(-1); if(checkWinOrOver(true)) return true; // Computer has won makeChoice(); // Computer makes choice setPick(false); return true; } void setPick(boolean bFlag) { flagPick = bFlag; if(flagPick) { lCommand.setText("Select from right grid"); } else { lCommand.setText("Place on main grid"); } } void place(int userChoice) { int i, j, ret; ret = findBestMove(userChoice); i = ret / 4; j = ret - (i * 4); qMain[i][j].setValue(userChoice); qChoice.setValue(-1); } int findBestMove(int userChoice) { int i, j; int least = 5; // shortest line for(i = 0; i < 4; i++) { for(j = 0; j < 4; j++) { if(-1 == qMain[i][j].type) { iTemp[i][j] = longestProperty(i, j, userChoice); if(iTemp[i][j] == 4) return i * 4 + j; // We have won. Fireworks begin if(least > iTemp[i][j]) least = iTemp[i][j]; } else { iTemp[i][j] = 5; // disqualify this place } } } int leastCount = 0; // Work hard to give a random move for(i = 0; i < 4; i++) { for(j = 0; j < 4; j++) { if(iTemp[i][j] == least) leastCount++; } } int moveNo = (int)(Math.random() * leastCount) + 1; leastCount = 0; for(i = 0; i < 4; i++) { for(j = 0; j < 4; j++) { if(iTemp[i][j] == least) { leastCount++; if(leastCount == moveNo) return i * 4 + j; // We have won. Fireworks begin } } } // God if you exist, please save our soul if we ever reach here return 0; // dummy to satisfy this compiler } int longestProperty(int iGot, int jGot, int userChoice) { int longest = 0; int p; int mask; int tempSize; for(p = 0; p < 4; p++) { // property type mask = 1 << p; tempSize = 0; for(int j = 0; j < 4; j++) { if(j == jGot) { // use the userChoice tempSize+= plusMinusOne(mask, userChoice); } else { if(-1 != qMain[iGot][j].type) tempSize += plusMinusOne(mask, qMain[iGot][j].type); } } if (tempSize < 0) tempSize = - tempSize; if (tempSize > longest) longest = tempSize; // try the other direction tempSize = 0; for(int i = 0; i < 4; i++) { if(i == iGot) { // use the userChoice tempSize+= plusMinusOne(mask, userChoice); } else { if(-1 != qMain[i][jGot].type) tempSize += plusMinusOne(mask, qMain[i][jGot].type); } } if (tempSize < 0) tempSize = - tempSize; if (tempSize > longest) longest = tempSize; } return longest; } int plusMinusOne(int mask, int userChoice) { if((mask & userChoice) == 0) return -1; return 1; } void makeChoice() { int i, j; int temp; int least = 5; for(i = 0; i < 4; i++) { for(j = 0; j < 4; j++) { if(qPick[i][j].type == -1) { iDamage[i][j] = 5; // disqualify } else { iDamage[i][j] = damage(qPick[i][j].type); } if(least > iDamage[i][j]) least = iDamage[i][j]; } } int leastCount = 0; // Work hard to give a random move for(i = 0; i < 4; i++) { for(j = 0; j < 4; j++) { if(iDamage[i][j] == least) leastCount++; } } int moveNo = (int)(Math.random() * leastCount) + 1; leastCount = 0; for(i = 0; i < 4; i++) { for(j = 0; j < 4; j++) { if(iDamage[i][j] == least) { leastCount++; if(leastCount == moveNo) { qChoice.setValue(qPick[i][j].type); qPick[i][j].setValue(-1); return; } } } } // God if you exist, please save our soul if we ever reach here } int damage(int userChoice) { int i, j; int iMax = 0; // shortest line for(i = 0; i < 4; i++) { for(j = 0; j < 4; j++) { if(-1 == qMain[i][j].type) { iTemp[i][j] = longestProperty(i, j, userChoice); if(iMax < iTemp[i][j]) iMax = iTemp[i][j]; } } } return iMax; } boolean processPlace(int i, int j) { // place choice on main grid qMain[i][j].setValue(qChoice.type); qChoice.setValue(-1); if(checkWinOrOver(false)) return true; // user has won. What pity. We have lost touch. setPick(true); return true; } void startNewGame() { userFirst = !userFirst; qChoice.setValue(-1); int i, j; for(i = 0; i < 4; i++) { for(j = 0; j < 4; j++) { qPick[i][j].setValue(i * 4 + j); qMain[i][j].setValue(-1); } } bGameOver = false; if(!userFirst) makeChoice(); setPick(userFirst); } boolean checkWinOrOver(boolean flagComp) { int i, j; boolean gameOver = true; for(i = 0; i < 4; i++) { for(j = 0; j < 4; j++) { if(qMain[i][j].type == -1) gameOver = false; } } if(gameOver) { lCommand.setText("It is a DRAW"); bGameOver = true; return true; } // check for win int p, mask, val; for(p = 0; p < 4; p++) { mask = 1 << p; for(i = 0; i < 4; i++) { val = 0; for(j = 0; j < 4; j++) { if(-1 != qMain[i][j].type) val += plusMinusOne(mask, qMain[i][j].type); } if((val == 4) || (val == -4)) return processWin(flagComp); } for(j = 0; j < 4; j++) { val = 0; for(i = 0; i < 4; i++) { if(-1 != qMain[i][j].type) val += plusMinusOne(mask, qMain[i][j].type); } if((val == 4) || (val == -4)) return processWin(flagComp); } } return false; } boolean processWin(boolean flagComp) { // fireworks or tears time bGameOver = true; if(flagComp) { lCommand.setText("I WON. YIPEEE"); } else { lCommand.setText("You WON. Congratulations"); } return true; } void processHelp() { QuartoHelp window = null; try { window = new QuartoHelp(); } catch (Exception e) { bHelp.setLabel("Error"); bHelp.disable(); return; } window.setTitle("QuartoHelp"); window.setText("This game is a waste of time"); window.setText("BUT if you still insist"); window.setText("Here are the rules:"); window.setText(" There are four types of object properties"); window.setText(" 1. Size (small or big)"); window.setText(" 2. Color (Blue or Red)"); window.setText(" 3. Shape (Circle or Square)"); window.setText(" 4. Solidity (Filled or Hollow)"); window.setText("You are required to get four objects of "); window.setText("same property in a row or column. Thats all"); window.setText("** If you THINK u can do it. Go ahead **"); window.pack(); window.show(); } } class QuartoButton extends Button { int type; // picture type QuartoButton(int type) { super(); this.type = type; } public void setValue(int type) { this.type = type; repaint(); } public void update(Graphics g) { Color bg = getBackground(); Color fg = getForeground(); Dimension d = size(); g.setColor(bg); g.fillRect(2,2, d.width - 4, d.height - 4); if( type == -1) return; int x = d.width; if(x > d.height) x = d.height; x -= 6; // Buttons are funny they don't let you draw all over if((type & 4) == 0) x = x / 2; int xOff = (d.width - x) / 2; int yOff = (d.height - x) / 2; g.setColor(Color.blue); if((type & 8) == 0) g.setColor(Color.red); if((type & 2) == 0) { g.fillRect(xOff, yOff, x, x); } else { g.fillOval(xOff, yOff, x, x); } if((type & 1) == 0) { g.setColor(bg); if((type & 2) == 0) { g.fillRect(xOff + 3, yOff + 3, x - 6, x - 6); } else { g.fillOval(xOff + 3, yOff + 3, x - 6, x - 6); } } g.setColor(fg); } public void paint(Graphics g) { update(g); } public boolean handleEvent(Event e) { repaint(); return super.handleEvent(e); } } class QuartoHelp extends Frame { private TextArea textArea; public QuartoHelp() { textArea = new TextArea(5, 40); textArea.setEditable(false); add("Center", textArea); } public boolean handleEvent(Event event) { if (event.id == Event.WINDOW_DESTROY) { dispose(); } return super.handleEvent(event); } public void setText(String text) { textArea.appendText(text + "\n"); } }