Using packages
[Agent practical 5 of 9]
We'll now expand what we've done to utilise a neighbourhood.
To do this, we'll utilise a nice little class distributed with Java, java.awt.Polygon
(API docs). This class
represents a closed polygon defined in a coordinate space, and has a useful little method called contains()
which takes in
an x,y coordinate and tells you if it is inside the polygon or not. To use it, all we have to do is
construct a java.awt.Polygon object around our proposed point and then query each agent for their x
and y
coordinates to see if they
fall in the Polygon. We'll then have identified if they fall within a neighbourhood around our prospective new location.
The constructor for java.awt.Polygon
takes in an array of x-coordinates, and array of y-coordinates, and a number of coordinates to use. The polygon is automatically closed between
the first and last point. You need to think through in detail what kind of shape you want to use for your neighbourhood, depending on
its size and the datasets it is being compared against. Here, we're going to use a hexagonal neighbourhood, just because its better than a
square. With a bit more effort, you could construct something more like a circle, but this isn't necessary here.
To be honest, thinking through the maths is a bit of a faff, so we're going to give you the code. You can find it in this copy of the Animal class:
- Animal.java (as it includes a generic spatial behaviour, we also add a new method to Agent.java).
Check this is compatible with your code, and then either download it to your directory for this practical, or cut and paste the new code into your Animal class.
Note a few things about this. Firstly, there are three new instance variables, set to private to this class only:
private int neighbourhoodRadius = 5;
private int opp = (int)Math.abs((Math.sin(Math.toRadians(30.0)) * (double)neighbourhoodRadius));
private int adj = (int)Math.abs((Math.cos(Math.toRadians(30.0)) * (double)neighbourhoodRadius));
These utilise the static trigonometry methods built into the Math
class to calculate some key lengths for building of
hexagon. Note also that these take radians, rather than degrees.
Secondly, note that the class imports java.awt.*
so we can get hold of the Polygon class.
Finally, note that getNeighbourhood
is polymorphic. There's a version that generates the neighbourhood around the
current agent location, and another that takes in specific coordinates. Note that the former simply pass the current x
and y
to
the latter. This isn't an uncommon way of doing polymorphism -- there's no point in doubling-up code unnecessarily. We won't use the
version for the current neighbourhood at the moment, but it is there if we need it later.
So, how do we use our new method, which is inherited into Nibbler? Well, here's our take on the locationSuitable
method, but feel free to
adapt to match your own:
private boolean locationSuitable(int x, int y) {
for (Agent agent: agents) {
if ((getNeighbourhood(x,y).contains(agent.getX(), agent.getY()) == true) && (agent != this)) {
return false;
}
}
return true;
}
Get this, or its equivalent, working, and we're done for this practical.
Go on to the last page for a summary of where we're at.