package Agents.Behaviour;
import Agents.Attributes.AgentAttributes;
import Agents.Attributes.VehicleAttributes;
import Entity.TrafficLight;
import GeographicInformation.Cell;
import GlobalData.Constants;
import GlobalData.SharedData;
import java.util.ArrayList;
/**
* This is the move behaviour for a vehicle agent. A vehicle "moves" by changing
* its current occupying cell to the next one in its list of the safest path.
*/
public class VehicleMoveBehaviour implements VehicleBehaviour {
//If capacity == Load
/**
* The vehicle agent attribute
*/
VehicleAttributes runAttributes;
/**
* Check if the agent is done executing.
*/
boolean flag;
/**
* Run the behaviour of the agent with the given attributes.
* @param agentAttributes the agent's attributes
*/
public void run(AgentAttributes agentAttributes) {
runAttributes = (VehicleAttributes) agentAttributes;
move();
}
/**
* Simple DEBUG move method for traversiong the cells
* Note this is methods does not make use of cell occupancy.
*/
private void moveCell() {
if (!runAttributes.shouldMove) {
return;
}
//runAttributes.currentCellLocation.setOccupied(false); //leave the current cell
if (checkTrafficLightStatus()) {
runAttributes.currentCellLocation = runAttributes.bestRouteToHome.get(runAttributes.currentCellIndex);//move to next one
runAttributes.currentCellIndex += runAttributes.SPEED;
if (runAttributes.currentCellIndex >= runAttributes.bestRouteToHome.size()) {
runAttributes.currentCellIndex = runAttributes.bestRouteToHome.size() - 1;
}
Utilities.Log.logger.info("index: " + runAttributes.currentCellIndex + " moved to:" + runAttributes.currentCellLocation.toString());
} else {
Utilities.Log.logger.info("index: " + runAttributes.currentCellIndex + " moved to:" + runAttributes.currentCellLocation.toString() + "Because of Light");
}
//runAttributes.currentCellLocation.setOccupied(true);//set the occupancy
}
/**
* Simple move method for traversiong the cells
*/
private void move() {
if (!runAttributes.shouldMove) {
return;
}
//runAttributes.currentCellLocation.setOccupied(false); //leave the current cell
if (checkTrafficLightStatusOnRoad()) {
//Signal is clear to move
runAttributes.currentCellLocation = runAttributes.bestRouteToHome.get(runAttributes.currentCellIndex);//move to next one
//Check if the cell is occupied
/*check is the vehicle can move that far.
* if yes, then check if its occupid.
* If no, chcek if destination is occupied.
* NOTE: No action for a occupied cell.
* TODO: Reduce speed of vehicle or other alternatives for
* a occupied cell.
*/
//int futureCellIndex = runAttributes.currentCellIndex + runAttributes.SPEED; //The location where the agent will potentially move to
int futureCellIndex = getNearestUnoccupiedCell(runAttributes.SPEED, runAttributes.bestRouteToHome, runAttributes.currentCellIndex);//Check if the location exists...
//if (runAttributes.bestRouteToHome.size() >= futureCellIndex) {
//Location exists
// if ((runAttributes.bestRouteToHome.get(futureCellIndex).isOccupied())) {
// //Cell is occupied dont move
// Utilities.Log.logger.info("index: " + runAttributes.currentCellIndex + " moved to:" + runAttributes.currentCellLocation.toString() + " Because cell is occupied");
// } else {
// runAttributes.currentCellLocation.setOccupied(false); //leave the current cell
// runAttributes.currentCellIndex += runAttributes.SPEED;
// runAttributes.currentCellLocation.setOccupied(true); //set the current cell occupancy.
// if (runAttributes.currentCellIndex >= runAttributes.bestRouteToHome.size()) {
// runAttributes.currentCellIndex = runAttributes.bestRouteToHome.size() - 1;
// }
// Utilities.Log.logger.info("index: " + runAttributes.currentCellIndex + " moved to:" + runAttributes.currentCellLocation.toString());
// }
/* Set the cell as occupied and verify the return value. If setting fails then stay in current
* location.
*/
if (runAttributes.bestRouteToHome.get(futureCellIndex).updateOccupiedFlagInDB(true)) { //IF successfully changed
runAttributes.currentCellLocation.updateOccupiedFlagInDB(false); //leave the current cell
runAttributes.currentCellIndex = futureCellIndex;
runAttributes.currentCellLocation = runAttributes.bestRouteToHome.get(futureCellIndex); // change current location
Utilities.Log.logger.info("index: " + runAttributes.currentCellIndex + " moved to:" + runAttributes.currentCellLocation.toString());
} else {
Utilities.Log.logger.info(" Could not move as the set occupied failed on cell id = " + (runAttributes.bestRouteToHome.get(futureCellIndex)).getId());
}
// } else { //The speed overshoots the home location. Hence move to last location
//
// Utilities.Log.logger.info("index: " + runAttributes.currentCellIndex + " moved to:" + runAttributes.currentCellLocation.toString() + " Direct Jump Home");
// }
//runAttributes.currentCellLocation.setOccupied(true);//set the occupancy
}
}
/**
* This function returns the nearest un-occupied cell form current location to the home
* given the vehicle speed. This can be interpreted as a reduction in speed.
* @param vehicleSpeed the speed of the vehicle
* @param bestRouteHome the list of cells that the vehicle follows to reach home.
* @return the nearest unoccupied cell form current cell.
*
*/
private int getNearestUnoccupiedCell(int vehicleSpeed, ArrayList<Cell> bestRouteHome, int currentCellIndex) {
int probableCell = currentCellIndex + vehicleSpeed;//The location where the agent will potentially move to
// Check if the vehicle overshoots the home base
if (probableCell >= bestRouteHome.size() - 1) {
probableCell = bestRouteHome.size() - 1;
}
//Check occupancy
for (int i = (currentCellIndex + 1); i < probableCell; i++) {
if (bestRouteHome.get(i).isOccupied()) {
return i - 1;
}
}
return probableCell;
}
private boolean checkTrafficLightStatusOnRoad() {
// //Get the current cell in which the vehicle is located from its best route.
// Cell possibility = runAttributes.bestRouteToHome.get(runAttributes.currentCellIndex);
//
// //From the list of traffic lights find the nearest traffic light located nearest to this cell.
// //If the traffic light is at a distance of more that OBEY_TRAFFIC_LIGHT_DISTANCE cells then
// //ignore the traffic light else check the color of the light.
// for (TrafficLight l : SharedData.trafficLights) {
// if (l.getLocation().getLatLon().distance(possibility.getLatLon()) > Constants.OBEY_TRAFFIC_LIGHT_DISTANCE) {
// //Light is too far. Ignore the traffic light.
// return true;
// } else {
// if (l.getColor() == GlobalData.Constants.SIGNAL_GREEN) {
// return true;
// }
// }
// }
// return false;
return true;
}
/**
* This function checks if there are any traffic light around and checks if
* the traffic light rules have to be followed.
* NOTE: The function cannot identity the exactly which road the traffic
* light controls. But generally follows the nearest traffic light. This
* may lead to semantic errors in future.
* @return
*/
//TODO: Better algorithm for traffic light rules
private boolean checkTrafficLightStatus() {
//Get the current cell in which the vehicle is located from its best route.
Cell possibility = runAttributes.bestRouteToHome.get(runAttributes.currentCellIndex);
//From the list of traffic lights find the nearest traffic light located nearest to this cell.
//If the traffic light is at a distance of more that OBEY_TRAFFIC_LIGHT_DISTANCE cells then
//ignore the traffic light else check the color of the light.
for (TrafficLight l : SharedData.trafficLights) {
if (l.getLocation().getLatLon().distance(possibility.getLatLon()) > Constants.OBEY_TRAFFIC_LIGHT_DISTANCE) {
//Light is too far. Ignore the traffic light.
return true;
} else {
if (l.getColor() == GlobalData.Constants.SIGNAL_GREEN) {
return true;
}
}
}
return false;
}
// public void decideWhereToMove() {
// //Utilities.Log.logger.info(this.AID + " : Identifying destination");
// //Check if disaster has been triggered
// //go home if not, otherwise decide where to go
// if (!SharedData.isDisasterTriggered) {
// //Utilities.Log.logger.info("I'm happy in a peaceful city");
// return;
// } else {
// // based on curiosity run towards disaster
// double distancetodisaster;
// double distancetohospital = -10;
//
// Point disasterlocation = SharedData.disasters.get(0).getLatlon();
//
// Point closesthospitallocation = runAttributes.homeBase.getLatLon();
//
// distancetodisaster = (Math.pow(runAttributes.currentCellLocation.getLatLon().x - disasterlocation.x, 2) + Math.pow(runAttributes.currentCellLocation.getLatLon().y - disasterlocation.y, 2));
// // Utilities.Log.logger.info("Distance to disaster = " + distancetodisaster);
//
// Iterator<Hospital> iterator = SharedData.hospitals.iterator();
//
// //Utilities.Log.logger.info("Number of hospitals: " + SharedData.hospitals.size());
//
// //identify closest hospital
// double newdistance = 0;
// while (iterator.hasNext()) {
// Hospital target = iterator.next();
//
// Point targetlocation = target.getLatLon();
//
// newdistance = (Math.pow(runAttributes.currentCellLocation.getLatLon().x - targetlocation.x, 2) + Math.pow(runAttributes.currentCellLocation.getLatLon().y - targetlocation.y, 2));
//
// if (newdistance < distancetohospital || distancetohospital < 0) {
// closesthospitallocation = targetlocation;
// distancetohospital = newdistance;
// }
// }
// Utilities.Log.logger.info("Distance to closest hospital = " + distancetohospital);
//compare if hospital and disaster based on curiosity
// double curiousdisasterdistance = distancetodisaster * (100 - runAttributes.CURIOSITY);
// double curioushospitaldistance = distancetohospital * runAttributes.CURIOSITY;
//
// if (curiousdisasterdistance < curioushospitaldistance) {
// runAttributes.homeBase.setLatLon(disasterlocation);
// //Utilities.Log.logger.info("Moving to disaster");
// } else {
// runAttributes.homeBase.setLatLon(closesthospitallocation);
// // Utilities.Log.logger.info("Moving to Hospital");
// }
//
// }
// }
}