/**
** Raindrop.java
**
** Copyright 2011 by Sarah Wise, Mark Coletti, Andrew Crooks, and
** George Mason University.
**
** Licensed under the Academic Free License version 3.0
**
** See the file "LICENSE" for more information
**
** $Id$
**/
package sim.app.geo.waterworld;
import java.util.ArrayList;
import sim.engine.SimState;
import sim.engine.Steppable;
import sim.engine.Stoppable;
import sim.field.grid.ObjectGrid2D;
import sim.util.Bag;
/**
* A Steppable object that updates its position on the landscape as a function
* of its local cost surface.
*/
public class Raindrop implements Steppable
{
WaterWorld world; // the simulation of which the Raindrop is a part
Basin basin; // the Basin in which the Raindrop currently resides
ObjectGrid2D landscape; // the landscape of elevations and water
Stoppable stopper; // a variable used to unschedule the Raindrop
private static final long serialVersionUID = 1L;
/**
* Constructor function.
* @param ww - the WaterWorld object, kept so the Raindrop can update the
* simulation if it exits the simulation
* @param l - the ObjectGrid2D landscape object, kept so the Raindrop can
* determine its local cost surface
* @param b - the Basin in which the Raindrop finds itself
*/
public Raindrop(WaterWorld ww, ObjectGrid2D l, Basin b)
{
world = ww;
landscape = l;
basin = b;
stopper = null;
}
/**
* Steppable that moves the Raindrop across the landscape.
*/
@Override
public void step(SimState state)
{
// get a copy of all of the neighbors of this tile
Bag neighbors = new Bag();
landscape.getNeighborsMaxDistance(
basin.loc_x, basin.loc_y, 1, true, neighbors, null, null);
// find the set of neighbors that is of minimal height
ArrayList<Basin> mins = new ArrayList<Basin>();
double minheight = Double.MAX_VALUE;
for (Object o : neighbors)
{
Basin b = (Basin) o;
if (b.cumulativeHeight < minheight)
{
mins = new ArrayList<Basin>(); // set up a new list of minimal neighbors
mins.add(b); // add our new find to it
minheight = b.cumulativeHeight;
} else if (b.cumulativeHeight == minheight)
{
mins.add(b);
}
}
// if we haven't found anything better than where we currently are, stay where we are!
if (minheight >= basin.cumulativeHeight)
{
// if we're on the edge, fall off the edge
if (basin.loc_x == 0 || basin.loc_y == 0
|| basin.loc_x == landscape.getWidth() - 1 || basin.loc_y == landscape.getHeight() - 1)
{
stopper.stop();
basin.removeDrop(this);
world.drops.remove(this);
}
// otherwise just hang out in this same basin!
return;
}
// select randomly from the eligible neighbors
Basin newbasin = mins.get(state.random.nextInt(mins.size()));
// move to this new spot
basin.removeDrop(this);
newbasin.addDrop(this);
basin = newbasin;
}
}