Спасибо за все вклады. Я провел исследование и написал свой собственный код для решения этой проблемы. Это довольно сложно :(:
function loadUnits(originalPassengersAndVehicles) {
// this function takes care of everything required to load any selected passenger(s) into the destination vehicle(s)
var vehicles = []; // an array of all transport vehicles
var passengers = []; // an array of all passengers
var passengerVehicleDistances = []; // an array of the distance between all passengers and all vehicles. this is a 2-dimensional array, with the first dimension being all passengers and the second dimension being the distance between all vehicles for those passengers
var unitsAndDestinations = []; // an array of all valid passengers and their destination (which should be a vehicle's position)
var loadingNumbers = []; // store the number of units loading into the vehicles
var errorMessage = "";
var distance, currentPassenger;
// store the vehicle(s) location as the destination
var destination = {
lat: null,
lng: null
};
function smallestValue() {
// this function iterates over the passengerVehicleDistances array to find the passenger which is closest to a vehicle. it ignores any distances that are negative, since these would be passengers that are flagged as boarding/boarded
var returnValue = {
distance: 2000, // used as a comparison of passengers' shortest distances to vehicles in the passengerVehicleDistances array. we set the value to double passenger's maximum move distance
passengerIndex: -1, // used to store the passenger index of the shortest distance between a passenger and a vehicle in the passengerVehicleDistances array
vehicleIndex: -1 // used to store the vehicle index of the shortest distance between a passenger and a vehicle in the passengerVehicleDistances array
};
for (var i = 0; i < passengers.length; i++) {
for (var j = 0; j < vehicles.length; j++) {
if (passengerVehicleDistances[i][j] < returnValue.distance &&
passengerVehicleDistances[i][j] > 0) {
returnValue.distance = passengerVehicleDistances[i][j];
returnValue.passengerIndex = i;
returnValue.vehicleIndex = j;
}
}
}
return returnValue;
}
// iterate through all selected passengers and assign valid transport vehicles to the vehicles array and valid passenger to the passengers array
for (var key in originalPassengersAndVehicles) {
if (originalPassengersAndVehicles.hasOwnProperty(key)) {
if (originalPassengersAndVehicles[key].userID == gv.user.ID &&
originalPassengersAndVehicles[key].selected) {
if (originalPassengersAndVehicles[key].capacity > 0) {
// if the vehicle is moving, show an error message and don't assign it to the vehicles array
if (originalPassengersAndVehicles[key].moving) {
errorMessage = "Cannot load passenger into a moving " + originalPassengersAndVehicles[key].type + ".";
clickedError(originalPassengersAndVehicles[key].position, -30, 0, errorMessage);
continue;
}
// if the vehicle is currently full, show an error message and don't assign it to the vehicles array
if (originalPassengersAndVehicles[key].occupants >= originalPassengersAndVehicles[key].capacity) {
errorMessage = capitalizeFirstLetter(originalPassengersAndVehicles[key].type) + " is full.";
clickedError(originalPassengersAndVehicles[key].position, -20, 0, errorMessage);
continue;
}
vehicles.push(key); // add this vehicle to the array
loadingNumbers.push(0); // add another array element to loading numbers for this vehicle
}
else if (originalPassengersAndVehicles[key].type == "passenger") {
// if the passenger is already being loaded into another vehicle, show an error message and don't assign it to the passengers array
if (originalPassengersAndVehicles[key].loading.length > 0) {
errorMessage = "That passenger passenger is already boarding another vehicle.";
clickedError(originalPassengersAndVehicles[key].position, -30, 0, errorMessage);
continue;
}
// if the passenger is already onboard another vehicle, show an error message and don't assign it to the passengers array. note that this is the same procedure as above, but we want to show a different error message
if (originalPassengersAndVehicles[key].holding.length > 0) {
errorMessage = "That passenger passenger is already in another vehicle.";
clickedError(originalPassengersAndVehicles[key].position, -30, 0, errorMessage);
continue;
}
passengers.push(key); // add this passenger to the array
passengerVehicleDistances.push([]); // add an empty array element to the passengers and vehicles distance array for each vehicle to be processed below
}
}
}
}
// if either passengers or vehicles are empty, show an error message, disable the load button to prevent the player clicking it again (i.e. force him to try a different selection), and quit this function
if (vehicles.length == 0) {
errorMessage = "No valid vehicles selected to load passenger.";
clickedError(gv.map.getCenter(), 0, 0, errorMessage);
gv.o("transportIcon").style.display = "none"; // hide the load icon
return;
}
if (passengers.length == 0) {
errorMessage = "No valid passenger selected to board vehicles.";
clickedError(gv.map.getCenter(), 0, 0, errorMessage);
gv.o("transportIcon").style.display = "none"; // hide the load icon
return;
}
// iterate over the passengers and vehicles arrays and calculate the distances between each passenger and each vehicle. this loop generates the passengerVehicleDistances array, which then needs to be processed for assigning passengers to vehicles
for (var i = 0; i < passengers.length; i++) {
for (var j = 0; j < vehicles.length; j++) {
// calculate the distance between the passenger's current position and the vehicle's current position
distance = google.maps.geometry.spherical.computeDistanceBetween(originalPassengersAndVehicles[passengers[i]].position, originalPassengersAndVehicles[vehicles[j]].position); // in metres
passengerVehicleDistances[i].push(distance); // add the distance to the array
}
}
// calculate the best apportionment of passengers to vehicles. passengers should move to their closest vehicles until that vehicle is full
for (var i = 0; i < passengers.length; i++) {
currentPassenger = smallestValue(); // iterate over our passengerVehicleDistances array and find the passenger closest to a vehicle who hasn't yet been processed. note that we don't use i below, as the iteration over this loop isn't the same as the current closest passenger index
// first we check for -1 in passenger and vehicle indices. if this is the case, then smallestValue() has not found any values in passengerVehicleDistances so we can stop the loop and process unitsAndDestinations
if (currentPassenger.passengerIndex == -1 && currentPassenger.vehicleIndex == -1) {
break; // end the loop since there are no longer any valid distances in passengerVehicleDistances
}
// check the vehicle this passenger has been assigned to. if it's now full, show an error message and invalidate all distances related to it in passengerVehicleDistances
if (originalPassengersAndVehicles[vehicles[currentPassenger.vehicleIndex]].occupants >= originalPassengersAndVehicles[vehicles[currentPassenger.vehicleIndex]].capacity) {
for (var j = 0; j < passengerVehicleDistances.length; j++) {
passengerVehicleDistances[j][currentPassenger.vehicleIndex] = -1;
}
errorMessage = capitalizeFirstLetter(originalPassengersAndVehicles[vehicles[currentPassenger.vehicleIndex]].type) + " is full.";
clickedError(originalPassengersAndVehicles[passengers[currentPassenger.passengerIndex]].position, -20, 0, errorMessage);
continue;
}
// check if this passenger will fit into this vehicle based on the vehicle's current occpants, units currently boarding and its capacity. first, we calculate the true loading figure as we can't just count the loading array as each unitID may be a passenger group
loadingNumbers[currentPassenger.vehicleIndex] += originalPassengersAndVehicles[passengers[currentPassenger.passengerIndex]].totalUnits;
// then we add the vehicle's current occupants with the loading number and check if loading this passenger would put it over capacity. if the passenger can board, but the vehicle will be full when this passenger boards, invalidate all distances related to this vehicle in passengerVehicleDistances
if (originalPassengersAndVehicles[vehicles[currentPassenger.vehicleIndex]].occupants + loadingNumbers[currentPassenger.vehicleIndex] > originalPassengersAndVehicles[vehicles[currentPassenger.vehicleIndex]].capacity) {
// the passenger cannot board (i.e. its totalUnits is greater than available capacity). ideally, in this circumstance the passenger should try to board all other vehicles in ascending distance order. if it can't board any other vehicle, then we can remove the passenger from processing
// insert code here
for (var j = 0; j < passengerVehicleDistances.length; j++) {
passengerVehicleDistances[j][currentPassenger.vehicleIndex] = -1;
}
errorMessage = capitalizeFirstLetter(originalPassengersAndVehicles[vehicles[currentPassenger.vehicleIndex]].type) + " will be full.";
clickedError(originalPassengersAndVehicles[passengers[currentPassenger.passengerIndex]].position, -20, 0, errorMessage);
continue;
}
// if this distance is too far, then the distance to every other vehicle will also be too far
if (currentPassenger.distance > originalPassengersAndVehicles[passengers[i]].range_move) {
// show an error message
errorMessage = "This passenger is too far to load.";
clickedError(originalPassengersAndVehicles[passengers[currentPassenger.passengerIndex]].position, -10, 0, errorMessage);
// remove the passenger from the distances array so that it's not processed again
for (var j = 0; j < passengerVehicleDistances[currentPassenger.passengerIndex].length; j++) {
passengerVehicleDistances[currentPassenger.passengerIndex][j] = -1;
}
continue;
}
// only add the passenger to the vehicle if it passes the above checks (within movement range, vehicle not currently full or will be full). move this passenger directly to its closest vehicle (i.e. directly to the same grid square occupied by the vehicle)
destination.lat = roundToDecimal(originalPassengersAndVehicles[vehicles[currentPassenger.vehicleIndex]].position.lat() - (gv.gridUnit / 2), 6);
destination.lng = roundToDecimal(originalPassengersAndVehicles[vehicles[currentPassenger.vehicleIndex]].position.lng() - (gv.gridUnit / 2), 6);
// if we are ok to load, add the passenger to unitsAndDestinations
unitsAndDestinations.push([passengers[currentPassenger.passengerIndex], destination]);
// remove the passenger from the distances array so that it's not processed again
for (var j = 0; j < passengerVehicleDistances[currentPassenger.passengerIndex].length; j++) {
passengerVehicleDistances[currentPassenger.passengerIndex][j] = -1;
}
// flag the transport vehicle as loading the units
originalPassengersAndVehicles[vehicles[currentPassenger.vehicleIndex]].loading.push(passengers[currentPassenger.passengerIndex]);
// flag the passenger as boarding the vehicle
originalPassengersAndVehicles[passengers[currentPassenger.passengerIndex]].loading.push(vehicles[currentPassenger.vehicleIndex]);
}
// only send something to the server and update the client if at least 1 passenger can be vaildly loaded
if (unitsAndDestinations.length > 0) {
// send the array of units and their destinations to the server for checking and database updating
serverProcessing(unitsAndDestinations);
gv.o("transportIcon").style.display = "none"; // hide the load icon
}
}
Это чистая реализация JavaScript, но я проверил ее в своем приложении, и она работает (насколько я вижу). Надеюсь, кто-то еще найдет код полезный.
Ура, Arj