-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathHound.java
More file actions
327 lines (284 loc) · 10.9 KB
/
Hound.java
File metadata and controls
327 lines (284 loc) · 10.9 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
import java.awt.Color;
import java.util.Random;
import java.util.Vector;
import java.util.concurrent.Phaser;
import java.util.concurrent.PriorityBlockingQueue;
/**
* Hounds can display themselves. They also get hungry.
*/
public class Hound extends FieldOccupant
{
/**
* Creates a new Hound.
*
* @param row
* the row the Hound is located at.
* @param col
* the col the Hound is located at.
* @param theField
* the Field the Hound is on.
* @param startPhaser
* the start phaser to wait on.
*/
public Hound(int row, int col, Field theField, Phaser startPhaser)
{
super(row, col, theField, startPhaser);
// Start out well-fed
eats();
}
/**
* Returns true if this Hound has starved to death.
*
* @return true if this Hound has starved to death.
*/
public boolean hasStarved()
{
return p_fedStatus <= 0;
}
/**
* Make this Hound hungrier by the amount we lived this round. Returns true
* if the Hound has starved.
*
* @return true if this Hound has starved to death.
*/
public boolean getHungrier(int timeLived)
{
// Decrease the fed status of this Hound
p_fedStatus -= timeLived;
return hasStarved();
}
/**
* Feeds a Hound (i.e. resets hunger to start value).
*/
public void eats()
{
// Reset the fed status of this Hound
p_fedStatus = p_houndStarveTime;
}
/**
* Returns the color to use for a Cell occupied by a Hound.
*
* @return the color to use for a Cell occupied by a Hound
*/
@Override
public Color getDisplayColor()
{
float defaultHue = 0.0f;
float defaultBrightness = 1.0f;
return Color.getHSBColor(defaultHue,
((float) p_fedStatus / p_houndStarveTime),
defaultBrightness);
} // getDisplayColor
/**
* Returns the String representing a Hound.
*
* @return the String representing a Hound.
*/
@Override
public String toString()
{
return "H";
}
/**
* Sets the starve time for this class.
*
* @param starveTime
* the starve time for a Hound.
*/
public static void setStarveTime(int starveTime)
{
p_houndStarveTime = starveTime;
}
/**
* Returns the starve time for Hounds.
*
* @return the starve time for Hounds.
*/
public static long getStarveTime()
{
return p_houndStarveTime;
}
/**
* Allows a Hound to eat Foxes, reproduce, and eventually die if it can't eat
* frequently enough.
*/
@Override
public void run()
{
Random r = new Random();
PriorityBlockingQueue<Cell<FieldOccupant>> toLock = new PriorityBlockingQueue<>();
Field theField = getTheField();
Vector<Fox> foxes = new Vector<>();
Vector<Hound> hounds = new Vector<>();
Fox toEat = null;
Hound toMate = null;
Cell<FieldOccupant> first, second, third;
int sleepTime;
// If we haven't started, join and wait for the start signal...
getStartPhaser().awaitAdvance(getStartPhaser().getPhase());
// While we haven't starved, we can keep on doing things.
do
{
// Get the next sleep time for this Hound.
sleepTime = r.nextInt(DEFAULT_SLEEP_VARIABLE) + DEFAULT_SLEEP;
// Wait for the random amount of time.
try
{
Thread.sleep(sleepTime);
}
catch (InterruptedException e)
{
// ignore, we can't be interrupted because we are a Hound.
}
// Now do Hound things...
// Iterate over the neighbors and see how many Foxes are nearby.
for (Cell<FieldOccupant> neighbor : theField
.getNeighborsOf(getRow(), getCol()))
{
if (neighbor.getOccupant() instanceof Fox)
{
foxes.addElement((Fox) neighbor.getOccupant());
}
} // for
// Attempt to eat the Fox and then reproduce.
if (foxes.size() > 0)
{
// Get a random Fox to eat.
toEat = foxes.get(r.nextInt(foxes.size()));
// Iterate over the neighbors and see how many Foxes and
// Hounds are nearby
for (Cell<FieldOccupant> neighbor : theField
.getNeighborsOf(toEat.getRow(), toEat.getCol()))
{
// Get all other Hounds around this Fox that are not ourself.
if (neighbor.getOccupant() instanceof Hound
&& this != neighbor.getOccupant())
{
hounds.addElement((Hound) neighbor.getOccupant());
}
} // for
// If the Fox we want to eat has neighboring Hounds, try to
// reproduce with that Hound into the Fox's Cell.
if (hounds.size() > 0)
{
// Then get a random Hound to mate with.
toMate = hounds.get(r.nextInt(hounds.size()));
// Add both of the Cells we intend to use if we get the chance to
// our priority queue so we can lock Cells in the correct order
// as to avoid deadlock.
toLock.add(
theField.getCellAt(toEat.getRow(), toEat.getCol()));
toLock.add(theField.getCellAt(toMate.getRow(),
toMate.getCol()));
// For clarity of reading, we'll lock the second and third Cells
// (after locking ourself first).
second = toLock.poll();
third = toLock.poll();
// Lock the first Cell, always our Cell to avoid race conditions.
synchronized (this)
{
// Lock the second Cell.
synchronized (second)
{
// Lock the third Cell.
synchronized (third)
{
// If the location is still occupied, and the
// occupant is a Fox, we'll eat that Fox.
if (theField.isOccupied(toEat.getRow(),
toEat.getCol())
&& theField
.getCellAt(toEat.getRow(),
toEat.getCol())
.getOccupant() instanceof Fox)
{
// Set the Fox's Cell to be null so it will exit
// before trying to do anything.
theField.getCellAt(toEat.getRow(),
toEat.getCol()).getOccupant()
.interrupt();
theField.setCellAt(toEat.getRow(),
toEat.getCol(), null);
// Feed ourself from the Fox we just ate.
eats();
// If the Neighboring Hound still exists, then
// birth a new Hound where the Fox was.
// Else we missed the Fox, so we just get hungrier.
if (theField.isOccupied(toMate.getRow(),
toMate.getCol())
&& theField
.getCellAt(toMate.getRow(),
toMate.getCol())
.getOccupant() instanceof Hound)
{
// Set the Cell that we are going to eat with a
// new Hound and start the thread.
theField.setCellAt(toEat.getRow(),
toEat.getCol(),
new Hound(toEat.getRow(),
toEat.getCol(), theField,
getStartPhaser()))
.start();
}
} // Eat Fox
} // Release lock on third Cell
} // Release lock on second Cell
} // Release lock on first Cell
} // If we can reproduce
// Else, we will just try to go eat a Fox.
else
{
// Get a random Fox to eat.
toEat = foxes.get(r.nextInt(foxes.size()));
// Prioritize our Cells.
toLock.add(theField.getCellAt(getRow(), getCol()));
toLock.add(
theField.getCellAt(toEat.getRow(), toEat.getCol()));
// Get the next two Cells to lock.
first = toLock.poll();
second = toLock.poll();
// Lock the first Cell.
synchronized (first)
{
// Lock the second Cell.
synchronized (second)
{
// If the location is still occupied, and the occupant
// is a Fox, we'll eat that Fox.
// Else we missed the Fox, so get hungrier.
if (theField.isOccupied(toEat.getRow(), toEat.getCol())
&& theField
.getCellAt(toEat.getRow(),
toEat.getCol())
.getOccupant() instanceof Fox)
{
// Set the Fox's Cell to be null so it will exit before
// trying to do anything.
theField.getCellAt(toEat.getRow(), toEat.getCol())
.getOccupant().interrupt();
theField.setCellAt(toEat.getRow(), toEat.getCol(),
null);
// Feed ourself from the Fox we just ate.
eats();
}
} // Release lock on second Cell
} // Release lock on first Cell
} // Just eat a Fox
// Else If none of its neighbors is a Fox, it starves more
} // Eat Fox, spawn Hound or just Eat a Fox
// Reset our lists of Foxes and Hounds nearby.
foxes.clear();
hounds.clear();
}
while (!getHungrier(sleepTime));
// Before exiting, remove ourselves from the Field.
getTheField().setCellAt(getRow(), getCol(), null);
} // run
// Default starve time for Hounds
public static final int DEFAULT_STARVE_TIME = DEFAULT_SLEEP
+ DEFAULT_SLEEP + DEFAULT_SLEEP;
// Class variable for all hounds
private static int p_houndStarveTime = DEFAULT_STARVE_TIME;
// Instance attributes to keep track of how hungry we are
private int p_fedStatus;
}