001 /** 002 * A dialog box that allows a user to start a new game of Antichess. The user 003 * chooses the type (human or computer) of each player, the amount of time 004 * allotted to each, and the number of powerups to be placed on each side of the 005 * board. 006 */ 007 008 package ui; 009 010 import java.awt.Dimension; 011 import java.awt.event.ActionEvent; 012 import java.awt.event.ActionListener; 013 import java.awt.event.WindowEvent; 014 import java.awt.event.WindowListener; 015 016 import javax.swing.Box; 017 import javax.swing.BoxLayout; 018 import javax.swing.ButtonGroup; 019 import javax.swing.JButton; 020 import javax.swing.JFrame; 021 import javax.swing.JLabel; 022 import javax.swing.JPanel; 023 import javax.swing.JRadioButton; 024 import javax.swing.JTextField; 025 import javax.swing.WindowConstants; 026 027 public class NewGameDialog extends JFrame 028 implements ActionListener, WindowListener { 029 030 static final long serialVersionUID = 666; 031 032 private JRadioButton wHuman; 033 private JRadioButton wCPU; 034 private JRadioButton bHuman; 035 private JRadioButton bCPU; 036 037 private JTextField wTime; 038 private JTextField bTime; 039 040 private JTextField powerupField; 041 042 private JButton beginButton; 043 044 private boolean successful; // false unless the begin button was pressed 045 046 /** 047 * Private constructor. To use a NewGameDialog, use the static showDialog 048 * method. 049 */ 050 private NewGameDialog() { 051 JPanel mainPanel; 052 JPanel topPanel; 053 JPanel whitePanel; 054 JPanel wTimePanel; 055 JPanel blackPanel; 056 JPanel bTimePanel; 057 JPanel powerupPanel; 058 JPanel buttonPanel; 059 060 wHuman = new JRadioButton("Human"); 061 wCPU = new JRadioButton("CPU"); 062 ButtonGroup wGroup = new ButtonGroup(); 063 wGroup.add(wHuman); 064 wGroup.add(wCPU); 065 wHuman.setSelected(true); 066 067 wTime = new JTextField("5:00", 1); 068 069 wTimePanel = new JPanel(); 070 wTimePanel.setLayout(new BoxLayout(wTimePanel, BoxLayout.X_AXIS)); 071 wTimePanel.add(new JLabel("Time:")); 072 wTimePanel.add(Box.createRigidArea(new Dimension(5, 5))); 073 wTimePanel.add(wTime); 074 075 whitePanel = new JPanel(); 076 whitePanel.setLayout(new BoxLayout(whitePanel, BoxLayout.Y_AXIS)); 077 whitePanel.add(new JLabel("White")); 078 whitePanel.add(Box.createRigidArea(new Dimension(5, 5))); 079 whitePanel.add(wHuman); 080 whitePanel.add(wCPU); 081 whitePanel.add(Box.createRigidArea(new Dimension(5, 5))); 082 whitePanel.add(wTimePanel); 083 084 bHuman = new JRadioButton("Human"); 085 bCPU = new JRadioButton("CPU"); 086 ButtonGroup bGroup = new ButtonGroup(); 087 bGroup.add(bHuman); 088 bGroup.add(bCPU); 089 bHuman.setSelected(true); 090 091 bTime = new JTextField("5:00", 1); 092 093 bTimePanel = new JPanel(); 094 bTimePanel.setLayout(new BoxLayout(bTimePanel, BoxLayout.X_AXIS)); 095 bTimePanel.add(new JLabel("Time:")); 096 bTimePanel.add(Box.createRigidArea(new Dimension(5, 5))); 097 bTimePanel.add(bTime); 098 099 blackPanel = new JPanel(); 100 blackPanel.setLayout(new BoxLayout(blackPanel, BoxLayout.Y_AXIS)); 101 blackPanel.add(new JLabel("Black")); 102 blackPanel.add(Box.createRigidArea(new Dimension(5, 5))); 103 blackPanel.add(bHuman); 104 blackPanel.add(bCPU); 105 blackPanel.add(Box.createRigidArea(new Dimension(5, 5))); 106 blackPanel.add(bTimePanel); 107 108 topPanel = new JPanel(); 109 topPanel.setLayout(new BoxLayout(topPanel, BoxLayout.X_AXIS)); 110 topPanel.add(Box.createRigidArea(new Dimension(15, 5))); 111 topPanel.add(whitePanel); 112 topPanel.add(Box.createRigidArea(new Dimension(30, 5))); 113 topPanel.add(blackPanel); 114 topPanel.add(Box.createRigidArea(new Dimension(15, 5))); 115 116 beginButton = new JButton("Begin"); 117 buttonPanel = new JPanel(); 118 buttonPanel.add(beginButton); 119 120 powerupField = new JTextField("0", 5); 121 powerupPanel = new JPanel(); 122 powerupPanel.setLayout(new BoxLayout(powerupPanel, BoxLayout.X_AXIS)); 123 powerupPanel.add(Box.createHorizontalGlue()); 124 powerupPanel.add(new JLabel("Powerups per side:")); 125 powerupPanel.add(Box.createRigidArea(new Dimension(5, 5))); 126 powerupPanel.add(powerupField); 127 powerupPanel.add(Box.createHorizontalGlue()); 128 powerupField.setMaximumSize(powerupField.getPreferredSize()); 129 130 mainPanel = new JPanel(); 131 mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.Y_AXIS)); 132 mainPanel.add(topPanel); 133 mainPanel.add(Box.createRigidArea(new Dimension(5, 20))); 134 mainPanel.add(powerupPanel); 135 mainPanel.add(Box.createRigidArea(new Dimension(5, 5))); 136 mainPanel.add(buttonPanel); 137 138 this.add(mainPanel); 139 140 beginButton.addActionListener(this); 141 this.addWindowListener(this); 142 143 successful = false; 144 145 this.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); 146 147 this.setTitle("New Game"); 148 this.setSize(this.getPreferredSize()); 149 this.setVisible(true); 150 this.setSize(this.getPreferredSize()); 151 } 152 153 /** 154 * @requires s is of the form [seconds] or [minutes]:[seconds], or else s is 155 * the empty String "". 156 * @return an integer representing the time in milliseconds represented by 157 * the String argument. (If s is the empty String or cannot be parsed, 0 is 158 * returned.) 159 */ 160 private int parseTime(String s) { 161 s = s.trim(); 162 163 if (s.length() == 0) { 164 return 0; 165 } 166 167 int minutes; 168 int seconds; 169 170 // No colon; s is just a number of seconds 171 try { 172 if (s.indexOf(":") == -1) { 173 minutes = 0; 174 seconds = Integer.parseInt(s); 175 } 176 177 // s has the form [minutes]:[seconds] 178 else { 179 minutes = Integer.parseInt(s.substring(0, s.indexOf(":"))); 180 seconds = Integer.parseInt(s.substring(s.indexOf(":") + 1)); 181 } 182 return ((60 * minutes) + seconds) * 1000; 183 } 184 185 // If the 186 catch (NumberFormatException x) { 187 return 0; 188 } 189 } 190 191 /** 192 * @return a GameSettings object corresponding to the options the user has 193 * selected 194 * [Returns null if the window was closed by some method other than 195 * the Begin button.] 196 */ 197 private GameSettings getInfo() { 198 int wt = parseTime(wTime.getText()); 199 int bt = parseTime(bTime.getText()); 200 201 // If the contents of powerupField can't be parsed, don't add powerups 202 try { 203 int numPairs = Integer.parseInt(powerupField.getText()); 204 return new GameSettings(wHuman.isSelected(), wt, 205 bHuman.isSelected(), bt, numPairs); 206 } 207 catch (NumberFormatException x) { 208 return new GameSettings(wHuman.isSelected(), wt, 209 bHuman.isSelected(), bt, 0); 210 } 211 } 212 /** 213 * @return true if the window was closed using the Begin button 214 */ 215 private boolean wasSuccessful() { 216 return successful; 217 } 218 219 /** 220 * @return a GameSettings object based on the options the user had selected 221 * upon pressing the Begin button. 222 * [If the user closed the window some other way, this method returns 223 * null.] 224 */ 225 public synchronized static GameSettings showDialog() { 226 NewGameDialog n = new NewGameDialog(); 227 n.setSize(n.getPreferredSize()); 228 GameSettings g = n.getAnswer(); 229 n.dispose(); 230 n = null; 231 return g; 232 } 233 234 /** 235 * Called when the user presses the Begin button. Hides the dialog and 236 * notifies the waiting thread that the user has made a decision. 237 */ 238 public synchronized void actionPerformed(ActionEvent e) { 239 successful = true; 240 this.setVisible(false); 241 this.notify(); 242 } 243 244 /** 245 * Waits until the dialog is rendered invisible (by the user pressing the 246 * Begin button), then looks at the options selected by the user and returns 247 * the appropriate GameSettings object. 248 */ 249 private synchronized GameSettings getAnswer() { 250 251 while(this.isVisible()) { 252 try { 253 this.wait(); 254 } catch (InterruptedException e) {} 255 } 256 GameSettings choice = this.getInfo(); 257 if (this.wasSuccessful()) { 258 return choice; 259 } 260 else { 261 return null; 262 } 263 } 264 265 public void windowOpened(WindowEvent e) { 266 267 } 268 269 // Notify the waiting call to getAnswer() when the window is closed 270 public synchronized void windowClosed(WindowEvent e) { 271 notifyAll(); 272 } 273 274 public void windowDeactivated(WindowEvent e) { 275 276 } 277 278 public void windowClosing(WindowEvent e) { 279 280 } 281 282 public void windowIconified(WindowEvent e) { 283 284 } 285 286 public void windowDeiconified(WindowEvent e) { 287 288 } 289 290 public void windowActivated(WindowEvent e) { 291 292 } 293 294 }