/* * JFLAP - Formal Languages and Automata Package * * * Susan H. Rodger * Computer Science Department * Duke University * August 27, 2009 * Copyright (c) 2002-2009 * All rights reserved. * JFLAP is open source software. Please see the LICENSE for terms. * */ package gui.pumping; import java.awt.BorderLayout; import java.awt.Dimension; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.*; import pumping.PumpingLemma; /** * This class represents the implementation of PumpingLemmaInputPane wherein * the user makes the first move. The user will choose the m and decomposition values, * while the computer will generate the w and i values based on the user's input. * The decomp panel has a network of sliders and displays allowing for the user to choose the decomposition. * * @author Chris Morgan & Jinghui Lim */ public abstract class HumanFirstPane extends PumpingLemmaInputPane { /** * The goal of the user, which is to try to find a valid pumping lemma. */ private static String OBJECTIVE = "Find a valid partition that can be pumped."; /** * The instruction that prompts for m. */ private static String PROMPT_M = "Please select a value for m in Box 1 and press \"Enter\"."; /** * The description that explains the selection of w. */ private static String DESCRIBE_W = "I have selected w such that |w| >= m. It is displayed in Box 2."; /** * The instruction that prompts for the decomposition of w. */ private static String PROMPT_DECOMPOSITION = "Please select the decomposition of w in Box 3 using the sliders."; /** * The description that explains the selection of i. */ private static String DESCRIBE_I = "I have selected i to give a contradition. It is displayed in Box 4."; /** * This string allows subclasses to set the title of myDecompButton. */ protected String decompButtonTitle; /** * The SliderPanel that controls x of the decomposition. */ protected SliderPanel myXPanel; /** * The SliderPanel that controls y of the decomposition. */ protected SliderPanel myYPanel; /** * The button that enters the decomposition into the lemma. */ protected JButton myDecompButton; /** * The text area that displays z of the decomposition or a short * message indicating a condition violated in selecting the decomposition. */ protected JTextArea myZDisplay; /** * The text area that displays the length of z. */ protected JTextArea myZLength; /** * The table that displays the string w with each character in a cell * for easy visualization. */ protected JTable myXYZDisplay; /** * The panel that holds both the u, v, x, and y * sliders and the table that displays the string w. */ protected JPanel myXYZPanel; /** * The panel the SliderPanels are put on. Subclasses can add to it. */ protected JPanel sliderPanel; public HumanFirstPane(PumpingLemma l, String title) { super(l, title); l.setFirstPlayer(PumpingLemma.HUMAN); } /** * Initializes and returns a panel that allows the user to choose the * decomposition of w into xyz with sliders. * The panel also contains a single-row table in which each cell contains * one character of w such that each column corresponds to * one unit in the sliders. This is done to aid the visualization process. * * @return a panel that takes the decomposition from the user */ protected JPanel initDecompPanel() { JPanel n = new JPanel(new BorderLayout()); JPanel o = new JPanel(); o.setLayout(new BoxLayout(o, BoxLayout.X_AXIS)); sliderPanel = new JPanel(); sliderPanel.setLayout(new BoxLayout(sliderPanel, BoxLayout.Y_AXIS)); addDecompPanelGameFeatures(n); myXPanel = new SliderPanel("x", this); sliderPanel.add(myXPanel); myYPanel = new SliderPanel("y", this); sliderPanel.add(myYPanel); JPanel m = new JPanel(); // I'm really running out of letters here m.setLayout(new BoxLayout(m, BoxLayout.X_AXIS)); m.setBorder(BorderFactory.createEmptyBorder(0, 8, 8, 7)); m.add(new JLabel("z: ")); myZDisplay = new JTextArea(1, 30); myZDisplay.setEditable(false); m.add(myZDisplay); m.add(new JLabel(" |z|: ")); myZLength = new JTextArea(1, 5); myZLength.setEditable(false); m.add(myZLength); sliderPanel.add(m); myXYZPanel = new JPanel(new BorderLayout()); myXYZDisplay = new JTable(1, 1); myXYZDisplay.setEnabled(false); myXYZPanel.add(myXYZDisplay); myXYZPanel.setBorder(BorderFactory.createEmptyBorder(0, 8, 0, 7)); sliderPanel.add(myXYZPanel, BorderLayout.SOUTH); JPanel p = new JPanel(new BorderLayout()); p.add(stageMessages[3], BorderLayout.WEST); sliderPanel.add(p); o.add(sliderPanel); JPanel q = new JPanel(); q.setLayout(new BoxLayout(q, BoxLayout.Y_AXIS)); myDecompButton = new JButton(decompButtonTitle); myDecompButton.setEnabled(false); myDecompButton.addActionListener(new ActionListener() { public void actionPerformed (ActionEvent ev) { stages[4].setVisible(true); stages[5].setVisible(true); resetMessages(); setI(); displayIEnd(); if (myLemma.isInLang(myLemma.createPumpedString())) myLemma.addAttempt(myLemma.getDecompositionAsString()+"; I = "+myLemma.getI() + "; Won"); else myLemma.addAttempt(myLemma.getDecompositionAsString()+"; I = "+myLemma.getI() + "; Failed"); updateTopPane(false); leftPanel.revalidate(); setCanvas(); myCanvas.stop(); /* * If there is only one case and myCases will not * have been initialized. */ if(myCases != null) myCases.setAddReplaceButtonsEnabled(true); } }); q.add(myDecompButton); o.add(q); n.add(o, BorderLayout.NORTH); return n; } /** * Updates the individual cells in the single-row table such that each * show a character of the string. It resizes the table depending on how * many characters there are. */ public void updateTable() { myXYZPanel.remove(myXYZDisplay); myXYZDisplay = new JTable(1, myLemma.getW().length()); myXYZDisplay.setEnabled(false); String s = myLemma.getW(); for(int i = 0; i < s.length(); i++) myXYZDisplay.setValueAt(s.substring(i, i + 1), 0, i); myXYZPanel.add(myXYZDisplay, BorderLayout.CENTER); } protected String addTopGameFeatures(JButton b) { b.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { myMDisplay.setText(""); updateTopPane(false); reset(); } }); return OBJECTIVE; } protected String addMGameFeatures() { myMDisplay = new JTextField(10); ((JTextField)myMDisplay).addActionListener(new ActionListener() { public void actionPerformed (ActionEvent ev) { try { reset(); int m = Integer.parseInt(ev.getActionCommand()); if(!(m >= myLemma.getRange()[0] && m <= myLemma.getRange()[1])) throw new NumberFormatException(); myLemma.setM(m); stages[2].setVisible(true); stages[3].setVisible(true); mEnteredReset(); /* * If this is has only one case, myCases will not be initialized * so we check for null. */ if(myCases != null) myCases.setListButtonEnabled(true); } catch(NumberFormatException e) { //Something other than a positive integer was entered. String error = "Please enter a positive integer in range [" + myLemma.getRange()[0] + ", " + myLemma.getRange()[1] + "] for best results."; myMDisplay.selectAll(); stageMessages[1].setText(error); } } }); return new String(PROMPT_M); } protected String addWGameFeatures() { myWDisplay = new JTextArea(1, 20); myWDisplay.setEditable(false); return new String(DESCRIBE_W); } /** * The method through which subclasses can customize features of the w stage panel * upon initialization of the w JPanel. * * @param p the current decomposition panel */ protected abstract void addDecompPanelGameFeatures(JPanel p); protected String addIGameFeatures() { myIDisplay = new JTextArea(1, 5); myIDisplay.setEditable(false); return new String(DESCRIBE_I); } public void displayEnd() { String s = myLemma.createPumpedString(); myPumpedStringDisplay.setText(s); if(myLemma.isInLang(s)) myLastWord.setText(createXYZ() + " = " + PumpingLemmaInputPane.toHTMLString(s) + " = " + s + " is in the language. YOU WIN!"); else myLastWord.setText(createXYZ() + " = " + PumpingLemmaInputPane.toHTMLString(s) + " = " + s + " is NOT in the language. Please try again."); } /** * Resets various fields after m is entered. */ protected abstract void mEnteredReset(); /** * Refreshes the various fields accordingly after any action is taken when adjusting * SliderPanels. */ protected abstract void refresh(); /** * Calculates i and the associated pumped string based on the user's decomposition. */ protected abstract void setI(); }