/*
Copyright 2006 by Sean Luke and George Mason University
Licensed under the Academic Free License version 3.0
See the file "LICENSE" for more information
*/
package sim.app.hexabugs;
import sim.engine.*;
import sim.util.*;
import sim.field.grid.*;
public /*strictfp*/ class HexaBugs extends SimState
{
private static final long serialVersionUID = 1;
public double minIdealTemp = 17000;
public double maxIdealTemp = 31000;
public double minOutputHeat = 6000;
public double maxOutputHeat = 10000;
public double evaporationRate = 0.993;
public double diffusionRate = 1.0;
public static final double MAX_HEAT = 32000;
public double randomMovementProbability = 0.1;
public int gridHeight = 100;
public int gridWidth = 100;
public int bugCount = 100;
HexaBug[] bugs;
public double getMinimumIdealTemperature() { return minIdealTemp; }
public void setMinimumIdealTemperature( double temp ) { if( temp <= maxIdealTemp ) minIdealTemp = temp; }
public double getMaximumIdealTemperature() { return maxIdealTemp; }
public void setMaximumIdealTemperature( double temp ) { if( temp >= minIdealTemp ) maxIdealTemp = temp; }
public double getMinimumOutputHeat() { return minOutputHeat; }
public void setMinimumOutputHeat( double temp ) { if( temp <= maxOutputHeat ) minOutputHeat = temp; }
public double getMaximumOutputHeat() { return maxOutputHeat; }
public void setMaximumOutputHeat( double temp ) { if( temp >= minOutputHeat ) maxOutputHeat = temp; }
public Object domEvaporationConstant() { return new Interval(0.0,1.0); }
public double getEvaporationConstant() { return evaporationRate; }
public void setEvaporationConstant( double temp ) { if( temp >= 0 && temp <= 1 ) evaporationRate = temp; }
public Object domDiffusionConstant() { return new Interval(0.0,1.0); }
public double getDiffusionConstant() { return diffusionRate; }
public void setDiffusionConstant( double temp ) { if( temp >= 0 && temp <= 1 ) diffusionRate = temp; }
public Object domRandomMovementProbability() { return new Interval(0.0,1.0); }
public double getRandomMovementProbability() { return randomMovementProbability; }
public void setRandomMovementProbability( double t )
{
if (t >= 0 && t <= 1)
{
randomMovementProbability = t;
for( int i = 0 ; i < bugCount ; i++ )
if (bugs[i]!=null)
bugs[i].setRandomMovementProbability( randomMovementProbability );
}
}
public double getMaximumHeat() { return MAX_HEAT; }
public int getGridHeight() { return gridHeight; }
public int getGridWidth() { return gridWidth; }
public int getBugCount() { return bugCount; }
public void setBugCount(int val) { if (val >= 0) bugCount = val; }
public DoubleGrid2D valgrid = new DoubleGrid2D(gridWidth, gridHeight,0);
public DoubleGrid2D valgrid2 = new DoubleGrid2D(gridWidth, gridHeight, 0);
public SparseGrid2D buggrid = new SparseGrid2D(gridWidth, gridHeight);
// some variables shared by all hexa bugs in the application
DoubleBag neighVal = new DoubleBag();
IntBag neighX = new IntBag();
IntBag neighY = new IntBag();
/** Creates a HexaBugs simulation with the given random number seed. */
public HexaBugs(long seed)
{
// we build a schedule that has two orders per step: for the bugs, then the Hexa decreaser
super(seed);
bugs = new HexaBug[bugCount];
}
ThreadedHexaDiffuser diffuser = null;
/** Resets and starts a simulation */
public void start()
{
super.start(); // clear out the schedule
// make new grids
valgrid = new DoubleGrid2D(gridWidth, gridHeight,0);
valgrid2 = new DoubleGrid2D(gridWidth, gridHeight, 0);
buggrid = new SparseGrid2D(gridWidth, gridHeight); // we're doing toroidal, so specify dimensions
bugs = new HexaBug[bugCount];
// Schedule the Hexa bugs -- we could instead use a RandomSequence, which would be faster
// But we spend no more than 3% of our total runtime in the scheduler max, so it's not worthwhile
for(int x=0;x<bugCount;x++)
{
bugs[x] = new HexaBug(random.nextDouble() * (maxIdealTemp - minIdealTemp) + minIdealTemp,
random.nextDouble() * (maxOutputHeat - minOutputHeat) + minOutputHeat,
MAX_HEAT, randomMovementProbability);
buggrid.setObjectLocation(bugs[x],random.nextInt(gridWidth),random.nextInt(gridHeight));
schedule.scheduleRepeating(bugs[x]);
}
// Schedule the decreaser to happen after the HexaBugs
if (availableProcessors() > 1) // yay, multi-processor!
{
// store away the ThreadedHexaDiffuser so we can call cleanup() on it later in our stop() method.
diffuser = new ThreadedHexaDiffuser(valgrid,valgrid2,evaporationRate,diffusionRate);
schedule.scheduleRepeating(Schedule.EPOCH,1,diffuser,1);
}
else
schedule.scheduleRepeating(Schedule.EPOCH,1,new HexaDiffuser(valgrid,valgrid2,evaporationRate,diffusionRate),1);
}
public void stop()
{
if (diffuser != null) diffuser.cleanup();
diffuser = null;
}
public int availableProcessors()
{
Runtime runtime = Runtime.getRuntime();
try { return ((Integer)runtime.getClass().getMethod("availableProcessors", (Class[])null).
invoke(runtime,(Object[])null)).intValue(); }
catch (Exception e) { return 1; } // a safe but sometimes wrong assumption!
}
public static void main(String[] args)
{
doLoop(HexaBugs.class, args);
System.exit(0);
}
}