/* * PlayingWindow.java * * Title: Fril - Java noughts and crosses demo * Author: entpm May/June 2001 * Description: Tutorial demonstration of Fril embedded in a java application * The GUI code was mostly generated by CodeWarrior. * An array of JButtonSquares is used to represent the board. * Input and output text areas are provided for Fril, and an output text area for Java * to facilitate debugging. * * @author T. P. Martin * @date June 2001 * @version 1.0b1 */ import java.awt.*; import java.io.*; import java.awt.event.*; import javax.swing.*; public class PlayingWindow extends JFrame { public static final int NSQUARES=9; private JButtonSquare [] theGrid = new JButtonSquare[NSQUARES]; private FrilJavaDemo topLevel; private JFril theFril; private FrilWriter theFrilWriter; private boolean computerGoesFirst; private static final String THISCLASS = "PlayingWindow::"; private static final boolean DEBUGGING=true; private static final String FRILINDEFAULT = "/* Type Fril input here */\n"; // BEGIN GENERATED CODE // member declarations javax.swing.JScrollPane JScrollPane = new javax.swing.JScrollPane(); javax.swing.JTextArea JFrilTextArea = new javax.swing.JTextArea(); javax.swing.JButton JStartButton = new javax.swing.JButton(); javax.swing.JPanel jPanel1 = new javax.swing.JPanel(); javax.swing.JScrollPane jScrollPane1 = new javax.swing.JScrollPane(); javax.swing.JTextArea JJavaTextArea = new javax.swing.JTextArea(); javax.swing.JLabel JLabel = new javax.swing.JLabel(); javax.swing.JLabel jHumanScore = new javax.swing.JLabel(); javax.swing.JLabel jComputerScore = new javax.swing.JLabel(); javax.swing.JLabel jLabel3 = new javax.swing.JLabel(); javax.swing.JLabel jLabel4 = new javax.swing.JLabel(); javax.swing.JLabel jDrawScore = new javax.swing.JLabel(); javax.swing.JScrollPane jScrollPane2 = new javax.swing.JScrollPane(); javax.swing.JTextArea jFrilTextInput = new javax.swing.JTextArea(); javax.swing.JRadioButton jRadioButtonC = new javax.swing.JRadioButton(); javax.swing.JRadioButton jRadioButtonH = new javax.swing.JRadioButton(); javax.swing.JButton jButtonSendToFril = new javax.swing.JButton(); // END GENERATED CODE public PlayingWindow(FrilJavaDemo theTopLevel, JFril aFril) { int index; int [] xcoords = {20, 80, 140}; int [] ycoords = {10,70,130}; for (int xi = 0; xi < 3; xi++) for (int yi = 0; yi < 3; yi++) { index = 3*yi+xi; theGrid[index] = new JButtonSquare(index, xcoords[xi], ycoords[yi], this); } topLevel = theTopLevel; theFril = aFril; theFrilWriter = new FrilWriter(JFrilTextArea); theFril.jFrilSetOutWriter(theFrilWriter); } public void initComponents() throws Exception { // BEGIN GENERATED CODE // the following code sets the frame's initial state JScrollPane.setLocation(new java.awt.Point(30, 330)); JScrollPane.setVisible(true); JScrollPane.setSize(new java.awt.Dimension(300, 90)); JScrollPane.getViewport().add(JFrilTextArea); JFrilTextArea.setText("Fril Messages"); JFrilTextArea.setVisible(true); JFrilTextArea.setToolTipText("output from Fril appears here"); JStartButton.setText("Start"); JStartButton.setLocation(new java.awt.Point(220, 60)); JStartButton.setVisible(true); JStartButton.setBackground(new java.awt.Color(255, 255, 255)); JStartButton.setToolTipText("click here to start or restart"); JStartButton.setSize(new java.awt.Dimension(90, 30)); jPanel1.setLocation(new java.awt.Point(20, 10)); jPanel1.setVisible(true); jPanel1.setBackground(new java.awt.Color(0, 0, 255)); jPanel1.setSize(new java.awt.Dimension(170, 170)); jScrollPane1.setLocation(new java.awt.Point(30, 440)); jScrollPane1.setVisible(true); jScrollPane1.setSize(new java.awt.Dimension(300, 80)); jScrollPane1.getViewport().add(JJavaTextArea); JJavaTextArea.setText("Java Messages"); JJavaTextArea.setVisible(true); JJavaTextArea.setToolTipText("output from Java appears here"); JLabel.setText("Human Wins : "); JLabel.setLocation(new java.awt.Point(20, 200)); JLabel.setVisible(true); JLabel.setSize(new java.awt.Dimension(90, 20)); jHumanScore.setText("0"); jHumanScore.setLocation(new java.awt.Point(110, 200)); jHumanScore.setVisible(true); jHumanScore.setSize(new java.awt.Dimension(20, 20)); jComputerScore.setText("0"); jComputerScore.setLocation(new java.awt.Point(240, 200)); jComputerScore.setVisible(true); jComputerScore.setSize(new java.awt.Dimension(20, 20)); jLabel3.setText("Computer Wins : "); jLabel3.setLocation(new java.awt.Point(140, 200)); jLabel3.setVisible(true); jLabel3.setSize(new java.awt.Dimension(110, 20)); jLabel4.setText("Draw : "); jLabel4.setLocation(new java.awt.Point(260, 200)); jLabel4.setVisible(true); jLabel4.setSize(new java.awt.Dimension(50, 20)); jDrawScore.setText("0"); jDrawScore.setLocation(new java.awt.Point(300, 200)); jDrawScore.setVisible(true); jDrawScore.setSize(new java.awt.Dimension(20, 20)); jScrollPane2.setLocation(new java.awt.Point(30, 240)); jScrollPane2.setVisible(true); jScrollPane2.setSize(new java.awt.Dimension(300, 50)); jScrollPane2.getViewport().add(jFrilTextInput); jFrilTextInput.setText(FRILINDEFAULT); jFrilTextInput.setVisible(true); jRadioButtonC.setText("Computer goes first"); jRadioButtonC.setLocation(new java.awt.Point(210, 10)); jRadioButtonC.setVisible(true); jRadioButtonC.setBackground(java.awt.Color.white); jRadioButtonC.setToolTipText("click here to make the computer take first move"); jRadioButtonC.setSize(new java.awt.Dimension(150, 20)); jRadioButtonH.setText("Human goes first"); jRadioButtonH.setLocation(new java.awt.Point(210, 30)); jRadioButtonH.setVisible(true); jRadioButtonH.setBackground(java.awt.Color.white); jRadioButtonH.setToolTipText("click here if you want to take first move"); jRadioButtonH.setSize(new java.awt.Dimension(150, 20)); jRadioButtonH.setSelected(true); // computerGoesFirst = false; ButtonGroup group = new ButtonGroup(); group.add(jRadioButtonC); group.add(jRadioButtonH); jButtonSendToFril.setText("Send query"); jButtonSendToFril.setLocation(new java.awt.Point(120, 295)); //220, 150)); jButtonSendToFril.setVisible(true); jButtonSendToFril.setRolloverEnabled(false); jButtonSendToFril.setBackground(java.awt.Color.white); jButtonSendToFril.setToolTipText("click here to send the input window to Fril"); jButtonSendToFril.setSize(new java.awt.Dimension(130, 30)); setForeground(new java.awt.Color(255, 255, 255)); setLocation(new java.awt.Point(0, 0)); setTitle("Java - Fril Demo"); setResizable(false); setBackground(new java.awt.Color(255, 255, 255)); getContentPane().setLayout(null); setSize(new java.awt.Dimension(368, 550)); getContentPane().add(JScrollPane); getContentPane().add(JStartButton); getContentPane().add(jRadioButtonC); getContentPane().add(jRadioButtonH); getContentPane().add(jButtonSendToFril); for(int index=0; index < 9; index++) getContentPane().add(theGrid[index]); getContentPane().add(jPanel1); getContentPane().add(jScrollPane1); getContentPane().add(jScrollPane2); getContentPane().add(JLabel); getContentPane().add(jHumanScore); getContentPane().add(jComputerScore); getContentPane().add(jLabel3); getContentPane().add(jLabel4); getContentPane().add(jDrawScore); JStartButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent e) { JStartButtonActionPerformed(e); } }); jButtonSendToFril.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent e) { jButtonSendToFrilActionPerformed(e); } }); addWindowListener(new java.awt.event.WindowAdapter() { public void windowClosing(java.awt.event.WindowEvent e) { thisWindowClosing(e); } }); // END GENERATED CODE } private boolean mShown = false; public void addNotify() { super.addNotify(); if (mShown) return; // resize frame to account for menubar JMenuBar jMenuBar = getJMenuBar(); if (jMenuBar != null) { int jMenuBarHeight = jMenuBar.getPreferredSize().height; Dimension dimension = getSize(); dimension.height += jMenuBarHeight; setSize(dimension); } mShown = true; } // Close the window when the close box is clicked void thisWindowClosing(java.awt.event.WindowEvent e) { setVisible(false); dispose(); System.exit(0); } public void JStartButtonActionPerformed(java.awt.event.ActionEvent e) { int index; for (index=0; index < NSQUARES; index++) theGrid[index].resetState(); if(jRadioButtonC.isSelected()) { index = chooseComputerSquare(); computerMove(index); } } public void jButtonSendToFrilActionPerformed(java.awt.event.ActionEvent e) { theFril.jFrilExecuteFril(jFrilTextInput.getText()); jFrilTextInput.setText(FRILINDEFAULT); } public int[] getStateList() { int ret[] = new int[NSQUARES]; for(int index = 0; index < NSQUARES; index++) { ret[index] = theGrid[index].getState(); } return ret; } // pass the query (X (final ((..) (..) (..)) X)) to fril // where the list ((..) ..) represents the state of the board. // This query succeeds if no more moves are possible, in which // case X is instantiated to computer/human/draw appropriately. public boolean checkGameEnded() { int index; boolean gameEnded = false; StringBuffer frilQuery = new StringBuffer("(X (final "+ stateToFrilList() + " X))"); if (DEBUGGING) addJavaText(THISCLASS + "checkGameEnded::Fril query" + frilQuery); // TESTING ONLY if (theFril.jFrilFindSolution(frilQuery.toString()) == JFril.JFRILATOM) { gameEnded = true; String winner = theFril.jFrilGetAtom(JFril.JFRILFSLIST, JFril.JFRILFSITEM); if (winner.equals("computer")) { incrementScore(FrilJavaDemo.COMPUTER); disableAllSquares(); } else if (winner.equals("human")) { incrementScore(FrilJavaDemo.HUMAN); disableAllSquares(); } else if (winner.equals("draw")) incrementScore(FrilJavaDemo.DRAW); else JJavaTextArea.append(THISCLASS + " unrecognised value from " + frilQuery + " X = " + winner); } if (DEBUGGING) addJavaText(THISCLASS + "checkGameEnded::ret " + gameEnded) ; // TESTING ONLY return gameEnded; } private void disableAllSquares() { int index; for (index=0; index < NSQUARES; index++) theGrid[index].setEnabled(false); } // pass the query (X (move ((..) (..) (..)) X)) to fril // This query should always succeed, in which // case X is instantiated to a number 0-8 representing the // square to be occupied by the computer. public int chooseComputerSquare() { int index; int move = FrilJavaDemo.BLANK; int[] state = getStateList(); StringBuffer frilQuery = new StringBuffer("(X (move "); for (index=0; index < NSQUARES; index++) // defensive measure - default move is the last unoccupied square { if (state[index] == index) { move =index; } } frilQuery.append(stateToFrilList() + " X))"); addJavaText (THISCLASS + "Fril query" + frilQuery) ; // TESTING ONLY index = theFril.jFrilFindSolution(frilQuery.toString()); if (index == JFril.JFRILINT) { Integer anInt = theFril.jFrilGetInt(JFril.JFRILFSLIST, JFril.JFRILFSITEM); addJavaText (THISCLASS + " got int from move " + anInt.intValue()) ; // TESTING ONLY if (anInt.intValue() != -1) // TESTING ONLY move = anInt.intValue(); } else addJavaText(THISCLASS + "ERROR: got non-int from move " + index) ; // shouldn't happen unless Fril is not loaded correctly return move; } /* converts the Java representation of the board state to the fril representation * Java uses an array of ints where the value 0-8 indicates the square is * unoccupied (value = index of the square) or FrilJavaDemo.HUMAN, FrilJavaDemo.COMPUTER * for occupied squares. * Fril wants a list of three row lists, with numbers 0-8 for unoccupied and o or x * for computer or human respectively. * There is no fundamental reason why the representation couldn't be the same in both * systems - the Fril code was written first and it was easier to leave it alone and deal * with the transformation here. */ private String stateToFrilList() { int[] state = getStateList(); int index; StringBuffer frilString = new StringBuffer("(("); for (index=0; index < NSQUARES; index++) { if (state[index] == index) { frilString.append(index + " "); } else if (state[index] == FrilJavaDemo.HUMAN) frilString.append("x "); else frilString.append("o "); if(((index+1)%3 == 0) && (index < NSQUARES-1)) frilString.append(") ("); } frilString.append("))"); return frilString.toString(); } public void addJavaText(String toAdd) { JJavaTextArea.append(toAdd + "\n"); } public void incrementScore(int scoreID) { JLabel theLabel = null; switch (scoreID) { case FrilJavaDemo.HUMAN: theLabel = jHumanScore; break; case FrilJavaDemo.COMPUTER: theLabel = jComputerScore; break; case FrilJavaDemo.DRAW: theLabel = jDrawScore; break; } if (theLabel != null) { int score = Integer.parseInt(theLabel.getText()); theLabel.setText(Integer.toString(score+1)); } } public void computerMove(int theSquare) { if(DEBUGGING) addJavaText(" computerMove " + theSquare); theGrid[theSquare].occupySquare(FrilJavaDemo.COMPUTER); } /* * Fril sends its output to a Writer (or subclass). Here we use * a StringWriter which dumps its contents and clears itself when * the flush() method is called. * It keeps a record of the window's text area. */ private class FrilWriter extends StringWriter { private JTextArea myTextArea; FrilWriter(JTextArea frilTextArea) { super(); myTextArea = frilTextArea; } public void flush() { myTextArea.append(this.toString()); super.flush(); this.getBuffer().delete(0, this.getBuffer().length()); // 1.2 and above // this.getBuffer().setLength(0); // java 1.1 } } }