/*
* (C) 2003-2009 Spolecne s.r.o.
* Author: Tomas Straka
* www.spoledge.com
*
* Written permission must be obtained in advance from Spolecne s.r.o for any form of
* reproduction, use or distribution.
*/
package ants.models.thrakia;
import ants.Ant;
import ants.DPoint;
import ants.EventQueue;
import ants.OrientedRectangle;
import ants.World;
import ants.WorldObject;
import vb.util.AdvancedPropertiesParser;
import vb.util.ParsingException;
import java.util.HashMap;
/**
* The implementation of the Thrakia ant.
*/
public class ThrakiaAnt extends Ant {
/**
* The time frame for the ant to collect the result of the neural network
* and perform the desired activity. see FireLaw, this number must be significantly
* higher than tm. In seconds. Smaller number = smooth walk. Bigger number = faster
* simulation.
*/
private static final double dTime = 0.2;
/**
* The neural network. All the logic of the ants behaviour is implemented there
*/
private ThrakiaNetwork network;
/**
* The constructor
*/
public ThrakiaAnt(AdvancedPropertiesParser app, String prefix) throws ParsingException {
super( app, prefix );
}
/**
* Tests position of antenas against all objects in the world.
* It does not test tail of the ant - so it can go back inside another
* world object.
*
* @param lt left antena
* @param rt right antena
*/
protected boolean [] testCrashFront(DPoint lt, DPoint rt) {
boolean left = false;
boolean right = false;
for (WorldObject wo : world.getObjects()) {
if (wo == this) continue;
OrientedRectangle bb = wo.getBoundingBox();
if(!left) left = bb.contains( lt.x, lt.y );
if(!right) right = bb.contains( rt.x, rt.y );
if(left && right) break; // optimisation
}
return new boolean [] { left, right };
}
/**
* Read the world's environment. See makePath for the reverse method.
*/
protected void fillRemainingEnvironment( DPoint tentacle, HashMap<Odour, Double> environment ) {
environment.put(Odour.HOME, new Double(world.get(tentacle.x, tentacle.y, World.MRAVSLINT)));
environment.put(Odour.LEAVE, new Double(world.get(tentacle.x, tentacle.y, World.LEAVE)));
environment.put(Odour.WATER, new Double(world.get(tentacle.x, tentacle.y, World.WATER)));
}
/**
* Read the world and fill the tentacles. See max and min intensity in the Tentacle.
*/
protected void fillTentacles() {
DPoint leftTentacle = boundingBox.getLT();
DPoint riteTentacle = boundingBox.getRT();
HashMap<Odour, Double> leftEnvironment = new HashMap<Odour, Double>();
HashMap<Odour, Double> riteEnvironment = new HashMap<Odour, Double>();
boolean [] crashed = testCrashFront(leftTentacle, riteTentacle);
if( crashed[0] ) leftEnvironment.put(Odour.STONE, Tentacle.getMaxIntensity());
if( crashed[1] ) riteEnvironment.put(Odour.STONE, Tentacle.getMaxIntensity());
fillRemainingEnvironment(leftTentacle, leftEnvironment);
fillRemainingEnvironment(riteTentacle, riteEnvironment);
network.getLeftTentacle().accept( leftEnvironment );
network.getRightTentacle().accept( riteEnvironment );
}
/**
* Put some odour into the world, make paths. See fillRemainingEnvironment for
* the reverse method.
* @param amount in 0..1
*/
protected void makePath( DPoint leg, Odour o, double amount ) {
if (o == null) return;
double putVol = amount * Tentacle.getMaxIntensity();
switch( o ) {
case HOME: world.put(leg.x, leg.y, World.MRAVSLINT, putVol );
break;
}
}
/**
* Walk according to the network output
*/
protected void walk() {
OutputDBC [] out = new OutputDBC [] { network.getLeftLegFwd(),
network.getLeftLegBackwd(),
network.getRightLegFwd(),
network.getRightLegBackwd() };
for ( int i = 0; i < out.length; i++ ) {
out[i].compute();
out[i].clean(); // for the next step
}
makePath( boundingBox.getLB(), out[0].getOdour(), out[0].getAmount() );
makePath( boundingBox.getRB(), out[2].getOdour(), out[2].getAmount() );
makePath( boundingBox.getLB(), out[1].getOdour(), out[1].getAmount() ); // in fact void
makePath( boundingBox.getRB(), out[3].getOdour(), out[3].getAmount() ); // in fact void
double leftWards = out[0].getAmount() - out[1].getAmount(); // -1 .. +1
double riteWards = out[2].getAmount() - out[3].getAmount();
if( leftWards > 0.0 && riteWards > 0.0 ) {
if( leftWards > riteWards ) {
moveLeftLeg(leftWards - riteWards);
moveBothLegs(riteWards);
} else {
moveRightLeg(riteWards - leftWards);
moveBothLegs(leftWards);
}
} else if( leftWards < 0.0 && riteWards < 0.0 ) {
if( leftWards > riteWards ) {
moveRightLeg(riteWards - leftWards);
moveBothLegs(leftWards);
} else {
moveLeftLeg(leftWards - riteWards);
moveBothLegs(riteWards);
}
} else {
moveLeftLeg(leftWards);
moveRightLeg(riteWards);
}
}
/**
* One step in the life
*/
public void simulate(EventQueue.Item item) {
EventQueue eq = item.getEventQueue();
if( network == null ) { // We are at the beginning of the simulation
network = new ThrakiaNetwork( eq );
} else {
walk();
}
fillTentacles();
// schedule the next step
eq.schedule(dTime, this);
}
/**
* Return the interval between actions
*/
public static double getInterval() {
return dTime;
}
}
|