All pastes #418693 Raw Edit

Someone

public text v1 · immutable
#418693 ·published 2007-03-31 19:47 UTC
rendered paste body
/*
 * BoggleGUI.java
 *
 * @author PaulKube and Michael Green
 * see http://www-cse.ucsd.edu/~kube/100/boggle/
 */

package cs310;

import java.awt.*;
import javax.swing.*;
import javax.swing.border.*;
import java.util.*;
import java.awt.event.*;
import java.io.*;

/**  A GUI for the game of Boggle.
 * 
 * BoggleGUI defines and implements methods to do these things:
 * 
 * 1.  Draw the boggle board
 * 2.  Manage the computer and human players' word lists
 * 3.  Update the scoreboard
 *
 * BoggleGUI requires class BogglePlayer, to define these instance methods:
 * <PRE>
 * public void buildLexicon(Set wordList)
 * public void setBoard(String[] letterArray)
 * public SortedSet getAllValidWords(int minimumWordLength)
 * public boolean isInLexicon(String wordToCheck)
 * public java.util.List isOnBoard(String wordToCheck)
 * public String[] getCustomBoard()
 * </PRE>
 *
 * @author Michael Green
 * @author Paul Kube
 *
 * Copyright (C) 2002 Michael Green <mtgreen@cs.ucsd.edu>
 * Copyright (C) 2002 Paul Kube <kube@cs.ucsd.edu>
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.  See
 * http://www.gnu.org/copyleft/gpl.html
 */
public class BoggleGUI extends JFrame {

  public static String WORDLISTFILENAME;
  public static  int DICEROWS = 4;  // default
  public static  int DICECOLS = 4;  // default
  public static  int MINIMUMWORDLENGTH = 4; // default

  private BogglePlayer computerPlayer;
  private BoggleBoard theBoard;
  private ScoreArea humanArea, computerArea;
  private WordEntryField wordEntryField;
        
  public BoggleGUI()  {
    super( "Welcome to B00GLE!");
                
    // create a BogglePlayer computer player to use
    computerPlayer = new BogglePlayer();
    // Read word list from file and initialize computerPlayer's Lexicon
    initLexicon();
    /* Intialize graphics panelsur option) any later version.  See
     * http://www.gnu.org/copyleft/gpl.html
     */
public class BoggleGUI extends JFrame {

  public static String WORDLISTFILENAME;
  public static  int DICEROWS = 4;  // default
  public static  int DICECOLS = 4;  // default
  public static  int MINIMUMWORDLENGTH = 4; // default

  private BogglePlayer computerPlayer;
  private BoggleBoard theBoard;
  private ScoreArea humanArea, computerArea;
  private WordEntryField wordEntryField;
        
  public BoggleGUI()  {
    super( "Welcome to B00GLE!");
                
    // create a BogglePlayer computer player to use
    initPanels();
    // Establish menu bar options and listeners for them
    setUpMenuBar();
    // WindowClosing listener:  for JDK 1.2 compatibility
    addWindowListener(new WindowAdapter() {
      public void windowClosing(WindowEvent e) {
        System.exit(0);
      }});
    // Trust contained components to set their sizes; top level frame packs
    pack();
  }

  /**
   * Get ready for a new game, given a letter list specification of
   * the Boggle board.
   */
  public void newGame(String[] letterList)  {
    // Tell theBoard about the board layout
    theBoard.setBoard(letterList);
    // Tell computerPlayer about the board layout
    computerPlayer.setBoard(letterList);
    // Prepare score areas
    humanArea.setReady();
    computerArea.setReady();
    // Clear board highlighting
    theBoard.unHighlightAllDice();
    // Allow edits to text area and set focus
    wordEntryField.setReady();
    // redraw the whole thing so it looks as nice as can be
    repaint();
  }
        
  /**
   * Consider a word entered by the human player.
   */
  public void checkAndAddWordHuman(String wordToCheck)   {

    // clear any board highlighting
    theBoard.unHighlightAllDice();

    // if empty word, the computer gets to take its turn
    if(wordToCheck.length() == 0)      {
      wordEntryField.setUnready();
      computerPlay();
      return;
    }

    // check that word is:
    // (1) at least minimum length, (2) on the board, (3) in the lexicon,
    // (4) not already entered by the player
    if(wordToCheck.length() <  MINIMUMWORDLENGTH)      {
      chideUser(wordToCheck, "Less Than " + MINIMUMWORDLENGTH + " Letters");
      return;
    }

    java.util.List letterLocations;
    
    // letterLocations = theBoard.getLocationsForWord(wordToCheck);
    // String wordOnBoard = theBoard.getWordFromLocations(letterLocations);
    //    if(!wordToCheck.equalsIgnoreCase(wordOnBoard)) { // double check

    // we just trust the computer player to check this
    letterLocations = computerPlayer.isOnBoard(wordToCheck);
    if(letterLocations == null) { 
      chideUser(wordToCheck, "Not On Board");
      return;
    }

    if(!computerPlayer.isInLexicon(wordToCheck))          {
      chideUser(wordToCheck, "Not In Lexicon");
      return;
    }

    if(humanArea.containsWord(wordToCheck)) {
      chideUser(wordToCheck, "Duplicate Word");
      return;
    }

    // OK, this word passed our rigorous suite of tests.  Add it
    humanArea.addWord(wordToCheck);
    // Highlight locations on board
    theBoard.highlightDice(letterLocations);
    wordEntryField.clear();      //clear the wordEntryField text
  }

  public void chideUser(String attemptedWord, String complaint) {
    JOptionPane.showMessageDialog(this,
                                  attemptedWord + ": " + complaint + "!!!",
                                  complaint,
                                  JOptionPane.ERROR_MESSAGE);
    wordEntryField.clear();      //clear the wordEntryField text
  }

  /**
   * Let the computer player take its turn.
   */
  public void computerPlay() {
    computerArea.setName("Thinking!");
    computerArea.paintImmediately(computerArea.getVisibleRect());
    SortedSet<String> allWords = computerPlayer.getAllValidWords(MINIMUMWORDLENGTH);
    Iterator<String> allWordsIterator = allWords.iterator();
    computerArea.setName("Computer");
    while(allWordsIterator.hasNext())     {
      String newWord = allWordsIterator.next();
      java.util.List wordPath = computerPlayer.isOnBoard(newWord);
      // Add word to appropriate score area & highlight appropriate dice
      computerArea.addWord(newWord);
      theBoard.highlightDice(wordPath);
      // pause for a tenth of a second
      // try {Thread.sleep(100); }   catch (Exception e) {}
    }
    theBoard.unHighlightAllDice(); // leave board unhighlighted when done
  } 


  /**
   * Read word list from file with name WORDLISTFILENAME, and pass a Set
   * containing those words to the computer player to intialize its lexicon.
   */
  private void initLexicon()  { 
    boolean EOF = false;
    ArrayList<String> wordsFromFile = new ArrayList<String> ();
    System.err.print("Reading word list from file " + WORDLISTFILENAME + "...");
    try      {
      // Open File
      BufferedReader input = new BufferedReader( new FileReader(WORDLISTFILENAME));
      String nextWord;
      while((nextWord = input.readLine()) != null)
        wordsFromFile.add(nextWord.toLowerCase());

      //Close the file
      input.close();
    } catch (FileNotFoundException fnfex )      {
      JOptionPane.showMessageDialog(null, 
                                    "Unable to find word list file " + WORDLISTFILENAME, "Error",
                                    JOptionPane.ERROR_MESSAGE);
    }
    catch( IOException e)       {
      JOptionPane.showMessageDialog(null, 
                                    "Error Opening File", "Error",
                                    JOptionPane.ERROR_MESSAGE);
    }
    System.err.println(" Read " + wordsFromFile.size() + " words.");
    System.err.print("Building player's lexicon... ");
    computerPlayer.buildLexicon(wordsFromFile);
    System.err.println("done.");
  }

  private void initPanels()  {
    Container contentPane = getContentPane();
    humanArea = new ScoreArea("Me");
    computerArea = new ScoreArea("Computer");
    theBoard = new BoggleBoard(DICEROWS,DICECOLS,computerPlayer);
    wordEntryField = new WordEntryField();
    contentPane.add(wordEntryField,BorderLayout.SOUTH);
    contentPane.add(humanArea, BorderLayout.WEST);
    contentPane.add(theBoard, BorderLayout.CENTER);
    contentPane.add(computerArea, BorderLayout.EAST);
  }
                

  private void setUpMenuBar()  {
    //Set Up Menu Bar
    JMenuBar menu = new JMenuBar();
                
    // Game Menu
    JMenu gameMenu = new JMenu("Game");
    gameMenu.setMnemonic('G');
    menu.add(gameMenu);

    JMenuItem newRandom = new JMenuItem("New Random");
    gameMenu.add(newRandom);
    newRandom.setMnemonic('N');
    newRandom.addActionListener(new ActionListener() {
      public void actionPerformed( ActionEvent e) {
        newGame(theBoard.getRandomBoard());
      }});

    JMenuItem customGame = new JMenuItem("New Custom");
    gameMenu.add(customGame);
    customGame.setMnemonic('C');
    customGame.addActionListener(new ActionListener() {
      public void actionPerformed( ActionEvent e) {
        newGame(computerPlayer.getCustomBoard());
      }});

    JMenuItem quitGame = new JMenuItem("Quit");
    gameMenu.add(quitGame);
    quitGame.setMnemonic('Q');
    quitGame.addActionListener( new ActionListener() {
      public void actionPerformed( ActionEvent e) {
        System.exit(0);
      }});

    // Help menu
    JMenu helpMenu = new JMenu("Help");
    menu.add(helpMenu);
    helpMenu.setMnemonic('H');
                
    JMenuItem aboutGame = new JMenuItem("About...");
    helpMenu.add(aboutGame);
    aboutGame.setMnemonic('A');
    aboutGame.addActionListener(new ActionListener() {
      public void actionPerformed( ActionEvent e)  {
        JOptionPane.showMessageDialog(BoggleGUI.this,
                                      "It's ABOUT time you got to work", 
                                      "About Game",
                                      JOptionPane.PLAIN_MESSAGE);
      }});
    setJMenuBar(menu);
  }

  /**
   * A class defining the visual appearance of a Boggle board, and
   * defining some related methods.
   */
  static class BoggleBoard extends JPanel {
    public static final Color BACKGROUNDCOLOR = new Color(255, 219, 13);

    private DiePanel theDice[][];
    private Vector diceBag;  // used for drawing dice for a random game
    private int rows, cols;
    private BogglePlayer theComputer;

    BoggleBoard(int rows, int cols, BogglePlayer theComputer ) {
      this.rows = rows; this.cols = cols;
      this.theComputer = theComputer;

      // create some dice to use when getting a random game
      initDiceBag();

      // create a JPanel with rowsXcols GridLayout to hold the DiePanels
      JPanel innerPanel = new JPanel();
      innerPanel.setLayout(new GridLayout(rows,cols,1,1));
      innerPanel.setBackground(BACKGROUNDCOLOR);
        
      // Create Individual DiePanels, and add them
      theDice = new DiePanel[rows][cols];
      for (int row = 0; row < rows; row++)      {
        for (int col = 0; col < cols; col++)      {
          theDice[row][col] = new DiePanel();

          innerPanel.add(theDice[row][col]);
        }
      }
      innerPanel.setBorder(BorderFactory.createMatteBorder(10,10,10,10,      
                                                           BACKGROUNDCOLOR));
      this.add(innerPanel);
    }

    // fill the diceBag with the 16 "official" Boggle dice for the 4X4 game
    private void initDiceBag() {
      diceBag = new Vector(16);
      diceBag.add(new Die("A", "O", "B", "B", "O", "J"));
      diceBag.add(new Die("W", "H", "G", "E", "E", "N"));
      diceBag.add(new Die("N", "R", "N", "Z", "H", "L"));
      diceBag.add(new Die("N", "A", "E", "A", "G", "E"));
      diceBag.add(new Die("D", "I", "Y", "S", "T", "T"));
      diceBag.add(new Die("I", "E", "S", "T", "S", "O"));
      diceBag.add(new Die("A", "O", "T", "T", "W", "O"));
      diceBag.add(new Die("H", "Qu", "U", "M", "N", "I"));
      diceBag.add(new Die("R", "Y", "T", "L", "T", "E"));
      diceBag.add(new Die("P", "O", "H", "C", "S", "A"));
      diceBag.add(new Die("L", "R", "E", "V", "Y", "D"));
      diceBag.add(new Die("E", "X", "L", "D", "I", "R"));
      diceBag.add(new Die("I", "E", "N", "S", "U", "E"));
      diceBag.add(new Die("S", "F", "F", "K", "A", "P"));
      diceBag.add(new Die("I", "O", "T", "M", "U", "C"));
      diceBag.add(new Die("E", "H", "W", "V", "T", "R"));
    }

    /**
     * Return an array of Strings showing the sequence of faces on
     * a randomly generated board.
     */
    public String[] getRandomBoard()  {
      // Get random faces from randomy selected dice to fill the letterList
      int diceBagSize = diceBag.size();
      int boardSize = rows * cols;
      String[] letterList = new String[(rows * cols)];
      // we try to handle any size board with a fixed diceBag
      for (int i = 0; i<boardSize; i++) {
        if(i % diceBagSize == 0 )  Collections.shuffle(diceBag);
        Die d = (Die) diceBag.elementAt(i % diceBagSize);
        letterList[i] =   d.getRandomFace();
      }
      // set the corresponding DiePanels, and return the result
      return letterList;
    }

    /**
     * Non-randomly reset the board according to 
     * an array of Strings showing the sequence of faces on
     * the new board.  Return the array.
     */
    public void setBoard(String[] letterList)  {
      if(letterList == null ||
         letterList.length != rows*cols) {
        throw new IllegalArgumentException("setBoard(): String array length is not " + rows*cols);
      }
                
      //Set the DiePanels with given letters
      for (int row = 0; row < rows; row++)  {
        for (int col = 0; col < cols; col++)  {
          theDice[row][col].setFace(letterList[(row*cols) + col]);
        }
      }
    }

    public java.util.List getLocationsForWord(String word) {
      // we use the computer player for this
      return theComputer.isOnBoard(word);
    }
    
    public String getWordFromLocations(java.util.List locations) {
      int loc;
      int row,col;
      if (locations==null) return null;
      String result = "";
      for(int i = 0; i < locations.size(); i++)              {
        loc = ((Integer)locations.get(i)).intValue();
        row = loc / rows;
        col = loc % cols;
        result += theDice[row][col].getFace();
      }
      return result;
    }

    public void highlightDice(java.util.List locations) {
      if(locations == null) return;

      Integer loc;
      int row, col;

      unHighlightAllDice();
      for(int i = 0; i < locations.size(); i++) {
        highlightDie((Integer) locations.get(i));
      }
      this.paintImmediately(this.getVisibleRect());
    }

    /**
     * Highlight the specified die, given row and column.
     */
    public void highlightDie(int row, int column) {
      theDice[row][column].highlight();
    }

    /**
     * Highlight the specified die, given Integer offset
     * from upper-left-hand corner, using left-to-right,
     * top-to-bottom ordering of dice.
     */
    public void highlightDie(Integer indx) {
      int i = indx.intValue();
      int row = i / theDice[0].length;
      int col = i % theDice[0].length;
      highlightDie(row, col);
    }

    /**
     * Unhighlight all dice.
     */
    public void unHighlightAllDice()  {
      for (int row = 0; row < theDice.length; row++)   {
        for (int col = 0; col < theDice[row].length; col++)  {
          theDice[row][col].unHighlight();
        }
      }
      this.paintImmediately(this.getVisibleRect());
    }


    static class Die {
      private String[] sides;
      private int currentSideUp;
      public Random randomizer = new Random();

      public Die(String side1, String side2, String side3,
                 String side4, String side5, String side6)    {
        sides = new String[] {side1,side2,side3,side4,side5,side6};
        randomize();
      }

      public String getLetter()    {
        return sides[currentSideUp];
      }

      public String getRandomFace()    {
        randomize();
        return sides[currentSideUp];
      }

      private void randomize()    {
        currentSideUp = randomizer.nextInt(6);
      }
    }
                


    // For displaying one Die on the board
    static class DiePanel extends JPanel {
      private String face;
      private boolean isHighlighted;
      private JLabel faceLabel;

      private final Color DIECOLOR = new Color(230, 230, 230);
      private final Color FACECOLOR = new Color(3, 51, 217);
        
      private final Font FACEFONT = new Font("SansSerif", Font.PLAIN, 24);
      private final int DIESIZE = 50;

      public DiePanel()  {
        face = new String(""); 
        faceLabel = new JLabel("", SwingConstants.CENTER);
        setLayout(new BorderLayout());
        add(faceLabel, BorderLayout.CENTER);
        setBackground(BoggleBoard.BACKGROUNDCOLOR);
        setSize(DIESIZE, DIESIZE);
      }

      public Dimension getPreferredSize()  {
        return (new Dimension (DIESIZE+1, DIESIZE+1));
      }

      public Dimension getMinimumSize()  {
        return (getPreferredSize());
      }

      public void setFace( String chars )  {
        face = chars;
      }

      public String getFace() {
        return face;
      }

      /**
       * Draw one die including the letter centered in the middle of the die.
       * If highlight is true, we 
       * reverse the background and letter colors to highlight the die.
       */
      public void paintComponent(Graphics g)  {
        super.paintComponent(g);
                
        int centeredXOffset, centeredYOffset;
        // Draw the blank die
        g.setColor( (isHighlighted) ? FACECOLOR : DIECOLOR);
        g.fillRoundRect( 0, 0, DIESIZE, DIESIZE, DIESIZE/2, DIESIZE/2);
                
        // Outline the die with black
        g.setColor(Color.black);
        g.drawRoundRect( 0, 0, DIESIZE, DIESIZE, 
                         DIESIZE/2, DIESIZE/2);
        Graphics faceGraphics = faceLabel.getGraphics();
        faceGraphics.setColor( isHighlighted ? DIECOLOR : FACECOLOR);   
        Color myColor =  isHighlighted ? DIECOLOR : FACECOLOR;  
        faceLabel.setForeground(myColor);
        faceLabel.setFont(FACEFONT);
        faceLabel.setText(face);
      }

      public void unHighlight()  {
        isHighlighted = false;
      }

      public void highlight()  {
        isHighlighted = true;
      }
    }

  } // class BoggeBoard

  // Maintains name, score, and word list information for one player
  class ScoreArea extends JPanel {
    private final int WORDAREALINES = 16;
    private String playerName;
    private int playerScore, dimensionX, dimensionY;
    private HashSet wordList;
        
    private final Font ScoreFont = new Font("SansSerif", Font.PLAIN, 18);
    private final Font WordFont = new Font("Geneva", Font.PLAIN, 9);
    private final Font LabelFont = new Font("Helvitica", Font.PLAIN, 9);

    private final Color WordColor = new Color(3, 128, 77);
    private final Color LabelColor = new Color(3, 115, 64);

    private JPanel topPanel, wordPanel, namePanel, scorePanel;
    private JTextArea wordArea;
    private JLabel nameText, scoreText;
        
    public ScoreArea(String player) {
      playerName = new String(player);
      playerScore = 0;
      wordList = new HashSet();
                
      // Set-Up Top of Score Area
      namePanel = new JPanel();
      nameText = new JLabel(player);
      nameText.setFont(ScoreFont);
      namePanel.setLayout( new BorderLayout() );
      namePanel.add(nameText, BorderLayout.CENTER);

      scorePanel = new JPanel();
      scoreText = new JLabel("  0");
      scoreText.setFont(ScoreFont);
      scorePanel.setLayout( new BorderLayout() );
      scorePanel.add(scoreText, BorderLayout.CENTER);

      topPanel = new JPanel();
      topPanel.setLayout( new BorderLayout());
      topPanel.add(namePanel, BorderLayout.WEST);
      topPanel.add(scorePanel, BorderLayout.EAST);
                
      // Create bordering for top panel
      Border raisedBevel, loweredBevel, compound;
                
      raisedBevel = BorderFactory.createRaisedBevelBorder();
      loweredBevel = BorderFactory.createLoweredBevelBorder(); 
      compound = BorderFactory.createCompoundBorder(raisedBevel,
                                                    loweredBevel);
      topPanel.setBorder(compound);
                
      // Set-Up area to display word list
      wordPanel = new JPanel();
      Border etched = BorderFactory.createEtchedBorder();
      TitledBorder etchedTitle =
        BorderFactory.createTitledBorder(etched, "Word List");
      etchedTitle.setTitleJustification(TitledBorder.RIGHT);
      wordPanel.setBorder(etchedTitle);
      wordArea = new JTextArea(WORDAREALINES,
                               // 2/3 of max word len is a good # of columns
                               BoggleGUI.DICEROWS*BoggleGUI.DICECOLS*2/3);
      wordArea.addMouseListener(new MouseAdapter() {
        public void mouseClicked(MouseEvent e) {
          // if double-click, highlight the selection on the board
          if(e.getClickCount() == 2) {
            String word = wordArea.getSelectedText().trim();
            theBoard.highlightDice(theBoard.getLocationsForWord(word));
          }
        }});
      wordArea.setEditable(false); // for now
      wordPanel.add(new JScrollPane(wordArea,
                                    JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
                                    JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED));

      setLayout(new BorderLayout());
      add(topPanel, BorderLayout.NORTH);
      add(wordPanel, BorderLayout.CENTER);
    }

    public void setReady()  {
      resetScore();  // zero out score
      wordList.clear();  // remove words from HashSet
      // remove words from TextArea
      wordArea.setEditable(true);
      wordArea.selectAll();
      wordArea.cut();
      wordArea.setEditable(false);
      paintImmediately(getVisibleRect());
    }

    public void setName(String newName)  {
      playerName = newName;
      nameText.setText(playerName);
      repaint();
    }

    public boolean containsWord(String word) {
      return wordList.contains(word);
    }

    public void addWord(String word)  {
      if (containsWord(word)) return;
      wordList.add(word);
      wordArea.append(" " +word+"\n");
      addPoints(pointsForWord(word));
      wordArea.paintImmediately(wordArea.getVisibleRect());
    }

    /**
     * Define how many points a player gets for a given word.
     */
    public int pointsForWord(String word) {
      return word.length() - BoggleGUI.MINIMUMWORDLENGTH + 1;
    }

    public void addPoints(int points)  {
      playerScore += points;
      scoreText.setText(playerScore+"");
      scoreText.paintImmediately(scoreText.getVisibleRect());
    }

    public void resetScore() {
      playerScore = 0;
      scoreText.setText(playerScore+"");
      scoreText.paintImmediately(scoreText.getVisibleRect());
    }

  } // class ScoreArea

  class WordEntryField extends JPanel {
    private JTextField textField;
    
    public WordEntryField() {
      //Set up for human player's Text Entry Field
      textField = new JTextField(30);
      //Add listener to text entry field
      textField.addActionListener( new ActionListener() {
        public void actionPerformed( ActionEvent e) {
          checkAndAddWordHuman(textField.getText());
        }});
      this.add(new JLabel("Enter word: "));
      this.add(textField);
      setUnready();
    }

    public void clear() {
      textField.setText("");
    }

    public void setUnready() {
      clear();
      textField.setEditable(false);
      paintImmediately(getVisibleRect());
      // attempt to give up focus to top-level frame
      BoggleGUI.this.requestFocus();
    }
    public void setReady() {
      textField.setEditable(true);
      textField.requestFocus();
    }
  } // class WordEntryField

  /**
   * The entry point for the BoggleGUI application.
   * Usage:
   * java BoggleGUI [ wordfile [ rows [ columns [ minwordlength ]]]]
   */
  public static void main(String args[] )  {
    if (args.length ==0) WORDLISTFILENAME = "enable1.txt";
    if(args.length > 0) WORDLISTFILENAME = args[0];
    if(args.length > 1) DICEROWS = Integer.parseInt(args[1]);
    if(args.length > 2) DICECOLS = Integer.parseInt(args[2]);
    if(args.length > 3) MINIMUMWORDLENGTH = Integer.parseInt(args[3]);

    System.err.println("Starting " + DICEROWS + "x" + DICECOLS + " game," +
		       " words from " + WORDLISTFILENAME +
		       ", min word length " + MINIMUMWORDLENGTH + ".");
    (new BoggleGUI()).setVisible(true);
  }

}