Methods
[Agent practical 3 of 9]
Ok, so now we'll shift the behaviour for the agents from Model.java into Agent.java.
Looking at Model class, you should have something like this:
for (int i = 0; i < numberOfIterations; i++) {
for (int j = 0; j < numberOfAgents; j++) {
// Code to move agents[j].x.
// Code to move agents[j].y.
// Code to eat world.data at agents[j].x, agents[j].y.
System.out.println("value at " + x + " " + y + " is " + world.data[y][x]);
}
}
This is ok, but it isn't well structured. One of the key ideas with Object Orientated Programming is that the functionality associated with a class should be inside that class. This makes classes easier to reuse and to swap in and out of code. Given this, we'd really like to put the agent-centred code in Agent, and get this code down to:
for (int i = 0; i < numberOfIterations; i++) {
for (int j = 0; j < numberOfAgents; j++) {
agents[j].run();
System.out.println("value at " + agents[j].x + " " + agents[j].y + " is " + world.data[agents[j].y][agents[j].x]);
}
}
This is also much cleaner, simplifying our Model.java to the core functions we expect of it and keeping the complicated stuff hidden from this class and anyone reading it -- they'll know to look in Agent.java if they need more detail.
In order to implement the above, we need to shift the removed code into a new "run()
" method within Agent.java:
public class Agent {
int x = 50;
int y = 150;
private Environment world = null;
public Agent(Environment worldIn) {
world = worldIn;
}
public void run() {
// Code to move agents[j].x.
// Code to move agents[j].y.
// Code to eat world.data at agents[j].y, agents[j].x.
}
}
Before you do this, however, note a couple of things. Firstly, because we're now inside the Agent class, not
the loops inside Model, agents[j].x
won't work -- neither agents[]
nor j
exist as labels inside Agent.java,
let alone as *these* labels, which are specific to Model.java. In each case, you need to replace the
agent[j]
with "this
". "this
" is a Java keyword refering to the object which
you are inside. It is mainly used when you have a method variable with the same name as an instance variable;
this.x
then refers to the instance variable x
, rather than the method variable
x
, which otherwise takes precedence:
// Don't need this yet - just an example.
int x = 0;
void setX(int x) {
this.x = x;
}
is the same as:
int x = 0;
void setX(int xIn) {
x = xIn;
}
Anyhow, in our code, we currently have agents[j]
referring to the agent, but now we're inside the agent, we need to change it to this
. For example,
int x = agents[j].x;
in Model.java, becomes:
int x = this.x;
in Agent.java. Note that because we've used the same label for the Environment object world
, we don't need to rename that here.
Secondly, note that we've let the instance variables x
and y
as not private for the moment, so they
can still be directly accessed by Model.java.
It may seem a bit confusing to have two x
and y
values in our agent's run()
method
(x
and this.x
). However, they are different variables doing different jobs. The class-level instance variable this.x
is keeping track of where we are now, and the method-level variable
x
is holding where we are considering going. We could rename the latter, so either of the following bits
of code would be fine:
int x = 0;
do {
x = this.x;
double randomNumber = Math.random();
if (randomNumber < 0.33) x--;
if (randomNumber > 0.66) x++;
} while ((x < 0) || (x > world.getWidth() - 1));
this.x = x;
int nextX = 0;
do {
nextX = this.x;
double randomNumber = Math.random();
if (randomNumber < 0.33) nextX--;
if (randomNumber > 0.66) nextX++;
} while ((nextX < 0) || (nextX > world.getWidth() - 1));
this.x = nextX;
or, indeed, as we no longer have a local "x", we could just do the following, though it seems to reverse everything we've done before, rather confusingly!
int nextX = 0;
do {
nextX = x;
double randomNumber = Math.random();
if (randomNumber < 0.33) nextX--;
if (randomNumber > 0.66) nextX++;
} while ((nextX < 0) || (nextX > world.getWidth() - 1));
x = nextX;
With these caveats in mind, have a go at implementing the above run()
method, and getting Model.java to use it.
Once you've got that working, we'll finish off by tidying up the code.