package cse1030.games.boggle; import java.awt.Color; import java.awt.Dimension; import java.awt.Font; import java.awt.GridLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; import javax.swing.BoxLayout; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JTextArea; import javax.swing.JTextField; /** * The view for the Boggle app. Please see the lab for a detailed description of * the view. * * @author CSE1030_F13_14 * */ public class BoggleView extends JFrame implements ActionListener { /** * The string representing the clear command. The view listens for its own * clear event. */ public static final String CLEAR_COMMAND = "clear"; /** * The string representing the roll command. */ public static final String ROLL_COMMAND = "roll"; /** * The string repesenting the submit command. */ public static final String SUBMIT_COMMAND = "submit"; /** * A list that contains references to the buttons representing the dice. */ private List diceButtons; /** * The text field that displays the current word. */ private JTextField word; /** * The set of dice buttons that have already been used to form the current * word. */ private Set usedButtons; /** * The text area that displays the list of correct words. */ private JTextArea correctWords; /** * The text area that displays the list of incorrect words. */ private JTextArea incorrectWords; /** * Create the Boggle user interface. Please see the lab for a detailed * description of the user interface. * * @param controller * the controller that listens for submit and roll events */ public BoggleView(BoggleController controller) { super("Boggle"); this.diceButtons = new ArrayList(); this.usedButtons = new HashSet(); JPanel contentPanel = new JPanel(); JPanel leftPanel = this.makeLeftPanel(); JPanel rightPanel = this.makeRightPanel(); JPanel middlePanel = this.makeMiddlePanel(controller); contentPanel.add(leftPanel); contentPanel.add(middlePanel); contentPanel.add(rightPanel); this.setContentPane(contentPanel); this.pack(); this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); } /** * Creates the panel that contains the buttons representing the Boggle dice. * * @return the JPanel that contains the buttons representing the * Boggle dice. * */ private JPanel makeDicePanel() { Font font = new Font(Font.SANS_SERIF, Font.BOLD, 32); JPanel p = new JPanel(); p.setLayout(new GridLayout(4, 4)); p.setMaximumSize(new Dimension(450, 450)); for (int i = 0; i < 16; i++) { JButton b = new JButton("" + i); b.setPreferredSize(new Dimension(100, 100)); b.setMaximumSize(b.getSize()); b.setFont(font); b.setBackground(Color.WHITE); b.setActionCommand("" + i); b.addActionListener(this); p.add(b); this.diceButtons.add(b); } return p; } /** * Returns the buttons surrounding the button representing the die that was * last selected by the user. These are the buttons that could legally be * chosen next by the user when forming a word. * * @param idx * the index of the button representing the die that was last * selected by the user * @return the buttons surrounding the last selected die */ private List findNeighbors(int idx) { List neighbors = new ArrayList(); final int row = idx / 4; final int col = idx % 4; final int minRow = Math.max(0, row - 1); final int maxRow = Math.min(3, row + 1); final int minCol = Math.max(0, col - 1); final int maxCol = Math.min(3, col + 1); for (int i = minRow; i <= maxRow; i++) { for (int j = minCol; j <= maxCol; j++) { int n = i * 4 + j; if (n != idx) { neighbors.add(this.diceButtons.get(n)); } } } return neighbors; } /** * Disable all of the buttons representing the dice. */ private void disableAllDiceButtons() { for (JButton b : this.diceButtons) { b.setEnabled(false); } } /** * Enable all of the buttons representing the dice. */ private void enableAllDiceButtons() { for (JButton b : this.diceButtons) { b.setEnabled(true); b.setBackground(Color.WHITE); } } /** * Responds to events from the view. This method responds to an event where * the action command is either BoggleView.CLEAR_COMMAND, * BoggleView.ROLL_COMMAND, or * BoggleView.SUBMIT_COMMAND. * * @param event * an event emitted by the view * * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent) */ @Override public void actionPerformed(ActionEvent event) { String command = event.getActionCommand(); if (command.equals(CLEAR_COMMAND)) { this.clearCurrentWord(); } else if (command.equals(ROLL_COMMAND)) { this.clearCorrectWords(); this.clearIncorrectWords(); this.clearCurrentWord(); } else { try { int d = Integer.parseInt(command); JButton b = this.diceButtons.get(d); b.setBackground(Color.BLUE); this.word.setText(this.word.getText() + b.getText()); this.usedButtons.add(b); this.disableAllDiceButtons(); List neighbors = findNeighbors(d); for (JButton n : neighbors) { if (!this.usedButtons.contains(n)) { n.setEnabled(true); } } } catch (NumberFormatException ex) { } } } /** * Creates the left-hand panel. Please see the lab for a detailed description * of the panel's contents. * * @return the left-hand JPanel with all of its necessary * components */ private JPanel makeLeftPanel() { // create the panel JPanel p = new JPanel(); // set the layout for the panel to use a BoxLayout; // BoxLayout stacks its components vertically or horizontally p.setLayout(new BoxLayout(p, BoxLayout.Y_AXIS)); // create a label for the list of correct words and add it to the panel JLabel label = new JLabel("Correct Words"); p.add(label); // create the list of correct words, remove the ability for the user to // edit the list, and add it to the panel this.correctWords = new JTextArea(30, 16); this.correctWords.setEditable(false); p.add(this.correctWords); return p; } /** * Creates the right-hand panel. Please see the lab for a detailed description * of the panel's contents. * * @return the right-hand JPanel with all of its necessary * components */ private JPanel makeRightPanel() { JPanel p = new JPanel(); // follow makeLeftPanel return p; } /** * Creates the middle panel. Please see the lab for a detailed description of * the panel's contents. * * @return the middle JPanel with all of its necessary components */ private JPanel makeMiddlePanel(BoggleController controller) { JPanel p = new JPanel(); // 1. set the layout to a BoxLayout (same as makeLeftPanel) // 2. make the dice panel and add it to p; there is a method that makes the // dice panel for you! // 3. make the contorl panel and add it to p; there is a method that makes // the control for you! return p; } /** * Creates the panel that contains the clear, submit, and re-roll buttons, and * the text field for the word. * * @return the JPanel that contains the controls below the dice * */ private JPanel makeControlPanel(BoggleController controller) { JPanel p = new JPanel(); // You don't need to create a lay out. JPanel uses FlowLayout if you don't // specify a lay out. // Make the clear button JButton clear = new JButton("Clear"); // Set its action command to the clear command clear.setActionCommand(BoggleView.CLEAR_COMMAND); // Add this as an action listener; see the actionPerformed method above. // The controller does not need to listen to this button because the model // is not needed to clear the current word. clear.addActionListener(this); // Add the clear button to the panel. p.add(clear); // Make a text field that can display a 16 character word this.word = new JTextField(16); // Disable editing by the user. this.word.setEditable(false); // Add the text field to the panel. p.add(this.word); // Here, you need to: // - make the submit button // - set its action command // - add the controller as an action listener // - add the submit button to the panel // Here, you need to: // - make the re-roll button // - set its action command // - add the controller as an action listener // - add this as an action listener // - add the re-roll button to the panel return p; } /** * Get the current string that is in the word text field. * * @return the current string that is in the word text field */ public String getWord() { // change the return statement below return ""; } /** * Sets the text on the buttons representing the dice. * * @pre. dice.size() == 16 * * @param dice * a list of 16 Boggle dice */ public void setDice(List dice) { } /** * Causes the view to update after the submitted word is evaluated for * correctness. If isCorrect == true then the current word is * added to the list of correct words. If isCorrect == false then * the current word is added to the list of incorrect words. In both cases, * the current word is cleared. * * @param isCorrect * true if the current word has been determined to be a * legal Boggle word, false otherwise */ public void setWordIsCorrect(boolean isCorrect) { } /** * Clears the list of correct words. */ private void clearCorrectWords() { } /** * Clears the list of incorrect words. */ private void clearIncorrectWords() { } /** * Clears the current word and prepares the view to accept a new word. This * requires re-enabling all of the dice buttons and clearing the set * this.usedButtons */ private void clearCurrentWord() { // 1. enable all of the dice buttons; there is a method that does this for // you // 2. set the text of this.word to the empty string // 3. remove all of the buttons from this.usedButtons } public static void main(String[] args) { BoggleView v = new BoggleView(null); v.setVisible(true); } }