-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathController.java
More file actions
365 lines (327 loc) · 12.1 KB
/
Controller.java
File metadata and controls
365 lines (327 loc) · 12.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
import java.awt.*;
import java.awt.event.*;
/**
* Set up the GUI and handles events, and lets the rabbit and
* fox take turns moving.
*
* @author David Matuszek
* @version October 24, 2001
*/
public class Controller extends Frame implements Runnable {
// instance variables -- references to main classes
private Model model;
private View view;
private Controller controller;
// instance variables -- used for program control
private boolean animationIsRunning = false;
private int animationDelay;
private int lookDelay;
private boolean needToRedrawEverything = true;
private boolean showEveryLook = true;
private boolean singleStepping = false;
// instance "varibles" -- constants for use anywhere
private static int canvasWidth = 400;
private static int canvasHeight = 400;
// instance variables -- display elements
private Canvas canvas = new Canvas();
private Panel controlPanel = new Panel();
private Panel buttonPanel = new Panel();
private Button stepButton = new Button("Step");
private Button runButton = new Button("Run");
private Button stopButton = new Button("Stop");
private Button resetButton = new Button("Reset");
private Button replayButton = new Button("Replay");
private Scrollbar speedBar = new Scrollbar(Scrollbar.HORIZONTAL);
private Label messageLabel = new Label("Let the hunt begin!");
/**
* Constructs a Controller that uses the given model and view.
*/
Controller(Model model, View view) {
this.model = model;
this.view = view;
this.controller = this;
setTitle("Fox and Rabbit");
setLocation(50, 50);
createGui();
addWindowListener(new WindowCloser());
canvas.addComponentListener(new RedrawWindow());
}
/**
* Starts and controls the animation.
*/
public void run() {
while (animationIsRunning && !model.gameIsOver) {
try { Thread.sleep(animationDelay); }
catch (InterruptedException e) { }
step();
}
}
/**
* Tells the model to make one animation "step," then tells
* the view to display the result.
*/
private void step() {
model.allowSingleMove();
if (model.gameIsOver) {
if (model.rabbitIsAlive)
messageLabel.setText("THE RABBIT HAS ESCAPED!");
else
messageLabel.setText("THE FOX EATS THE RABBIT AFTER " +
model.stepsTaken + " TURNS!");
animationIsRunning = false;
runButton.setEnabled(false);
stopButton.setEnabled(false);
stepButton.setEnabled(false);
resetButton.setEnabled(true);
replayButton.setEnabled(true);
}
else {
messageLabel.setText("Step number " + model.stepsTaken);
}
view.setDisplayLookingAround(singleStepping, lookDelay);
if (needToRedrawEverything) {
view.displayEverything();
needToRedrawEverything = false;
}
else {
view.displayChanges();
}
}
/**
* Sets up the graphical user interface, including adding actions
* to the components, and displays it.
*/
private void createGui() {
// use border layout for main GUI organization
setLayout(new BorderLayout());
canvas.setSize(canvasWidth, canvasHeight);
// put a label at the top of the GUI
add(BorderLayout.NORTH, messageLabel);
// put canvas in main area of GUI
add(BorderLayout.CENTER, canvas);
// put control panel at bottom of GUI
add(BorderLayout.SOUTH, controlPanel);
controlPanel.setLayout(new BorderLayout());
controlPanel.add(BorderLayout.WEST, new Label("Speed:"));
controlPanel.add(BorderLayout.CENTER, speedBar);
// add button panel (with buttons) to control panel
controlPanel.add(BorderLayout.EAST, buttonPanel);
buttonPanel.add(stepButton);
buttonPanel.add(runButton);
buttonPanel.add(stopButton);
buttonPanel.add(resetButton);
buttonPanel.add(replayButton);
// add actions to the controls (see end of this file)
stepButton.addActionListener(new StepButtonHandler());
runButton.addActionListener(new RunButtonHandler());
stopButton.addActionListener(new StopButtonHandler());
stopButton.setEnabled(false);
animationIsRunning = false;
resetButton.addActionListener(new ResetButtonHandler());
replayButton.addActionListener(new ReplayButtonHandler());
replayButton.setEnabled(false);
speedBar.addAdjustmentListener(new SpeedBarListener());
// finish up and display the GUI
pack();
Rectangle rectangle = speedBar.getBounds();
rectangle.y = rectangle.y + 8;
rectangle.height = rectangle.height - 16;
rectangle.width = rectangle.width - 20;
speedBar.setBounds(rectangle);
setVisible(true);
speedBar.setBounds(rectangle);
speedBar.setValue(50);
setDelays(50);
view.setCanvas(canvas); // cannot be done until visible
view.displayEverything();
}
/**
* Changes the size of the Speed scrollbar in an attempt to make
* it look reasonable regardless of the window size.
*/
private void resizeSpeedBar() {
Rectangle rectangle = speedBar.getBounds();
rectangle.y = rectangle.y + 8;
rectangle.height = Math.max(4, rectangle.height - 16);
rectangle.width = Math.max(50, rectangle.width - 20);
speedBar.setBounds(rectangle);
setVisible(true);
speedBar.setBounds(rectangle);
}
/**
* Computes the animation delay and the delay between "looks," based
* on the current value of the speedBar.
*
* @param value current value returned from the speedBar (0..90)
*/
private void setDelays(int value) {
animationDelay = (int)(2320 - 500 * Math.log(value + 10));
lookDelay = animationDelay / 2 + 10;
}
/**
* Handles a click on the close window icon by closing the
* window and quitting the program.
*/
class WindowCloser extends WindowAdapter {
public void windowClosing(WindowEvent e) {
dispose();
System.exit(0);
}
}
/**
* Inner class for handling a window show or window resize
* operation.
*/
class RedrawWindow extends ComponentAdapter {
/**
* When the window is resized, notifies the view of the
* new size, and sets a flag so that everything on the
* canvas will be redrawn.
*
* @param e parameter is ignored.
*/
public void componentResized(ComponentEvent e) {
resizeSpeedBar();
view.setCanvas(canvas);
needToRedrawEverything = true;
}
/**
* When the window is resshown, sets a flag so that everything
* on the canvas will be redrawn.
*
* @param e parameter is ignored.
*/
public void componentShown(ComponentEvent e) {
needToRedrawEverything = true;
}
}
/**
* Inner class for handling the Step button.
*/
class StepButtonHandler implements ActionListener {
/**
* Handles the Step button. If the animation is running,
* the Step button just halts it (by setting the
* <code>programIsRunning</code> flag to false); otherwise, the
* rabbit hunt is advanced one step. While single stepping,
* all buttons except the Stop button should be enabled.
*
* @param e the Event that invoked this handler (ignored).
*/
public void actionPerformed(ActionEvent e) {
singleStepping = true;
if (animationIsRunning) {
animationIsRunning = false;
// adjust button states when game ends
if (!model.gameIsOver) {
runButton.setEnabled(true);
stopButton.setEnabled(false);
resetButton.setEnabled(true);
}
}
else {
step();
}
replayButton.setEnabled(true);
}
}
/**
* Inner class for handling the Run button.
*/
class RunButtonHandler implements ActionListener {
/**
* Sets the <code>programIsRunning</code> flag to true, and
* creates and starts an animation Thread to do the animation.
* While the animation is running, all buttons except the Run
* button should be enabled.
*
* @param e the Event that invoked this handler (ignored).
*/
public void actionPerformed(ActionEvent e) {
runButton.setEnabled(false);
stopButton.setEnabled(true);
resetButton.setEnabled(false);
replayButton.setEnabled(false);
Thread animationThread = new Thread(controller);
animationIsRunning = true;
singleStepping = false;
animationThread.start();
}
}
/**
* Inner class for handling the Stop button.
*/
class StopButtonHandler implements ActionListener {
/**
* Sets the <code>programIsRunning</code> flag to false, thus
* causing run() to end the Thread doing the animation.
* While the animation is stopped, all buttons except
* the Stop button should be enabled.
*
* @param e the Event that invoked this handler (ignored).
*/
public void actionPerformed(ActionEvent e) {
animationIsRunning = false;
runButton.setEnabled(true);
stopButton.setEnabled(false);
resetButton.setEnabled(true);
replayButton.setEnabled(true);
}
}
/**
* Inner class for handling the Reset button.
*/
class ResetButtonHandler implements ActionListener {
/**
* Recreates the entire setup, including placement of
* bushes and animals. Cannot be performed while the
* animation is running. Afterwards, all buttons except
* the Stop button should be enabled.
*
* @param e the Event that invoked this handler (ignored).
*/
public void actionPerformed(ActionEvent e) {
model.reset();
messageLabel.setText("New game");
runButton.setEnabled(true);
stopButton.setEnabled(false);
stepButton.setEnabled(true);
replayButton.setEnabled(false);
view.displayEverything();
needToRedrawEverything = false;
singleStepping = false;
}
}
/**
* Inner class for handling the Replay button.
*/
class ReplayButtonHandler implements ActionListener {
public void actionPerformed(ActionEvent e) {
model.replay();
messageLabel.setText("Instant replay");
runButton.setEnabled(true);
stopButton.setEnabled(false);
stepButton.setEnabled(true);
view.displayEverything();
needToRedrawEverything = false;
singleStepping = false;
}
}
/**
* Inner class for handling the SpeedBar control.
*/
class SpeedBarListener implements AdjustmentListener {
/**
* Handles the SpeedBar control. Speed control is nonlinear,
* and the formula used is a hack job that should be replaced.
*
* @param e the Event that invoked this handler (ignored).
*/
public void adjustmentValueChanged(AdjustmentEvent e) {
int scrollBarValue = e.getValue();
setDelays(scrollBarValue);
messageLabel.setText("scrollbar = " + scrollBarValue +
", delay = " + animationDelay);
}
}
}