/* 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.flockers; import sim.engine.*; import sim.util.*; import sim.field.continuous.*; public class Flockers extends SimState { private static final long serialVersionUID = 1; public Continuous2D flockers; public double width = 150; public double height = 150; public int numFlockers = 200; public double cohesion = 1.0; public double avoidance = 1.0; public double randomness = 1.0; public double consistency = 1.0; public double momentum = 1.0; public double deadFlockerProbability = 0.1; public double neighborhood = 10; public double jump = 0.7; // how far do we move in a timestep? public double getCohesion() { return cohesion; } public void setCohesion(double val) { if (val >= 0.0) cohesion = val; } public double getAvoidance() { return avoidance; } public void setAvoidance(double val) { if (val >= 0.0) avoidance = val; } public double getRandomness() { return randomness; } public void setRandomness(double val) { if (val >= 0.0) randomness = val; } public double getConsistency() { return consistency; } public void setConsistency(double val) { if (val >= 0.0) consistency = val; } public double getMomentum() { return momentum; } public void setMomentum(double val) { if (val >= 0.0) momentum = val; } public int getNumFlockers() { return numFlockers; } public void setNumFlockers(int val) { if (val >= 1) numFlockers = val; } public double getWidth() { return width; } public void setWidth(double val) { if (val > 0) width = val; } public double getHeight() { return height; } public void setHeight(double val) { if (val > 0) height = val; } public double getNeighborhood() { return neighborhood; } public void setNeighborhood(double val) { if (val > 0) neighborhood = val; } public double getDeadFlockerProbability() { return deadFlockerProbability; } public void setDeadFlockerProbability(double val) { if (val >= 0.0 && val <= 1.0) deadFlockerProbability = val; } public Double2D[] getLocations() { if (flockers == null) return new Double2D[0]; Bag b = flockers.getAllObjects(); if (b==null) return new Double2D[0]; Double2D[] locs = new Double2D[b.numObjs]; for(int i =0; i < b.numObjs; i++) locs[i] = flockers.getObjectLocation(b.objs[i]); return locs; } public Double2D[] getInvertedLocations() { if (flockers == null) return new Double2D[0]; Bag b = flockers.getAllObjects(); if (b==null) return new Double2D[0]; Double2D[] locs = new Double2D[b.numObjs]; for(int i =0; i < b.numObjs; i++) { locs[i] = flockers.getObjectLocation(b.objs[i]); locs[i] = new Double2D(locs[i].y, locs[i].x); } return locs; } /** Creates a Flockers simulation with the given random number seed. */ public Flockers(long seed) { super(seed); } public void start() { super.start(); // set up the flockers field. It looks like a discretization // of about neighborhood / 1.5 is close to optimal for us. Hmph, // that's 16 hash lookups! I would have guessed that // neighborhood * 2 (which is about 4 lookups on average) // would be optimal. Go figure. flockers = new Continuous2D(neighborhood/1.5,width,height); // make a bunch of flockers and schedule 'em. A few will be dead for(int x=0;x<numFlockers;x++) { Double2D location = new Double2D(random.nextDouble()*width, random.nextDouble() * height); Flocker flocker = new Flocker(location); if (random.nextBoolean(deadFlockerProbability)) flocker.dead = true; flockers.setObjectLocation(flocker, location); flocker.flockers = flockers; flocker.theFlock = this; schedule.scheduleRepeating(flocker); } } public static void main(String[] args) { doLoop(Flockers.class, args); System.exit(0); } }