VacWorld
From Agent Factory
Down below, you will find two examples of a cleaner agent for VacWorld.
Extended simple cleaner
Taking the simple cleaner code in the AgentSpeak tutorial and extending it to use a modified Whiteboard API to share information about the visited squares. Using that information, the vacs try to avoid squares visited by themselves or any other vac.
Agent code (VacBot.aspeak)
#agent VacBot #extends com.agentfactory.eis.EISAgent
module whiteboard -> vacworld.WhiteboardAPI;
action nextmethod(?d,?x,?y) -> vacworld.Next;
#implements #partial @postInitialize <- //setting up whiteboard at initialization
whiteboard.setup;
+location(?x, ?y) : square(here, dust) <- //a new move is initiated when there is a new location belief
!clean,
!doMove(?x,?y);
+location(?x, ?y) : ~square(here, dust) <-
!doMove(?x,?y);
+!doMove(?x,?y) : name(?name) <-
!addLocationInfo(?x,?y), //adds the current square to the whiteboard
!isNextVisited(?x,?y), //creates the beliefs about the next possible squares
try {
!move(?x,?y)
} recover {
.println(?name + " had problem moving."),
!doMove(?x,?y)
};
+!move(?x,?y) : square(forward, dust) <-
durative(eis.perform(move(forward)));
+!move(?x,?y) : square(left, dust) <-
durative(eis.perform(move(left)));
+!move(?x,?y) : square(right, dust) <-
durative(eis.perform(move(right)));
+!move(?x,?y) : ~square(forward, obstacle) & ~square(forward, vac) & ~isVisited(forward) <- //if square is not an obstacle, a vac or has not been visited
durative(eis.perform(move(forward)));
+!move(?x,?y) : ~square(left, obstacle) & ~square(left, vac) & ~isVisited(left) <- //if square is not an obstacle, a vac or has not been visited
durative(eis.perform(move(left)));
+!move(?x,?y) : ~square(right, obstacle) & ~square(right, vac) & ~isVisited(right) <- //if square is not an obstacle, a vac or has not been visited
durative(eis.perform(move(right)));
+!move(?x,?y) : ~square(forward, obstacle) & ~square(forward, vac) <-
durative(eis.perform(move(forward)));
+!move(?x,?y) : ~square(left, obstacle) & ~square(left, vac) <-
durative(eis.perform(move(left)));
+!move(?x,?y) : ~square(right, obstacle) & ~square(right, vac) <-
durative(eis.perform(move(right)));
+!move(?x,?y) : true <-
try {
durative(eis.perform(move(right))) //if move fails try to move right
} recover {
try{
durative(eis.perform(move(right))) //if move to right fails, try to move right (backwards from original direction)
} recover {
try{
durative(eis.perform(move(right))) //if move to right fails, try to move right (right from original direction)
} recover {
!move
}
}
};
+!clean : true <-
eis.perform(light(on)),
durative(eis.perform(clean)),
eis.perform(light(off));
+!addLocationInfo(?x,?y): true <-
whiteboard.setup, //calling setup (just in case)
whiteboard.put(?x,?y), //putting coordinates
whiteboard.view; //updating information from whiteboard (getting info from other bots)
+!isNextVisited(?x,?y):direction(?d) <- //
.abolishAll(next(?1,?2,?3)), //removing all next beliefs (next squares)
-isVisited(forward), //removing previous isVisited beliefs
-isVisited(left),
-isVisited(right),
nextmethod(?d,?x,?y); //creating new next beliefs
+next(?a,?b,?c):visited(?b,?c) <- //if square in next(square, x-coord, y-coord) has been visited (listed in whiteboard)
+isVisited(?a); //mark it as visited (create belief)
nextmethod(?d,?x,?y) action (Next.java)
package vacworld;
import com.agentfactory.clf.lang.Predicate;
import com.agentfactory.clf.interpreter.Action;
public class Next extends Action {
public boolean execute(Predicate activity){
String dir = termAsString(activity,0); //getting direction
int x = termAsInt(activity,1); //x-coordinate
int y = termAsInt(activity,2); //y-coordinate
//calculating the coordinates of the three possible next squares, and adding the beliefs
if(dir.equals("south")){
addBelief("next(right,"+(x-1)+","+(y)+")");
addBelief("next(left,"+(x+1)+","+(y)+")");
addBelief("next(forward,"+(x)+","+(y-1)+")");
} else if(dir.equals("west")){
addBelief("next(right,"+(x)+","+(y+1)+")");
addBelief("next(left,"+(x)+","+(y-1)+")");
addBelief("next(forward,"+(x-1)+","+(y)+")");
} else if(dir.equals("east")){
addBelief("next(right,"+(x)+","+(y-1)+")");
addBelief("next(left,"+(x)+","+(y+1)+")");
addBelief("next(forward,"+(x+1)+","+(y)+")");
} else if(dir.equals("north")){
addBelief("next(right,"+(x+1)+","+(y)+")");
addBelief("next(left,"+(x-1)+","+(y)+")");
addBelief("next(forward,"+(x)+","+(y+1)+")");
}
return true;
}
}
Whiteboard API (WhiteboardAPI.java)
package vacworld;
import com.agentfactory.clf.interpreter.Action;
import com.agentfactory.clf.interpreter.CoreUtilities;
import com.agentfactory.clf.interpreter.Module;
import com.agentfactory.clf.lang.Predicate;
public class WhiteboardAPI extends Module {
private WhiteboardService service;
public WhiteboardAPI() {
addAction("setup", new Action() {
@Override
public boolean execute(Predicate activity) {
agent.bindToPlatformService(WhiteboardService.NAME);
service = (WhiteboardService) agent.getPlatformService(WhiteboardService.NAME);
return true;
}
});
addAction("put(?x,?y)", new Action() {
@Override
public boolean execute(Predicate activity) {
String location = CoreUtilities.presenter.toString(activity.termAt(0))+","+CoreUtilities.presenter.toString(activity.termAt(1));
String info = "visited";
service.putInformation(location,"visited"); //we only need to store the coordinates (key)
return true;
}
});
addAction("removeInfo(?x,?y)", new Action() {
@Override
public boolean execute(Predicate activity) {
String location = CoreUtilities.presenter.toString(activity.termAt(0))+","+CoreUtilities.presenter.toString(activity.termAt(1));
service.removeInformation(location);
return true;
}
});
addAction("view", new Action() {
@Override
public boolean execute(Predicate activity) {
if (service == null) return false;
for (String bel : service.getInformation()) {
addBelief(bel);
}
return true;
}
});
}
}
Modified WhiteboardService (WhiteboardService.java)
package vacworld;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.agentfactory.platform.impl.AbstractPlatformService;
public class WhiteboardService extends AbstractPlatformService {
public static final String NAME = "af.std.wb";
private Map<String, String> information;
public WhiteboardService() {
information = new HashMap<String, String>();
}
public synchronized String getInformation(String key) {
if(!information.containsKey(key))
return null;
return "information(" + key + "," + information.get(key) + ")";
}
public synchronized List<String> getInformation() {
List<String> list = new ArrayList<String>();
for (String key: information.keySet()) {
list.add("visited(" + key + ")");
}
return list;
}
public synchronized void putInformation(String location, String info) {
information.put(location, info);
setChanged();
notifyObservers();
}
public synchronized String removeInformation(String location) {
String temp = (String) information.remove(location);
setChanged();
notifyObservers();
return temp;
}
}
To deploy the example create a VacWorld and an VacWordEIS java class
VacWorld.java
package vacworld;
import java.util.HashMap;
import java.util.Map;
public class VacWorld{
public static void main(String[] args) {
Map<String, String> designs = new HashMap<String, String>();
designs.put("vacbot", "vacworld/VacBot.aspeak");
new VacWorldEIS("vacworld", designs, "ita.jar");
}
}
VacWorldEIS.java
package vacworld;
import java.util.List;
import java.util.Map;
import com.agentfactory.eis.EISDebugConfiguration;
public class VacWorldEIS extends EISDebugConfiguration {
public VacWorldEIS(String name, Map<String, String> designs, String jar){
super(name,designs,jar);
configure();
addPlatformService(WhiteboardService.class, WhiteboardService.NAME);
}
}
Dust aware cleaner
This example retains some of the elements of a simple cleaner, however it is different from it.
Each move consists of three phases (preMove, theMove and PostMove).
preMove:
- gets location coordinates
- checks if current location contains dust
- if it contains dust, clean square
- scans the neighbouring squares for dust (if found, location is published to the whiteboard)
- if the current location is the target, remove targeted belief
theMove (the vac moves using the following conditions):
- if there is dust in the forward, left or right square, move to that square
- if there is a target, get the next move and make a move accordingly
- if there is no target and there is an avaliable dust as target, choose it and make move accordingly
- else make a move to an avaliable square
postMove:
- initiate a new move
Vac code (vac.aspeak)
#agent vac #extends com.agentfactory.eis.EISAgent
module whiteboard -> vacworld2.WhiteboardAPI; //whiteboard
module getsquare -> vacworld2.GetSquare; //get input square coordinates
module getdist -> vacworld2.GetDistance; //get distance between two locations
module nav -> vacworld2.Nav; //navigation module (used to get next move)
#implements #partial @postInitialize <-
whiteboard.setup, //setting up whiteboard
!makeMove; //making first move
+!makeMove:true <- //the move process
!preMove,
!theMove,
!postMove;
+!preMove:square(here,dust) <- //current square has dust
query(location(?x,?y)), //getting current location
!clean, //clean
!detect, //scan neighbouring squares
if(targeted(?x,?y)){ //if target==current location
-targeted(?x,?y) //remove target
};
+!preMove:~square(here,dust) <- //current square does not have dust
query(location(?x,?y)),
!removeDust(?x,?y),
!detect,
if(targeted(?x,?y)){
-targeted(?x,?y)
};
+!theMove : square(forward, dust) <- //if forward square has dust, move forward
durative(eis.perform(move(forward)));
+!theMove : square(left, dust) <- //if left square has dust, move left
durative(eis.perform(move(left)));
+!theMove : square(right, dust) <- //if right square has dust, move right
durative(eis.perform(move(right)));
+!theMove : targeted(?a,?b) <- //if there is a target
.abolishAll(nextMove(?r)), //delete all nextMove(?r) beliefs
query(direction(?dir)), //get current direction
if(targeted(?a,?b)){ //if there is a target (if added in as target dust might have been removed while deleting and querying direction)
query(location(?x,?y)),
nav.getNextMove(?a,?b,?x,?y,?dir), //get next move a:target x, b:target y, x:location x, y:location y
query(nextMove(?r)), //query next move
try{
durative(eis.perform(move(?r))) //try next move
} recover {
!theMove2 //if it fails continue with move
}
} else {
!theMove2 //if target lost, continue with move
};
+!theMove : dust(?a,?b) <- //if there is no target, and there is dust avaliable
!target(?a,?b), //target avaliable dust
.abolishAll(nextMove(?r)),
query(direction(?dir)),
query(location(?x,?y)),
nav.getNextMove(?a,?b,?x,?y,?dir),
query(nextMove(?r)),
try{
durative(eis.perform(move(?r)))
} recover {
!theMove2
};
+!theMove:true <- //if the previous conditions did not hold, continue with move
!theMove2;
//the moves had to be named differently, as fails have to be directed to this point, and not redirected to the top of the move list
//these moves are the same as for the simple cleaner bot
+!theMove2 : ~square(forward, obstacle) & ~square(forward, vac) <-
durative(eis.perform(move(forward)));
+!theMove2 : ~square(left, obstacle) & ~square(left, vac) <-
durative(eis.perform(move(left)));
+!theMove2 : ~square(right, obstacle) & ~square(right, vac) <-
durative(eis.perform(move(right)));
+!theMove2 : true <-
try {
durative(eis.perform(move(right)))
} recover {
try{
durative(eis.perform(move(right)))
} recover {
try{
durative(eis.perform(move(right)))
} recover {
!theMove
}
}
};
//target input coordinates
+!target(?x,?y):true <-
whiteboard.setup,
+targeted(?x,?y), //add target belief
whiteboard.removeInfo(?x,?y), //remove target dust from whiteboard
.send(inform, agentID(".*",addresses("local:vacworld.eis.ucd.ie")), targeted);
//send update info to all bots
+!postMove:true <- //make new move
!makeMove;
+!clean : location(?x,?y) <- //clean current square
eis.perform(light(on)),
durative(eis.perform(clean)),
eis.perform(light(off)),
query(location(?x,?y)),
!removeDust(?x,?y); //remove dust information
//to update the dust beliefs
+!updateDustInfo:true <-
whiteboard.setup, //setting up whiteboard (just in case)
.abolishAll(dust(?i,?j)), //removing all dust beliefs
whiteboard.view; //getting new beliefs
+!removeDust(?x,?y):true<-
whiteboard.setup,
whiteboard.removeInfo(?x,?y), //remove dust info from whiteboard
-dust(?x,?y), //remove dust belief
.send(inform, agentID(".*",addresses("local:vacworld.eis.ucd.ie")), cleaned(?x,?y));
//send cleaned message to all bots
//scan neighbouring squares for dust
+!detect:square(?pos,dust)&location(?x,?y)&direction(?dir) <- //if there is dust
foreach(square(?pos,dust)){ //for each location
getsquare.getsq(?dir,?x,?y,?pos) //get its coordinates (creates dustFound belief)
},
.send(inform, agentID(".*",addresses("local:vacworld.eis.ucd.ie")), updated(?x,?y));
//send update information with vac's location
+!detect:true <- //do nothing if conditions are not met
.nil;
+dustFound(?x,?y):true <- //belief generated when dust is found
whiteboard.setup,
whiteboard.put(?x,?y), //put dust information on whiteboard
-dustFound(?x,?y); //remove dustFound belief
//update message, only bost which are from a distance of 8 from the source bot update their beliefs
+message(inform, agentID(?from, ?addr), updated(?x,?y)):true <-
query(location(?a,?b)),
getdist.getdist(?x,?y,?a,?b), //get distance between bot and source bot
query(distance(?x,?y,?a,?b,?dist)),
if(?dist<8){ //if distance is less than 8 update
!updateDustInfo
}
if(~targeted(?a,?b)){ //if there is no target update
!updateDustInfo
}
-message(inform, agentID(?from, ?addr), updated), //remove message belief
-distance(?x,?y,?a,?b,?dist); //remove distance belief
//targetet message (all bots are required to update their beliefs)
+message(inform, agentID(?from, ?addr), targeted):true <-
!updateDustInfo,
-message(inform, agentID(?from, ?addr), targeted);
//clean update, warns bots about cleaned dust, if bot had cleaned dust as target, target belief is removed
+message(inform, agentID(?from, ?addr), cleaned(?x,?y)):true <-
if(targeted(?x,?y)){
-targeted(?x,?y)
};
Nav module (Nav.java)
Module to get the next move required to get to a certain location
package vacworld2;
import java.awt.List;
import java.util.HashMap;
import java.util.concurrent.ConcurrentHashMap;
import com.agentfactory.clf.interpreter.Action;
import com.agentfactory.clf.interpreter.Module;
import com.agentfactory.clf.interpreter.Sensor;
import com.agentfactory.clf.lang.Predicate;
public class Nav extends Module {
int tX = -1; //target x
int tY = -1; //target y
int lX = -1; //current x
int lY = -1; //current y
String dir = null; //direction
public Nav() {
//action to set target (getNextMove support setting target)
addAction("setTarget(?x,?y)",new Action(){
public boolean execute(Predicate activity){
tX = termAsInt(activity,0);
tY = termAsInt(activity,1);
return true;
}
});
//get the next move from current location to target
addAction("getNextMove(?a,?b,?x,?y,?dir)",new Action(){
public boolean execute(Predicate activity){
boolean fault = false;
tX = termAsInt(activity,0);
tY = termAsInt(activity,1);
try {
lX = termAsInt(activity,2);
} catch (Exception e){ //catch in case of invalid input
fault = true;
}
try {
lY = termAsInt(activity,3);
} catch (Exception e){ //catch in case input is invalid
fault = true;
}
dir = termAsString(activity,4);
String out = nextMove();
if(!fault){
addBelief("nextMove("+out+")");
} else { //in case of invalid input return forward as next move
addBelief("nextMove(forward)");
}
return true;
}
});
}
//method to calculate next move
public String nextMove(){
int Xdiff = lX-tX;
int Ydiff = lY-tY;
String out = "";
if(tX==-1||tY==-1){
out = "forward";
} else {
if(Xdiff!=0){
if(dir.equals("north")){
if(Xdiff<0){
out = "right";
} else {
out = "left";
}
} else if(dir.equals("south")){
if(Xdiff<0){
out = "left";
} else {
out = "right";
}
} else if(dir.equals("east")){
if(Xdiff<0){
out = "forward";
} else {
if(Ydiff<0){
out = "right";
} else {
out = "left";
}
}
} else if(dir.equals("west")){
if(Xdiff>0){
out = "forward";
} else {
if(Ydiff<0){
out = "left";
} else {
out = "right";
}
}
}
} else {
if(dir.equals("north")){
if(Ydiff<0){
out = "left";
} else {
out = "forward";
}
} else if(dir.equals("south")){
if(Ydiff<0){
out = "forward";
} else {
out = "left";
}
} else if(dir.equals("east")){
if(Ydiff<0){
out = "right";
} else {
out = "left";
}
} else if(dir.equals("west")){
if(Ydiff<0){
out = "left";
} else {
out = "right";
}
}
}
if(out.equals("")){
out = "forward";
}
}
return out;
}
}
GetSquare.java -- same code as for the Extended simple cleaner
DetDist (GetDistance.java)
To calculate the distance between two locations
package vacworld2;
import com.agentfactory.clf.interpreter.Action;
import com.agentfactory.clf.interpreter.Module;
import com.agentfactory.clf.interpreter.Sensor;
import com.agentfactory.clf.lang.Predicate;
public class GetDistance extends Module {
public GetDistance() {
addAction("getdist(?x,?y,?a,?b)",new Action(){
public boolean execute(Predicate activity){
int x = termAsInt(activity,0);
int y = termAsInt(activity,1);
int a = termAsInt(activity,2);
int b = termAsInt(activity,3);
int dist = Math.abs(x-a)+Math.abs(y-b);
addBelief("distance("+x+","+y+","+a+","+b+","+dist+")");
return true;
}
});
}
}
Whiteboard API (WhiteboardAPI.java)
Changed put(?x,?y) action
addAction("put(?x,?y)", new Action() {
@Override
public boolean execute(Predicate activity) {
String location = CoreUtilities.presenter.toString(activity.termAt(0))+","+CoreUtilities.presenter.toString(activity.termAt(1));
String info = "dust";
service.putInformation(location,info);
return true;
}
});
Whiteboard service (WhiteboardService.java)
Changed getInformation(key) method
public synchronized String getInformation(String key) {
if(!information.containsKey(key))
return null;
return "dust(" + key + ")";
}
To deploy, use the VacWorld and the VacWorldEIS java classes, and replace
designs.put("vacbot", "vacworld/VacBot.aspeak");
with
designs.put("vacbot", "vacworld2/vac.aspeak");
in the VacWorld class.
