/**
** Pedestrian.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.sillypeds;
import java.util.ArrayList;
import sim.engine.SimState;
import sim.engine.Steppable;
import sim.engine.Stoppable;
import sim.util.Bag;
/**
* A Steppable object that updates its position on the landscape as a function
* of its local cost surface.
*/
public class Pedestrian implements Steppable
{
SillyPeds world; // the simulation of which the Pedestrian is a part
Tile tile; // the Basin in which the Pedestrian currently resides
Space space;
Stoppable stopper; // a variable used to unschedule the Pedestrian
private static final long serialVersionUID = 1L;
/**
* Constructor function.
* @param ww - the WaterWorld object, kept so the Pedestrian can update the
* simulation if it exits the simulation
* @param s - the ObjectGrid2D landscape object, kept so the Pedestrian can
* determine its local cost surface
* @param t - the Basin in which the Pedestrian finds itself
*/
public Pedestrian(SillyPeds ww, Space s, Tile t)
{
world = ww;
space = s;
tile = t;
stopper = null;
}
/**
* Steppable that moves the Pedestrian across the landscape.
*/
@Override
public void step(SimState state)
{
// if on an exit, move to the next space
if (tile.exit)
{
Entrance e = space.exit(tile);
if (e == null)
{
// exiting the simulation
tile.removePed(this);
world.peds.remove(this);
return;
} else if (e.entrance.peds.size() > 0)
{
// exit blocked by another person, can't move through it. Stay in place,
// but make sure to reschedule self to run again!
state.schedule.scheduleOnce(this, (int) (1 + tile.baseheight));
return;
}
// leave old space, enter new space
tile.removePed(this);
space = e.space;
tile = e.entrance;
tile.addPed(this);
} else
{
// get a copy of all of the neighbors of this tile
Bag neighbors = new Bag();
space.field.getNeighborsMaxDistance(
tile.loc_x, tile.loc_y, 1, false, neighbors, null, null);
// find the set of neighbors that is of minimal height
ArrayList<Tile> mins = new ArrayList<Tile>();
double currentheight = tile.baseheight;
for (Object o : neighbors)
{
Tile b = (Tile) o;
if (b.peds.size() > 0)
{
continue; // the tile is occupied, can't move there
} else if (b.baseheight <= currentheight)
{
mins.add(b); // add our new find to it
}
}
if (mins.size() > 0)
{ // somewhere is both free and desirable
// select randomly from the eligible neighbors
Tile newbasin = mins.get(state.random.nextInt(mins.size()));
// move to this new spot
tile.removePed(this);
newbasin.addPed(this);
tile = newbasin;
}
}
// schedule self to update next turn!
// order of update is proportional to distance from exit, e.g. gradient of the tile
state.schedule.scheduleOnce(this, (int) (1 + tile.baseheight));
}
}