sim.app.antsforage.Ant Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of mason Show documentation
Show all versions of mason Show documentation
MASON is a fast discrete-event multiagent simulation library core in Java, designed to be the foundation for large custom-purpose Java simulations, and also to provide more than enough functionality for many lightweight simulation needs. MASON contains both a model library and an optional suite of visualization tools in 2D and 3D.
The newest version!
/*
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.antsforage;
import sim.field.grid.*;
import sim.portrayal.*;
import sim.portrayal.simple.*;
import sim.util.*;
import sim.engine.*;
import java.awt.*;
public /*strictfp*/ class Ant extends OvalPortrayal2D implements Steppable
{
public static final int ADD_PHEROMONE = 0;
public static final int MAX_PHEROMONE = 1;
public static final int LOCAL_PHEROMONE = 2;
public static final int PHEROMONE_TYPE = LOCAL_PHEROMONE;
public static final boolean TOROIDAL_WORLD = false;
// type of Ant
public static final int ORIENTED_ANT = 0;
public static final int NSEW_ANT = 1;
public static final int EIGHT_NEIGHBOURS_ANT = 2;
public static final int ANT_TYPE = ORIENTED_ANT;
public static final boolean GREEDY_REPOSITIONING = true;
public static final boolean GREEDY_EXPLORATION = true;
public static final int N = 0;
public static final int NE = 1;
public static final int E = 2;
public static final int SE = 3;
public static final int S = 4;
public static final int SW = 5;
public static final int W = 6;
public static final int NW = 7;
public double pheromoneToLeaveBehind;
public double minPheromone;
public double maxPheromone;
public int timeToLive;
double subtractingRatio;
double pheromoneRatio;
int orientation;
public boolean getHasFoodItem() { return hasFoodItem; }
public void setHasFoodItem(boolean val) { hasFoodItem = val; }
public boolean hasFoodItem;
public static final double ANT_K = 0.001;
public static final double ANT_N = 10.0;
boolean justCreated;
public Ant( int orientation,
double pheromoneToLeaveBehind,
double minPheromone,
double maxPheromone,
int timeToLive )
{
this.orientation = orientation;
this.pheromoneToLeaveBehind = pheromoneToLeaveBehind;
this.minPheromone = minPheromone;
this.maxPheromone = maxPheromone;
this.timeToLive = timeToLive;
subtractingRatio = ( 1.0 / timeToLive ) * maxPheromone;
pheromoneRatio = 1.0 * maxPheromone;
hasFoodItem = false;
justCreated = true;
}
protected void addInformation( final SimState state, int x, int y, final int orientation )
{
final AntsForage af = (AntsForage)state;
final DecisionInfo di = af.decisionInfo;
final DecisionMaker decisionMaker = af.decisionMaker;
if( TOROIDAL_WORLD )
{
x = (x+AntsForage.GRID_WIDTH)%AntsForage.GRID_WIDTH;
y = (y+AntsForage.GRID_HEIGHT)%AntsForage.GRID_HEIGHT;
}
else
{
if( x < 0 || x >= AntsForage.GRID_WIDTH || y < 0 || y >= AntsForage.GRID_HEIGHT )
return;
}
if( ( af.buggrid.getObjectsAtLocation(x,y) == null ||
af.buggrid.getObjectsAtLocation(x,y).numObjs < AntsForage.MAX_ANTS_PER_LOCATION ) &&
af.obstacles.field[x][y] <= 0.5 )
{
// toroidal coordinates!
di.position.x = x;
di.position.y = y;
di.orientation = orientation;
// di.homePheromoneAmount = /*Strict*/Math.pow( ANT_K + ((AntsForage)state).toHomeGrid.field[di.position.x][di.position.y], ANT_N) ;
// di.foodPheromoneAmount = /*Strict*/Math.pow( ANT_K + ((AntsForage)state).toFoodGrid.field[di.position.x][di.position.y], ANT_N );;
di.homePheromoneAmount = 0.001 + af.toHomeGrid.field[di.position.x][di.position.y];
di.foodPheromoneAmount = 0.001 + af.toFoodGrid.field[di.position.x][di.position.y];
decisionMaker.addInfo( di );
}
}
public DecisionInfo decideAction( final SimState state, final int myx, final int myy, final int orientation )
{
final AntsForage af = (AntsForage)state;
final DecisionMaker decisionMaker = af.decisionMaker;
decisionMaker.reset();
// collect the sensory information for the new grid model
// this should be done separately in the model, but whatever....
switch( ANT_TYPE )
{
case ORIENTED_ANT:
switch( orientation )
{
case 0: addInformation( state, myx-1, myy+1, (orientation+7)%8 ); // forward-left
addInformation( state, myx, myy+1, orientation ); // forward
addInformation( state, myx+1, myy+1, (orientation+1)%8 ); // forward-right
break;
case 1: addInformation( state, myx, myy+1, (orientation+7)%8 ); // forward-left
addInformation( state, myx+1, myy+1, orientation ); // forward
addInformation( state, myx+1, myy, (orientation+1)%8 ); // forward-right
break;
case 2: addInformation( state, myx+1, myy+1, (orientation+7)%8 ); // forward-left
addInformation( state, myx+1, myy, orientation ); // forward
addInformation( state, myx+1, myy-1, (orientation+1)%8 ); // forward-right
break;
case 3: addInformation( state, myx+1, myy, (orientation+7)%8 ); // forward-left
addInformation( state, myx+1, myy-1, orientation ); // forward
addInformation( state, myx, myy-1, (orientation+1)%8 ); // forward-right
break;
case 4: addInformation( state, myx+1, myy-1, (orientation+7)%8 ); // forward-left
addInformation( state, myx, myy-1, orientation ); // forward
addInformation( state, myx-1, myy-1, (orientation+1)%8 ); // forward-right
break;
case 5: addInformation( state, myx, myy-1, (orientation+7)%8 ); // forward-left
addInformation( state, myx-1, myy-1, orientation ); // forward
addInformation( state, myx-1, myy, (orientation+1)%8 ); // forward-right
break;
case 6: addInformation( state, myx-1, myy-1, (orientation+7)%8 ); // forward-left
addInformation( state, myx-1, myy, orientation ); // forward
addInformation( state, myx-1, myy+1, (orientation+1)%8 ); // forward-right
break;
case 7: addInformation( state, myx-1, myy, (orientation+7)%8 ); // forward-left
addInformation( state, myx-1, myy+1, orientation ); // forward
addInformation( state, myx, myy+1, (orientation+1)%8 ); // forward-right
break;
}
break;
case NSEW_ANT:
addInformation( state, myx-1, myy, (orientation+7)%8 ); // N
addInformation( state, myx+1, myy, (orientation+7)%8 ); // S
addInformation( state, myx, myy-1, (orientation+7)%8 ); // E
addInformation( state, myx, myy+1, (orientation+7)%8 ); // W
break;
case EIGHT_NEIGHBOURS_ANT:
addInformation( state, myx-1, myy-1, (orientation+7)%8 ); // N
addInformation( state, myx-1, myy, (orientation+7)%8 ); // N
addInformation( state, myx-1, myy+1, (orientation+7)%8 ); // N
addInformation( state, myx+1, myy-1, (orientation+7)%8 ); // S
addInformation( state, myx+1, myy, (orientation+7)%8 ); // S
addInformation( state, myx+1, myy+1, (orientation+7)%8 ); // S
addInformation( state, myx-1, myy, (orientation+7)%8 ); // E
addInformation( state, myx+1, myy, (orientation+7)%8 ); // W
break;
}
if( hasFoodItem )
return decisionMaker.getHomeGreedyDecision( state );
else
{
if( GREEDY_EXPLORATION )
return decisionMaker.getFoodGreedyDecision( state );
else
return decisionMaker.getFoodDecision( state );
}
}
public void addPheromone(DoubleGrid2D grid, int x, int y, double pheromone)
{
switch( PHEROMONE_TYPE )
{
case ADD_PHEROMONE:
grid.field[x][y] += /*Strict*/Math.abs(pheromoneToLeaveBehind);
if (grid.field[x][y] > maxPheromone)
grid.field[x][y] = maxPheromone;
break;
case MAX_PHEROMONE:
grid.field[x][y] = /*Strict*/Math.max( grid.field[x][y], pheromone );
break;
case LOCAL_PHEROMONE:
double amount = /*Strict*/Math.max( grid.field[x][y], pheromone );
if( x > 0 && y > 0 )
amount = /*Strict*/Math.max( /*Strict*/Math.max( grid.field[x-1][y-1]-subtractingRatio, minPheromone ), amount );
if( x > 0)
amount = /*Strict*/Math.max( /*Strict*/Math.max( grid.field[x-1][y]-subtractingRatio, minPheromone ), amount );
if( x > 0 && y < grid.field[x].length-1 )
amount = /*Strict*/Math.max( /*Strict*/Math.max( grid.field[x-1][y+1]-subtractingRatio, minPheromone ), amount );
if( y > 0 )
amount = /*Strict*/Math.max( /*Strict*/Math.max( grid.field[x][y-1]-subtractingRatio, minPheromone ), amount );
if( y < grid.field.length-1 )
amount = /*Strict*/Math.max( /*Strict*/Math.max( grid.field[x][y+1]-subtractingRatio, minPheromone ), amount );
if( x < grid.field.length-1 && y > 0 )
amount = /*Strict*/Math.max( /*Strict*/Math.max( grid.field[x+1][y-1]-subtractingRatio, minPheromone ), amount );
if( x < grid.field.length-1 )
amount = /*Strict*/Math.max( /*Strict*/Math.max( grid.field[x+1][y]-subtractingRatio, minPheromone ), amount );
if( x < grid.field.length-1 && y < grid.field[x].length-1 )
amount = /*Strict*/Math.max( /*Strict*/Math.max( grid.field[x+1][y+1]-subtractingRatio, minPheromone ), amount );
grid.field[x][y] = amount;
pheromoneRatio = amount;
break;
}
}
public DecisionInfo decideGreedyAction( final SimState state, final int myx, final int myy, final int orientation )
{
final AntsForage af = (AntsForage)state;
final DecisionMaker decisionMaker = af.decisionMaker;
decisionMaker.reset();
// add all neighboring cells and move to one of them
addInformation( state, myx, myy+1, 0 );
addInformation( state, myx+1, myy+1, 1 );
addInformation( state, myx+1, myy, 2 );
addInformation( state, myx+1, myy-1, 3 );
addInformation( state, myx, myy-1, 4 );
addInformation( state, myx-1, myy-1, 5 );
addInformation( state, myx-1, myy, 6 );
addInformation( state, myx-1, myy+1, 7 );
if( hasFoodItem )
return decisionMaker.getHomeGreedyDecision( state );
else
return decisionMaker.getFoodGreedyDecision( state );
}
public void step( final SimState state )
{
final AntsForage af = (AntsForage)state;
final DecisionMaker decisionMaker = af.decisionMaker;
Int2D location = af.buggrid.getObjectLocation(this);
int myx = location.x;
int myy = location.y;
if( justCreated )
{
DecisionInfo temp = decideGreedyAction( state, myx, myy, orientation );
if( temp == null )
return;
orientation = temp.orientation;
justCreated = false;
}
// final int START=-1;
int bestx, besty, besto;
DecisionInfo movingDecision = null;
if( hasFoodItem )
movingDecision = decideGreedyAction( state, myx, myy, orientation );
else
{
decisionMaker.reset();
addInformation( state, myx, myy+1, 0 );
addInformation( state, myx+1, myy+1, 1 );
addInformation( state, myx+1, myy, 2 );
addInformation( state, myx+1, myy-1, 3 );
addInformation( state, myx, myy-1, 4 );
addInformation( state, myx-1, myy-1, 5 );
addInformation( state, myx-1, myy, 6 );
addInformation( state, myx-1, myy+1, 7 );
int max = 0;
int howMany = 1;
for( int i = 1 ; i < decisionMaker.numInfos ; i++ )
if( decisionMaker.info[max].foodPheromoneAmount ==
decisionMaker.info[i].foodPheromoneAmount )
{
howMany++;
}
else if( decisionMaker.info[max].foodPheromoneAmount <
decisionMaker.info[i].foodPheromoneAmount )
{
max = i;
howMany = 1;
}
if( howMany == 1 )
movingDecision = decideGreedyAction( state, myx, myy, orientation );
else
movingDecision = decideAction( state, myx, myy, orientation );
}
if( movingDecision == null )
{
movingDecision = decideGreedyAction( state, myx, myy, orientation );
if( movingDecision == null )
{
bestx = myx;
besty = myy;
besto = orientation;
}
else
{
bestx = movingDecision.position.x;
besty = movingDecision.position.y;
besto = movingDecision.orientation;
}
}
else
{
bestx = movingDecision.position.x;
besty = movingDecision.position.y;
besto = movingDecision.orientation;
}
if( ( bestx != myx || besty != myy ))
{
// add some pheromones
if( hasFoodItem )
{
addPheromone(af.toFoodGrid,myx,myy,(/*pheromoneToLeaveBehind*/pheromoneRatio));
}
else
{
addPheromone(af.toHomeGrid,myx,myy,(/*pheromoneToLeaveBehind*/pheromoneRatio));
}
if( bestx != myx && besty != myy )
pheromoneRatio -= subtractingRatio*1.4142;
else
pheromoneRatio -= subtractingRatio;
if( pheromoneRatio < 0 )
{
die( state );
return;
}
// adjust the position of the agent, and then deposit the "to food" and "to home" pheromones
af.buggrid.setObjectLocation(this,bestx,besty);
orientation = besto;
if( ( besty >= AntsForage.HOME_YMIN ) && ( besty <= AntsForage.HOME_YMAX ) &&
( bestx >= AntsForage.HOME_XMIN ) && ( bestx <= AntsForage.HOME_XMAX ) )
{
if( hasFoodItem )
{
af.foodCollected++;
hasFoodItem = false;
pheromoneRatio = 1.0 * maxPheromone;
if( GREEDY_REPOSITIONING )
{
// pick greediest orientation!
DecisionInfo temp = decideGreedyAction( state, myx, myy, orientation );
if( temp != null )
orientation = temp.orientation;
else
orientation = (orientation+4)%8;
}
else
orientation = (orientation+4)%8; // rotate 180
}
}
else if( ( besty >= AntsForage.FOOD_YMIN ) && ( besty <= AntsForage.FOOD_YMAX ) &&
( bestx >= AntsForage.FOOD_XMIN ) && ( bestx <= AntsForage.FOOD_XMAX ) )
{
if( !hasFoodItem )
{
hasFoodItem = true;
pheromoneRatio = 1.0 * maxPheromone;
if( GREEDY_REPOSITIONING )
{
// pick greediest orientation!
DecisionInfo temp = decideGreedyAction( state, myx, myy, orientation );
if( temp != null )
orientation = temp.orientation;
else
orientation = (orientation+4)%8;
}
else
orientation = (orientation+4)%8; // rotate 180
}
}
timeToLive--;
if( timeToLive <= 0 )
{
die( state );
return;
}
}
}
// a few tweaks by Sean
private Color noFoodColor = Color.black;
private Color foodColor = Color.red;
public final void draw(Object object, Graphics2D graphics, DrawInfo2D info)
{
if( hasFoodItem )
graphics.setColor( foodColor );
else
graphics.setColor( noFoodColor );
// this code was stolen from OvalPortrayal2D
int x = (int)(info.draw.x - info.draw.width / 2.0);
int y = (int)(info.draw.y - info.draw.height / 2.0);
int width = (int)(info.draw.width);
int height = (int)(info.draw.height);
graphics.fillOval(x,y,width, height);
}
public Stoppable toDiePointer = null;
public void die( final SimState state )
{
AntsForage antsforage = (AntsForage)state;
antsforage.numberOfAnts--;
antsforage.buggrid.remove( this );
if(toDiePointer!=null) toDiePointer.stop();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy