-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathView.java
More file actions
338 lines (309 loc) · 11.7 KB
/
View.java
File metadata and controls
338 lines (309 loc) · 11.7 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
import java.awt.*;
import java.util.*;
/**
* Displays the progress of the rabbit hunt.
*
* @author David Matuszek
* @version October 20, 2001
*/
public class View {
// instance variables
private Object [][] field;
private int numberOfRows;
private int numberOfColumns;
private Canvas canvas;
private Graphics graphics;
private int width;
private int height;
private int cellWidth;
private int cellHeight;
private final Color BROWN = new Color(0xAA, 0x88, 0);
private final Color GREEN = new Color(0, 0xAA, 0);
private final Color LOOK = new Color(0xDD, 0xDD, 0);
private boolean initialDrawing = false;
private int foxRow;
private int foxColumn;
private int rabbitRow;
private int rabbitColumn;
private boolean displayLookingAround = true;
private int lookDelay;
/**
* Constructs a View for the given field.
*
* @param field the field on the fox hunts the rabbit
*/
View(Object[][] field) {
this.field = field;
numberOfRows = field.length;
numberOfColumns = field[0].length;
}
/**
* Tells this View what canvas it should use for its display.
*
* @param canvas the canvas to use
*/
void setCanvas(Canvas canvas) {
this.canvas = canvas;
this.graphics = canvas.getGraphics();
this.height = canvas.getHeight() - 1;
this.width = canvas.getWidth();
graphics = canvas.getGraphics();
cellHeight = height / numberOfRows;
cellWidth = width / numberOfColumns;
}
void setDisplayLookingAround(boolean displayLookingAround, int lookDelay) {
this.displayLookingAround = displayLookingAround;
this.lookDelay = lookDelay;
}
/**
* Determines the y-coordinate on the canvas that corresponds
* to the top edge of a given row in the field.
*
* @param row the row number in the field
* @return the y-coordinate of the top of that row on the canvas
*/
private int cellTop(int row) {
return (row * height) / numberOfRows;
}
/**
* Determines the x-coordinate on the canvas that corresponds
* to the left edge of a given column in the field.
*
* @param column the column number in the field
* @return the x-coordinate of the left of that column on the canvas
*/
private int cellLeft(int column) {
return (column * width) / numberOfColumns;
}
/**
* Draws a rabbit.
*
* @param i the row number of the rabbit
* @param j the column number of the rabbit
*/
private void drawRabbit(int i, int j) {
fillOval(i, j, BROWN, 5);
}
/**
* Draws a fox.
*
* @param i the row number of the fox
* @param j the column number of the fox
*/
private void drawFox(int i, int j) {
fillOval(i, j, Color.red, 1);
}
/**
* Draws a bush.
*
* @param i the row number of the bush
* @param j the column number of the bush
*/
private void drawBush(int i, int j) {
graphics.setColor(GREEN);
graphics.fillOval(cellLeft(j) + cellWidth / 4,
cellTop(i) + 1, cellWidth / 2, cellHeight - 1);
graphics.fillOval(cellLeft(j) + 1, cellTop(i) + 1 + cellHeight / 4,
cellWidth - 1, cellHeight / 2);
}
/**
* Erases the contents of a "cell" of the field on the screen.
*
* @param i the row number of the cell to be erased
* @param j the column number of the cell to be erased
*/
private void eraseCell(int i, int j) {
graphics.setColor(Color.white);
graphics.fillRect(cellLeft(j) + 1, cellTop(i) + 1,
cellWidth - 1, cellHeight - 1);
}
/**
* Draws the contents of a single cell on the field.
*/
private void drawCell(int row, int column) {
if (field[row][column] == null) {
eraseCell(row, column);
}
else if (field[row][column] instanceof Bush) {
drawBush(row, column);
}
else if (field[row][column] instanceof Fox) {
drawFox(row, column);
}
else if (field[row][column] instanceof Rabbit) {
drawRabbit(row, column);
}
}
/**
* Redraws the entire field display from scratch.
*/
void displayEverything() {
// loop through the field array and draw the things in it
for (int i = 0; i < numberOfRows; i++) {
for (int j = 0; j < numberOfColumns; j++) {
eraseCell(i, j);
Object obj = field[i][j];
if (obj instanceof Rabbit) {
rabbitRow = i;
rabbitColumn = j;
drawRabbit(i, j);
}
else if (obj instanceof Fox) {
foxRow = i;
foxColumn = j;
drawFox(i, j);
}
else if (obj instanceof Bush) {
drawBush(i, j);
}
}
}
// draw vertical lines
graphics.setColor(new Color(0x99, 255, 255));
for (int i = 1; i < numberOfColumns; i++) {
int left = cellLeft(i);
graphics.drawLine(left, 0, left, height);
}
// draw horizontal lines
for (int i = 0; i <= numberOfColumns; i++) {
int top = cellTop(i);
graphics.drawLine(0, top, width, top);
}
}
/**
* Erases the fox and/or rabbit from their old positions on the
* screen and redraws them in their new positions. If the flag
* <code>displayLookingAround</code> is true, will also show
* in which directions the animal has looked.
*/
void displayChanges() {
// find new positions of fox and rabbit
for (int i = 0; i < numberOfRows; i++) {
for (int j = 0; j < numberOfColumns; j++) {
if (field[i][j] instanceof Fox) {
// possibly display fox looking around
if (displayLookingAround && !Model.isRabbitsTurn) {
showLooks(foxRow, foxColumn, i, j);
}
// if fox has moved, update display
if (i != foxRow || j != foxColumn) {
eraseCell(foxRow, foxColumn);
foxRow = i;
foxColumn = j;
drawFox(i, j);
}
}
else if (field[i][j] instanceof Rabbit) {
// possibly display rabbit looking around
if (displayLookingAround && Model.isRabbitsTurn) {
showLooks(rabbitRow, rabbitColumn, i, j);
}
// if rabbit has moved, update display
if (i != rabbitRow || j != rabbitColumn) {
eraseCell(rabbitRow, rabbitColumn);
rabbitRow = i;
rabbitColumn = j;
drawRabbit(i, j);
}
}
} // for j
} // for i
}
/**
* Determines whether field[row][column] is a legal location.
*
* @param row the row to be tested
* @param column the column to be tested
* @return true if the location [row][column] is within field[][]
*/
private boolean legal(int row, int column) {
return row >= 0 && row < numberOfRows &&
column >= 0 && column < numberOfColumns;
}
/**
* Shows what each animal looks at. This a bit complicated because
* the animal has already moved by the time we do this, and we
* want to show the "look" as having been performed before the
* animal moved. Hence, <code>newRow</code> and <code>newColumn</code>
* (which now contain the animal) are treated as empty cells.
*
* @param oldRow The previous row of the animal (before moving)
* @param oldColumn The previous column of the animal (before moving)
* @param newRow The current row of the animal (after moving)
* @param newColumn The current column of the animal (after moving)
*/
void showLooks(int oldRow, int oldColumn, int newRow, int newColumn) {
int direction;
int rowDelta;
int columnDelta;
boolean cellWasEmpty;
Vector looks = Model.looks;
// for each "look," find starting position and direction
for (int i = 0; i < looks.size(); i++) {
direction = ((Integer)looks.elementAt(i)).intValue();
if (direction == Model.STAY) continue;
int lookRow = oldRow;
int lookColumn = oldColumn;
rowDelta = Model.rowChange(direction);
columnDelta = Model.columnChange(direction);
lookRow += rowDelta;
lookColumn += columnDelta;
// draw line of dots showing places looked
while (legal(lookRow, lookColumn)) {
fillOval(lookRow, lookColumn, LOOK, 6);
try { Thread.sleep(10); }
catch (InterruptedException e) {}
// we want to pretend the animal move has not happened yet,
// so new position of animal counts as an unoccupied cell
cellWasEmpty = (field[lookRow][lookColumn] == null) ||
(lookRow == newRow && lookColumn == newColumn);
if (!cellWasEmpty) break;
lookRow += rowDelta;
lookColumn += columnDelta;
}
try { Thread.sleep(lookDelay); }
catch (InterruptedException e) {}
// erase line of dots
lookRow = oldRow + rowDelta;
lookColumn = oldColumn + columnDelta;
while (legal(lookRow, lookColumn)) {
cellWasEmpty = (field[lookRow][lookColumn] == null) ||
(lookRow == newRow && lookColumn == newColumn);
if (lookRow == rabbitRow && lookColumn == rabbitColumn) {
drawRabbit(lookRow, lookColumn);
}
else if (cellWasEmpty) {
eraseCell(lookRow, lookColumn);
}
else {
drawCell(lookRow, lookColumn);
}
lookRow += rowDelta;
lookColumn += columnDelta;
}
}
}
/**
* Draws a filled oval at the position on the screen representing
* the given row and column of the field.
*
* @param row the number of the row in the field to be displayed
* @param column the number of the column in the field to be displayed
* @param color the color to be used for the oval
* @param adjustment the amount by which to shrink the oval
*/
private void fillOval(int row, int column, Color color, int adjustment) {
graphics.setColor(color);
// ensure oval is at least 4 pixels high and 4 pixels wide
int widthAdjustment = adjustment;
int heightAdjustment = adjustment;
if (cellWidth - 2 * adjustment < 4)
widthAdjustment = (cellWidth - 4) / 2;
if (cellHeight - 2 * adjustment < 4)
heightAdjustment = (cellHeight - 4) / 2;
graphics.fillOval(cellLeft(column) + widthAdjustment,
cellTop(row) + heightAdjustment,
cellWidth - 2 * widthAdjustment,
cellHeight - 2 * heightAdjustment);
}
}