Inheritance
[Agent practical 4 of 9]


So, finally, we get to this practical's coding. What we're going to do is make our Nibblers more aggresive and build a stopping criteria checking method.


First up, making the Nibblers more aggresive.

Well, aggresive for Nibblers. What we need is for our Nibblers to only move on after they've exhaused all the Environment data in the gridcell they're in. Can you adapt this bit of the Nibbler code, so that they only move if they've eaten everything down to zero at their current x and y?

public void run () {

   move();
   interactWithEnvironment();

}


Next, our stopping criteria method.

This will be built in our Model class, and will be used in our Model class, like this:

for (int i = 0; i < numberOfIterations; i++) {
   for (int j = 0; j < numberOfAgents; j++) {
      agents[j].run();
   }
   if (stoppingCriteriaMet() == true) break;
}

Note that because the method is in the same class as it will be used in, we don't need to use the dot operator to look inside anything to use the method. We could do this:

if (this.stoppingCriteriaMet() == true) break;

but it is the same as:

if (stoppingCriteriaMet() == true) break;

Note also that these two lines do the same job:

if (stoppingCriteriaMet() == true) break;
if (stoppingCriteriaMet()) break;

Give it a go adding the above code and writing the stoppingCriteriaMet() method in Model. The method should return a boolean primitive, with the value true when the stopping criteria are met, and false otherwise. In actual fact, there's only going to be one criterion in our method, and that's going to be whether there are any values above zero left in our whole world.data array. When all the values are zero, the method can return true, but if there are currently any over zero, the method should return false. Happy to give it a go? Of *course* you are.

One tip: you don't need to always put the return statements at the end of a method. As long as every path through the code has an approriate return statement, it doesn't matter where they are, so this kind of thing is fine:

public boolean blahMethod() {
   blah;
   blah;
   if (blah == blah) {
      return false;
   }
   blah;
   blah;
   blah;
   return true;
}

but this isn't, because there's no second return statement to catch the flow that isn't returned by the first one:

public boolean blahMethod() {
   blah;
   blah;
   if (blah == blah) {
      return false;
   }
   blah;
   blah;
   blah;
}

Ok, once you've got that working, give it a go. Push up the number of agents to 10 and the iterations to 1000000, but drop the the world size to 4 by 6 -- this should give a relatively rapid resolution.


Once you think you've got it working, you're done for this practical.

This practical, we've not only looked at how to structure a system for flexibility and future-proofing, but we've also tried out a few bits of coding, including:

Our model is also sufficiently mature that we can start adapting its behaviour, and we've also added a stopping criterion.


PS: If you want to time how long your model takes to run to the end, this code will print the number of milliseconds since midnight at the start of 1st Jan 1970 -- which is widely regarded by computers as the birthday of clocks. It will come back as the primitive type long, which is a larger int:

System.currentTimeMillis()

So you can do this kind of thing:

long startTime = System.currentTimeMillis();
// Do some stuff.
System.out.println("Time taken = " + (((double)((System.currentTimeMillis() - startTime))) / 1000.0) + " seconds");