/**
*
*/
package iamrescue.agent.search;
import iamrescue.belief.IAMWorldModel;
import iamrescue.execution.IExecutionService;
import iamrescue.execution.command.IPath;
import iamrescue.execution.command.MoveCommand;
import iamrescue.routing.IRoutingModule;
import iamrescue.routing.Path;
import iamrescue.util.PositionXY;
import iamrescue.util.comparators.EntityIDComparator;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Random;
import java.util.Set;
import javolution.util.FastList;
import org.apache.commons.collections15.SetUtils;
import org.apache.log4j.Logger;
import rescuecore2.config.Config;
import rescuecore2.standard.entities.Area;
import rescuecore2.standard.entities.Human;
import rescuecore2.standard.entities.Road;
import rescuecore2.standard.entities.StandardEntity;
import rescuecore2.standard.entities.StandardEntityURN;
import rescuecore2.worldmodel.EntityID;
/**
* @author Simon
* Coordinated search behaviour
*
* Agents search a subset of locations - defined at the start as a shared randomisation of the map
*
* id dictates which section of the list to favour
*
*/
public class RandomisedClosestSearchBehaviour implements ISearchBehaviour {
private EntityID myself;
private IAMWorldModel worldModel;
private IExecutionService executionService;
private IRoutingModule routingModule;
private boolean blockades;
private List<EntityID> preference;
private long randomSeed = 47298123;
private static final Logger LOGGER = Logger
.getLogger(RandomisedClosestSearchBehaviour.class);
private static final String BLOCKADE_KEY = "collapse.create-road-blockages";
public RandomisedClosestSearchBehaviour(IAMWorldModel worldModel, EntityID myself,
IExecutionService executionService, IRoutingModule routingModule,
Config config) {
this.blockades = true;// config.getBooleanValue(BLOCKADE_KEY, true);
this.worldModel = worldModel;
this.myself = myself;
this.executionService = executionService;
this.routingModule = routingModule;
//set start and end Ids for this agent to prefer to search
//team size is used to make the set
Collection<StandardEntity> preferences = worldModel.getEntitiesOfType(StandardEntityURN.BUILDING);
ArrayList<StandardEntity> prefs = new ArrayList<StandardEntity>();
for(Iterator<StandardEntity> it = preferences.iterator();it.hasNext();){
StandardEntity b = it.next();
prefs.add(b);
}
Collections.shuffle(prefs, new Random(randomSeed ));
Collection<StandardEntity> agents = worldModel.getEntitiesOfType(StandardEntityURN.AMBULANCE_TEAM,StandardEntityURN.POLICE_FORCE);
//assumption - worldmodel returns agents in the same order? need to ask
int pos=0;
int position=0;
for(Iterator<StandardEntity> it = agents.iterator();it.hasNext();){
StandardEntity agent = it.next();
if(agent.getID().getValue()==myself.getValue()){
position = pos;
}
pos++;
}
int clustersize = prefs.size()/agents.size();
makePreferenceList(position,clustersize,prefs);
}
/*
* keeps list in prerefnces for my section
*/
private void makePreferenceList(int position, int clustersize, ArrayList<StandardEntity> preferences) {
preference = new ArrayList<EntityID>();
int start = clustersize*position;
int it = start;
//System.out.println("Agent: " + myself.getValue());
while(it<start+clustersize){
preference.add(((StandardEntity) preferences.get(it)).getID());
it++;
//System.out.println(preferences.get(it).getID().getValue());
}
}
@Override
public void doDefaultSearch() {
if (LOGGER.isTraceEnabled()) {
LOGGER.trace("Starting search.");
Collection<EntityID> unknown = worldModel.getUnknownBuildings();
Collection<EntityID> safeUnsearched = worldModel
.getSafeUnsearchedBuildings();
LOGGER.trace("Unknown: " + unknown.toString());
LOGGER.trace("Safe Unsearched: " + safeUnsearched.toString());
}
//create merged list of safeUnsearched and unknown with start of unknown at divider
ArrayList<EntityID> buildings = new ArrayList<EntityID>();
buildings.addAll(worldModel.getSafeUnsearchedBuildings());
int divider = buildings.size();
buildings.addAll(worldModel.getUnknownBuildings());
//restrict to my search preferences
ArrayList<EntityID> preferenceList = modulatedList(buildings);
/*System.out.println("Agent"+myself.getValue());
for(int i=0;i<preference.size();i++){
System.out.println(preference.get(i).getValue());
}
System.out.println("pref list");
for(int i=0;i<preferenceList.size();i++){
System.out.println(preferenceList.get(i).getValue());
}*/
IPath searchPath = visitClosestBuilding(preferenceList,divider);
if (!searchPath.isValid()) {
if (blockades) {
searchPath = goToClosestUnseenRoad();
if (!searchPath.isValid()) {
// System.out.println("no close road");
searchPath = goToRandomLocation();
}
} else {
searchPath = goToRandomLocation();
}
}
MoveCommand move = new MoveCommand(searchPath);
if (searchPath.getLocations().size() > 0) {
executionService.execute(move);
}
}
/*
* keeps only buildings in my preference set (or if empty original list)
*/
private ArrayList<EntityID> modulatedList(ArrayList<EntityID> buildings) {
ArrayList<EntityID> copy = (ArrayList<EntityID>) buildings.clone();
ArrayList<EntityID> ret = new ArrayList<EntityID>();
for(int i=0;i<buildings.size();i++){
if(preference.contains(buildings.get(i))){
ret.add(buildings.get(i));
}
}
if(buildings.size()>0){
//System.out.println("should be ok");
return ret;
} else {
return copy;
}
}
private IPath visitClosestBuilding(ArrayList<EntityID> buildings, int index) {
if (buildings.size() > 0) {
IPath path = routingModule.findShortestPath(myself, buildings);
if (path.isValid()) {
List<EntityID> locations = path.getLocations();
EntityID destination = locations.get(locations.size()-1);
int pos = buildings.indexOf(destination);
if(pos<index){
//safeUnsearched
return path;
} else {
//unKnown
List<PositionXY> positions = path.getXYPath();
locations = locations.subList(0, locations.size() - 1);
positions = positions.subList(0, positions.size() - 1);
return new Path(locations, positions);
}
} else {
return Path.INVALID_PATH;
}
}else{
return Path.INVALID_PATH;
}
}
/**
* @return
*/
private IPath goToRandomLocation() {
EntityID id = ((Human) worldModel.getEntity(myself)).getPosition();
Area area = (Area) worldModel.getEntity(id);
List<EntityID> neighbours = area.getNeighbours();
IPath path = routingModule.findShortestPath(myself, neighbours);
if (!path.isValid()) {
List<EntityID> locations = new FastList<EntityID>();
locations.add(id);
List<PositionXY> positions = new FastList<PositionXY>();
positions.add(new PositionXY(((Human) worldModel.getEntity(myself))
.getLocation(worldModel)));
positions.add(positions.get(0));
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Staying on " + area + " using path: "
+ path.toString());
}
return new Path(locations, positions);
} else {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Going from " + area + " using path: "
+ path.toString());
}
return path;
}
}
/**
* @return
*/
private IPath goToClosestUnseenRoad() {
Collection<StandardEntity> roads = worldModel
.getEntitiesOfType(StandardEntityURN.ROAD);
Collection<EntityID> unseenRoads = new FastList<EntityID>();
for (StandardEntity road : roads) {
Road r = (Road) road;
if (!r.isBlockadesDefined()) {
unseenRoads.add(r.getID());
}
}
if (unseenRoads.size() > 0) {
IPath path = routingModule.findShortestPath(myself, unseenRoads);
if (LOGGER.isDebugEnabled() && path.isValid()) {
LOGGER.debug("Going to unknown road "
+ worldModel.getEntity(
path.getLocations().get(
path.getLocations().size() - 1))
.getFullDescription() + " from "
+ worldModel.getEntity(myself).getFullDescription()
+ " on "
+ worldModel.getEntity(myself).getFullDescription()
+ " using path: " + path.toString());
}
// System.out.println("GOing to unknown road: " +
// worldModel.getEntity(path.getLocations().get(path.getLocations().size()-1)).getFullDescription());
return path;
} else {
return Path.INVALID_PATH;
}
}
/**
* @return
*/
private IPath goToClosestUnseenBuilding() {
Collection<EntityID> unsearched = worldModel.getUnknownBuildings();
if (unsearched.size() > 0) {
IPath path = routingModule.findShortestPath(myself, unsearched);
if (path.isValid()) {
List<EntityID> locations = path.getLocations();
List<PositionXY> positions = path.getXYPath();
locations = locations.subList(0, locations.size() - 1);
positions = positions.subList(0, positions.size() - 1);
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Going outside unsafe building "
+ worldModel.getEntity(
path.getLocations().get(
path.getLocations().size() - 1))
.getFullDescription() + " from "
+ worldModel.getEntity(myself).getFullDescription()
+ " using path: " + path.toString());
}
// System.out.println("GOing outside unsafe bulding: " +
// path.getLocations().get(path.getLocations().size()-1));
return new Path(locations, positions);
}
}
return Path.INVALID_PATH;
}
/**
* @return
*/
private IPath goInsideClosestUnsearchedBuilding() {
Collection<EntityID> unsearched = worldModel
.getSafeUnsearchedBuildings();
if (unsearched.size() > 0) {
IPath path = routingModule.findShortestPath(myself, unsearched);
if (LOGGER.isDebugEnabled() && path.isValid()) {
LOGGER.debug("Going inside safe building "
+ worldModel.getEntity(
path.getLocations().get(
path.getLocations().size() - 1))
.getFullDescription() + " from "
+ worldModel.getEntity(myself).getFullDescription()
+ " using path: " + path.toString());
}
// System.out.println("GOing inside a safe bulding: " +
// worldModel.getEntity(path.getLocations().get(path.getLocations().size()-1)).getFullDescription());
return path;
} else {
return Path.INVALID_PATH;
}
}
}