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 }