SlowFish
The second type of fish that the biologists were interested in adding to their simulation moved very slowly or infrequently, so we dubbed it "SlowFish." A slow fish moves so slowly that it only has a 1 in 5 chance of moving out of its current cell into an adjacent cell in any given timestep in the simulation. When it does move, though, it moves like a normal fish; it is equally likely to move forward or to either side, and virtually never turns completely around to swim backwards.
Design Issues
To test whether the fish should move, I knew I would randomly pick a number
and compare it to the probability of moving. The first design decision I
had to make, though, was whether to put that test in the move
method or in the nextLocation
method. If I put it in the
move
method, then 4 out of 5 times it would do nothing. If I
put it in the nextLocation
method, then 4 out of 5 times it
would return the current location. Since it seemed like the test could go
in either place, I decided to put it in the lower-level, more specific
method, nextLocation
.
Having just decided to redefine the nextLocation
method, I realized that
when the slow fish do move, they choose their next location just as any
other fish would. I was thinking that I would have to duplicate that code
from Fish
in my redefined method in SlowFish
(since a redefined method overrides the original from the superclass), when
I remembered that it is possible to call the superclass method from within
the subclass method. I just needed to call
super.nextLocation()
within my nextLocation
method in SlowFish
. This gave me my updated pseudo-code.
SlowFish Next Location method: Get random number If random number represents 1 in 5 chance of moving Get next location as any normal fish would (super.nextLocation()) Otherwise, Return the current location.
My final design decision was how to determine whether a given slow fish
should move.
In mathematics, probabilities are represented as real numbers from 0.0 to
1.0, where 0.0 means there is no probability that something will happen and
1.0 means that it will always happen. The probability corresponding to a 1
in 5 chance is the mathematical value 1/5 (or 0.2). Therefore, the test for
whether the fish should move or not could be implemented by randomly
picking a real number (a double) in the range of 0.0 to 1.0 (using the
nextDouble()
method from the java.util.Random
or
edu.kzoo.util.RandNumGenerator
classes). I could then compare
the random double to the mathematical value 1/5. There is a 1 in 5 chance
that the randomly chosen value would be less than 1/5. (Similarly, there
would be a 3 in 5 chance that the randomly chosen value would be less
than 3/5, or 0.6.)
As I thought about it, I realized I could also represent the probability
using integers. I could get a random integer using nextInt(5)
and compare the random number to 0 (or any other number between 0 and 4).
There would be a 1 in 5 chance of the random number being whichever integer
I chose. (Or a 3 in 5 chance of it being less than 3, if that were what I
needed.)
Programming Exercise: SlowFish
- Create a subclass of the
Fish
calledSlowFish
.NOTE: You may want to make all slow fish a particular color, or display them using a different fish display class, to make them easier to spot when testing.Test your program so far, using the fileslowAndNormalFish.dat
. Do you expect the slow fish to behave any differently from objects of theFish
superclass yet? Do they behave differently?- Copy the signature and javadoc comments for the
nextLocation
method from theFish
class into theSlowFish
class, without copying the internals of the method. Implement the method using the pseudo-code above and one of the two methods described for determining probabilities.- How should you test your program to determine whether slow fish are moving correctly, and with the appropriate probability?
Testing Random Behavior
Programs with random behavior can be difficult to test. Every time you run the program, you get different results, which makes it difficult to come up with expected results for comparing against actual results. If the program includes probabilistic behavior, like slow fish movement, it is difficult to verify that the probabilities of different behaviors are correct. Just because a slow fish has a 1 in 5 chance of moving doesn't mean that they move exactly 20% of the time.
One technique I tried was to run the program for many steps with a small number of fish, so I could better keep track of the behavior for each one. Each step yielded different results, but the accumulation of results demonstrated that the slow fish were moving approximately as often as expected.
Another technique I tried was to put many slow fish in the grid, and keep track of all of their movements for a smaller number of steps. In this case, approximately 20% of the fish moved in any given time step, which was again what I expected.
Later in the summer I learned to seed the random number generator.
This causes the generator to create the same sequence of pseudo-random
numbers every time the program is run, leading to predictable results. For
example, the fish.dat
configuration file specifies the initial
location and direction of each fish, but not its color. Once I learned to
seed the random number generator, then the initial colors of the fish and
their behavior in each timestep were consistent every time I ran the
simulation. The benefit of this was that after recording the behavior of
one run of the simulation, I could use that as a prediction of expected
results for future tests, unless I made code changes that changed the
behavior.
Programming Exercise: Testing SlowFish
- Test your
SlowFish
program using either enough timesteps or enough fish to test that slow fish have the correct probability of moving.