package cz.agents.agentpolis.darptestbed.simmodel.agent.driver.logic; import com.google.common.collect.Maps; import cz.agents.agentpolis.darptestbed.global.Utils; import cz.agents.agentpolis.darptestbed.siminfrastructure.communication.passenger.message.DriverArrivedMessage; import cz.agents.agentpolis.darptestbed.siminfrastructure.communication.passenger.message.Proposal; import cz.agents.agentpolis.darptestbed.siminfrastructure.communication.passenger.protocol.PassengerMessageProtocol; import cz.agents.agentpolis.darptestbed.siminfrastructure.communication.protocol.GeneralMessageProtocol; import cz.agents.agentpolis.darptestbed.siminfrastructure.communication.receiver.StringMessage; import cz.agents.agentpolis.darptestbed.simmodel.agent.data.Request; import cz.agents.agentpolis.darptestbed.simmodel.agent.data.TripInfo; import cz.agents.agentpolis.darptestbed.simmodel.agent.data.TripPlan; import cz.agents.agentpolis.darptestbed.simmodel.agent.data.generator.PassengersInAndOutPair; import cz.agents.agentpolis.darptestbed.simmodel.entity.vehicle.TestbedVehicle; import cz.agents.agentpolis.darptestbed.simmodel.environment.model.TestbedModel; import cz.agents.agentpolis.siminfrastructure.planner.trip.Trip; import cz.agents.agentpolis.siminfrastructure.planner.trip.Trips; import cz.agents.agentpolis.simmodel.agent.activity.movement.DriveVehicleActivity; import cz.agents.agentpolis.simmodel.environment.model.citymodel.transportnetwork.AllNetworkNodes; import cz.agents.agentpolis.simmodel.environment.model.query.AgentPositionQuery; import java.util.Arrays; import java.util.HashSet; import java.util.Map; /** * Example of decentralized control mechanism. Related classes: PassengerDecentralizedLogicExample */ public class DriverDecentralizedLogicExample extends DriverDecentralizedLogic { public DriverDecentralizedLogicExample(String agentId, PassengerMessageProtocol sender, GeneralMessageProtocol generalMessageProtocol, TestbedModel taxiModel, AgentPositionQuery positionQuery, AllNetworkNodes allNetworkNodes, Utils utils, TestbedVehicle vehicle, DriveVehicleActivity drivingActivity) { super(agentId, sender, generalMessageProtocol, taxiModel, positionQuery, allNetworkNodes, utils, vehicle, drivingActivity); } // If we receive a request from the passenger ... @Override public void processNewRequest(Request request) { // debug output LOGGER.info("Request: [" + utils.toHoursAndMinutes(request.getTimeWindow().getEarliestDeparture()) + "] " + request.getPassengerId() + "->" + this.getAgentId() + ", latest departure: " + utils.toHoursAndMinutes(request.getTimeWindow().getLatestDeparture())); // if we don't have some of the requested special equipment (wheelchair support, etc.), reject the request if (!this.getVehicle().getVehicleEquipments().containsAll(request.getAdditionalRequirements())) { sendRequestRejectionToPassenger(request); return; } // if we already have a passenger on board, reject this request if (this.getCurrentPassengersOnBoard() > 0) { sendRequestRejectionToPassenger(request); return; } // if we currently have a trip plan which is not empty, reject this request if (this.getTripPlan() != null && this.getTripPlan().getTrips().numTrips() > 0) { sendRequestRejectionToPassenger(request); return; } // if we're already busy doing something, reject the request if (this.isBusy()) { sendRequestRejectionToPassenger(request); return; } // compute the driving time between the passenger and the driver double timeToPassenger = utils.computeDrivingTime(this.getAgentId(), request.getPassengerId()); // estimate when this driver could pick the passenger up long pickUpTime = Math.max(request.getTimeWindow().getEarliestDeparture(), utils.getCurrentTime() + Math.round(timeToPassenger)); // compute the driving time between the passenger's origin and destination double timeToDrive = utils.computeDrivingTime(request.getFromNode(), request.getToNode()); // estimate when this driver could drop the passenger off long dropOffTime = pickUpTime + Math.round(timeToDrive); // if this driver is able to pick the passenger up in time & drop him off in time ... if ((pickUpTime <= request.getTimeWindow().getLatestDeparture()) && (dropOffTime <= request.getTimeWindow().getLatestArrival())) { // send a proposal to the passenger this.sendProposalToPassenger(new Proposal(request, this.getAgentId(), this.getVehicle().getId())); // while we're waiting for the reply, flag ourselves as "busy", so we won't accept new requests this.setBusy(); } else { // otherwise, if we can't possibly satisfy this request within specified time windows, send a rejection sendRequestRejectionToPassenger(request); } } // If passenger accepts our proposal... @Override public void processNewAcceptance(Proposal proposal) { // original request Request request = proposal.getRequest(); // plan the trips (paths) // (1) from driver to passenger's departure node and // (2) from origin to arrival node Trip toPassenger = utils.planTrip(this.getVehicle().getId(), this.getCurrentPositionNode(), request.getFromNode()); Trip toDestination = utils.planTrip(this.getVehicle().getId(), request.getFromNode(), request.getToNode()); // concatenate those two trips into a drivePath for the driver Trips drivePath = new Trips(); if (toPassenger != null && toPassenger.numOfCurrentTripItems() > 1) drivePath.addTrip(toPassenger); if (toDestination != null && toDestination.numOfCurrentTripItems() > 1) drivePath.addTrip(toDestination); // if we didn't successfully find and concatenate two required trips reject the request (we can't find a way to fulfill it) if (drivePath.numTrips() != 2) { // send a rejection sendRequestRejectionToPassenger(request); // flag ourselves as "free" again this.setFree(); return; } // create a pickup map for this path (tells driver where he should pick up which passengers) Map<Long, PassengersInAndOutPair> pickUpAndDropOffMap = Maps.newHashMap(); pickUpAndDropOffMap.put(request.getFromNode(), new PassengersInAndOutPair(new HashSet<>(Arrays.asList(request.getPassengerId())), new HashSet<String>())); pickUpAndDropOffMap.put(request.getToNode(), new PassengersInAndOutPair(new HashSet<String>(), new HashSet<>(Arrays.asList(request.getPassengerId())))); // set the trip plan for the driver TripPlan tripPlan = new TripPlan(drivePath, pickUpAndDropOffMap); this.setTripPlan(tripPlan); LOGGER.info("Setting trip plan for " + this.getAgentId() + " (" + this.getCurrentPassengersOnBoard() + "/" + this.getVehicle().getCapacity() + ") to:\n\n" + tripPlan); // start driving driveNextPartOfTripPlan(); } // Process a rejection obtained by the passenger (not used in this example - passengers accept everything). @Override public void processNewRejection(Proposal proposal) { } // This is called by a timer at regular intervals. // You can use this instead of processNewRequest() if you want to store the requests in some array/queue and select among them. @Override public void processRequests() { } // This is called by a timer at regular intervals. @Override public void processAcceptancesAndRejections() { } // Notify the passenger that the taxi arrived, so he can get in. @Override protected void sendTaxiArrivedToPickup(String passengerId) { sender.sendMessage(passengerId, new DriverArrivedMessage(getAgentId(), new TripInfo(getAgentId(), this.getVehicle().getId()))); } @Override protected void sendTaxiArrivedToDropOff(String passengerId) { sender.sendMessage(passengerId, new DriverArrivedMessage(getAgentId(), new TripInfo(getAgentId(), this.getVehicle().getId()))); } @Override protected void sendTaxiArrivedLateMessageToDispatching(String passengerId) { } }