/* Applet to play animals game */ import java.awt.*; import java.awt.event.*; import structure.*; import java.io.*; import javax.swing.*; public class AnimalApp extends JFrame { // size of frame for game private static final int FRAME_HEIGHT = 260; private static final int FRAME_WIDTH = 600; protected BinaryTree animalTree; // holds the knowledge base *) protected BinaryTree currentTree; protected CardLayout cardManager; // Layout manager allowing different panels to show // Card showing display when start game protected JPanel startJPanel = new JPanel(); // JPanel for entire start screen protected JPanel midStartJPanel = new JPanel(); // subJPanels to make it look nicer protected JPanel bottomStartJPanel = new JPanel(); // JButtons (and JLabel) for actions in start screen protected JLabel directions = new JLabel("What would you like to do next?",JLabel.CENTER); protected JButton playJButton = new JButton("Start playing"); protected JButton loadJButton = new JButton("Load an old game"); protected JButton saveJButton = new JButton("Save the current game"); protected JButton quitJButton = new JButton("Quit the game"); // Card showing display when playing game protected JPanel playJPanel = new JPanel(); // JPanel for entire display when playing protected JLabel message = new JLabel(); // Question user is to respond to protected JButton yesJButton, noJButton; // JButtons for user response protected JPanel middle; // subJPanel for JButtons // Card showing display when entering new animal protected JPanel newAnimalJPanel = new JPanel(); // JPanel for entering new animal protected JLabel animalJLabel = new JLabel("What animal were you thinking of?",JLabel.CENTER); protected JTextField animalField = new JTextField(20); // slot for animal name protected JLabel questionJLabel = new JLabel( "What question distinguishes the new animal from the one I guessed?",JLabel.CENTER); protected JTextField questionField = new JTextField(40); // slot for question on animal protected JLabel answerJLabel = new JLabel("What is the correct answer for the new animal?", JLabel.CENTER); protected JButton yesAnsJButton = new JButton("Yes"); // JButtons to indicate correct answer protected JButton noAnsJButton = new JButton("No"); // to question entered // protected String animal, question; protected JPanel animalJPanel = new JPanel(); // subJPanel for animal name (and JLabel) protected JPanel questionJPanel = new JPanel(); // subJPanel for entering question protected JPanel JButtonJPanel = new JPanel(); // subJPanel for yes and no JButtons. // card allowing selection of file protected JPanel fileJPanel = new JPanel(); // JPanel for selecting a file protected JLabel fileNameJLabel = new JLabel("Enter the file name:"); protected JTextField fileNameField = new JTextField(20); // field to enter file name protected JButton selectJButton = new JButton("Do it!"); // JButtons to select file or cancel protected JButton cancelJButton = new JButton("Forget it!"); protected JPanel topFileJPanel = new JPanel(); // subJPanel for file name (and JLabel) protected JPanel bottomFileJPanel = new JPanel(); // subJPanel for JButtons protected boolean lastWasQuestion; // true when user just answered a question protected boolean save = true; // true if click on "Do it" should save tree in file. protected Container contentPane; /* Set up all JPanels for program and initialize animalTree for playing. */ public AnimalApp(String title) { super(title); contentPane = getContentPane(); cardManager = new CardLayout(); contentPane.setLayout(cardManager); // set card for starting card startJPanel.setLayout(new GridLayout(3,1,2,2)); startJPanel.add(directions); playJButton.setBackground(Color.green); midStartJPanel.add(playJButton); playJButton.addActionListener(new PlayJButtonListener()); quitJButton.setBackground(Color.red); midStartJPanel.add(quitJButton); quitJButton.addActionListener(new QuitJButtonListener()); loadJButton.setBackground(Color.cyan); loadJButton.addActionListener(new LoadJButtonListener()); saveJButton.setBackground(Color.cyan); saveJButton.addActionListener(new SaveJButtonListener()); bottomStartJPanel.add(loadJButton); bottomStartJPanel.add(saveJButton); startJPanel.add(midStartJPanel); startJPanel.add(bottomStartJPanel); contentPane.add("Start",startJPanel); // set card for playing playJPanel.setLayout(new GridLayout(2,1,2,2)); message.setHorizontalAlignment(JLabel.CENTER); playJPanel.add(message); yesJButton = new JButton("Yes"); yesJButton.setBackground(Color.green); yesJButton.addActionListener(new YesJButtonListener()); noJButton = new JButton("No"); noJButton.setBackground(Color.red); noJButton.addActionListener(new NoJButtonListener()); middle = new JPanel(); middle.add(yesJButton); middle.add(noJButton); playJPanel.add(middle); contentPane.add("Play",playJPanel); // set card for entering new animal newAnimalJPanel.setLayout(new GridLayout(5,1)); animalJPanel = new JPanel(); animalJPanel.add(animalJLabel); animalJPanel.add(animalField); animalField.setBackground(Color.white); newAnimalJPanel.add(animalJPanel); newAnimalJPanel.add(questionJLabel); questionField.setBackground(Color.white); questionJPanel.add(questionField); newAnimalJPanel.add(questionJPanel); newAnimalJPanel.add(answerJLabel); JButtonJPanel = new JPanel(); YesNoAnsJButtonListener yesNoAnsListener = new YesNoAnsJButtonListener(); yesAnsJButton.setBackground(Color.green); yesAnsJButton.addActionListener(yesNoAnsListener); JButtonJPanel.add(yesAnsJButton); noAnsJButton.setBackground(Color.red); noAnsJButton.addActionListener(yesNoAnsListener); JButtonJPanel.add(noAnsJButton); newAnimalJPanel.add(JButtonJPanel); contentPane.add("New animal",newAnimalJPanel); // set card for file interaction fileJPanel.setLayout(new BorderLayout()); topFileJPanel.add(fileNameJLabel); topFileJPanel.add(fileNameField); fileJPanel.add("North",topFileJPanel); fileNameField.setBackground(Color.white); selectJButton.setBackground(Color.green); selectJButton.addActionListener(new SelectJButtonListener()); bottomFileJPanel.add(selectJButton); cancelJButton.setBackground(Color.red); cancelJButton.addActionListener(new CancelJButtonListener()); bottomFileJPanel.add(cancelJButton); fileJPanel.add("South",bottomFileJPanel); contentPane.add("File",fileJPanel); // set up initial tree in case no file to read in AnimalTreeInfo left = new AnimalTreeInfo(true,"horse"); BinaryTree leftTree = new BinaryTree(left); AnimalTreeInfo right = new AnimalTreeInfo(true,"ant"); BinaryTree rightTree = new BinaryTree(right); AnimalTreeInfo root = new AnimalTreeInfo(false,"Is it bigger than a breadbox?"); animalTree = new BinaryTree(root,leftTree, rightTree); currentTree = animalTree; cardManager.first(contentPane); // Set frame so at starting JPanel } /* On JPanel for playing game. post: Ask next question if that is next, otherwise make a guess. */ public void askNext() { AnimalTreeInfo info = (AnimalTreeInfo) currentTree.value(); if (info.isAnimal()) // Ready to guess an animal { message.setText("Were you thinking of a(n) "+info.getContents()+"?"); lastWasQuestion = false; } else // Ask another question { message.setText(info.getContents()); lastWasQuestion = true; } } /* On JPanel for choosing file. pre: inFile refers to animal file, newAnimalTree holds partial animal tree. post: Recursively read game tree from file. When done, leave cursor where it was before the call. */ public BinaryTree readAnimalsFromFile(DataInputStream inFile) throws IOException { AnimalTreeInfo info; char tag = inFile.readChar(); String contents = inFile.readUTF(); if (tag == 'A') { info = new AnimalTreeInfo(true,contents); return new BinaryTree(info); } else { info = new AnimalTreeInfo(false,contents); BinaryTree leftTree = readAnimalsFromFile(inFile); BinaryTree rightTree = readAnimalsFromFile(inFile); return new BinaryTree(info,leftTree,rightTree); } } /* On JPanel for choosing file. pre: outFile refers to animal file. post: Recursively write subtree corresponding to cursor of animalTree to outFile. When done, leave cursor where it was before the call. */ public void writeAnimalsToFile(BinaryTree animalSubtree, DataOutputStream outFile) throws IOException { // Information about current node of tree AnimalTreeInfo info = (AnimalTreeInfo) animalSubtree.value(); if (info.isAnimal()) // Node corresponding to animal. Write it to outFile. { outFile.writeChar('A'); outFile.writeUTF(info.getContents()); } else // Node corresponding to question. Write subtree to outFile. { outFile.writeChar('Q'); outFile.writeUTF(info.getContents()); writeAnimalsToFile(animalSubtree.left(),outFile); writeAnimalsToFile(animalSubtree.right(),outFile); } } /* On JPanel for entering new animal and question for it. pre: animalField and questionField have been set to new animal and question. post: Add node to tree corresponding to new animal, with question as parent, and animal guessed as other child of parent. Put question in tree where the old animal used to be. New animal placed on left of question if yesAnswer is true and right side otherwise. */ public void addAnimal(boolean yesAnswer) { // Get new animal and question from text fields, and old animal from tree. Object newAnimalInfo = new AnimalTreeInfo(true,animalField.getText()); Object newQuestionInfo = new AnimalTreeInfo(false,questionField.getText()); Object oldAnimalInfo = currentTree.value(); BinaryTree leftTree; BinaryTree rightTree; if (yesAnswer) // Insert new animal to left and old to right { leftTree = new BinaryTree(newAnimalInfo); rightTree = new BinaryTree(oldAnimalInfo); } else // Insert new animal to right and old to left { leftTree = new BinaryTree(oldAnimalInfo); rightTree = new BinaryTree(newAnimalInfo); } currentTree.setValue(newQuestionInfo); currentTree.setLeft(leftTree); currentTree.setRight(rightTree); animalField.setText(""); questionField.setText(""); directions.setText("You won't fool me as easily next time! What next?"); cardManager.first(contentPane); // Go back to first card } /* post: If program is being run as an application, creates a frame for it to run in. Ignored if run as applet. */ public static void main(String[] args) { // Set up and show frame AnimalApp app = new AnimalApp("Animals Game"); app.setSize(FRAME_WIDTH,FRAME_HEIGHT); app.show(); } // class which handles play Button. protected class PlayJButtonListener implements ActionListener{ /** post: Handle clicks on play JButton by resetting tree and asking for next guess. **/ public void actionPerformed(ActionEvent evt) { cardManager.show(contentPane,"Play"); currentTree = animalTree; askNext(); } } // class which handles quit JButton. protected class QuitJButtonListener implements ActionListener{ /** post: Handle clicks on quit JButton by exiting **/ public void actionPerformed(ActionEvent evt) { AnimalApp.this.dispose(); } } // class which handles load JButton. protected class LoadJButtonListener implements ActionListener{ /** post: Handle clicks on load JButton by displaying card for selecting name. **/ public void actionPerformed(ActionEvent evt) { cardManager.last(contentPane); save = false; } } // class which handles save JButton. protected class SaveJButtonListener implements ActionListener{ /** post: Handle clicks on save JButton by showing the file card **/ public void actionPerformed(ActionEvent evt) { cardManager.show(contentPane,"File"); save = true; } } // class which handles select JButton. protected class SelectJButtonListener implements ActionListener{ /* On JPanel for choosing file. post: If saving, then open file name selected and store game. If loading game, read game tree from file. If file operation screws up, don't change old tree, just print a message. When done go to start JPanel. */ public void actionPerformed(ActionEvent evt) { String fileName = fileNameField.getText(); if (fileName != "") // User entered a file name { try { if (save) // Save the tree to a file. { DataOutputStream outFile = new DataOutputStream(new FileOutputStream(fileName)); writeAnimalsToFile(animalTree,outFile); outFile.close(); } else // Read in a new tree. { // open file to read in the tree DataInputStream inFile = new DataInputStream(new FileInputStream(fileName)); // Don't destroy old tree immediately in case there is a file problem! BinaryTree newAnimalTree = readAnimalsFromFile(inFile); // read in new tree inFile.close(); // close file animalTree = newAnimalTree; // replace old tree } directions.setText("What would you like to do next?"); cardManager.first(contentPane); // go back to start JPanel } catch(IOException e) // error with file operation { System.out.println("File error!\n"+ e.toString()); } } else // file name is blank System.out.println("Insert file name before saving!"); } } // class which handles cancel JButton. protected class CancelJButtonListener implements ActionListener{ /** post: Handle clicks on cancel JButton. **/ public void actionPerformed(ActionEvent evt) { directions.setText("What would you like to do next?"); cardManager.first(contentPane); } } // class which handles yes JButton on JPanel for playing game. protected class YesJButtonListener implements ActionListener{ /* On JPanel for playing game. post: If responding to question, ask next appropriate question. If responding to computer's guess, then gloat about winning and go to start JPanel. */ public void actionPerformed(ActionEvent evt) { if(lastWasQuestion) // Responding to computer's question { currentTree = currentTree.left(); askNext(); // Ask the next question } else // Computer guessed correctly { directions.setText("Ha, I knew I could guess it! What next?"); cardManager.first(contentPane); } } } // class which handles no JButton on JPanel for playing game. protected class NoJButtonListener implements ActionListener{ /* On JPanel for playing game. post: If responding to question, ask next appropriate question. If responding to computer's guess, then go to JPanel to get correct answer. */ public void actionPerformed(ActionEvent evt) { if(lastWasQuestion) // Responding to computer's question { currentTree = currentTree.right(); askNext(); // Ask the next question } else // Computer guessed incorrectly cardManager.show(contentPane,"New animal"); // shift to JPanel to get correct answer } } // Actions on JPanel for entering new animal and question protected class YesNoAnsJButtonListener implements ActionListener{ /* On panel for playing game. post: add new animal w/appropriate answer in tree. */ public void actionPerformed(ActionEvent evt) { addAnimal(evt.getSource() == yesAnsJButton); } } }