/** * Implementation of <b>Dijkstra's algorithm</b>. * * @param sourceDisplacement : source <b>Coordinate</b>. * @param destinationDisplacement : destination <b>Coordinate</b>. * @param avoidGuardian : a boolean which indicates whether to consider <b>Guardians</b> (<code> * true</code>) or not (<code>false</code>) when calculating the route. (Used to calculate a * route patrol regardless of the position of <b>Guardians</b>). * @return a list containing <b>Coordinates</b> steps to move from source <b>Coordinate</b> * (included) to destination <b>Coordinate</b> (included). */ public ArrayList<Coordinate> routeCalculation( Coordinate sourceDisplacement, Coordinate destinationDisplacement, boolean avoidGuardian) { if (areAdjacent(sourceDisplacement, destinationDisplacement) && grid.isValidGuardian(destinationDisplacement)) { ArrayList<Coordinate> route = new ArrayList<Coordinate>(); route.add(sourceDisplacement); route.add(destinationDisplacement); return route; } // INITIALISATION // toutes les coordonnes valables int dimension = grid.getDimension(); Coordinate coordinates[][] = new Coordinate[dimension][dimension]; for (int i = 0; i < dimension; i++) { for (int j = 0; j < dimension; j++) { coordinates[i][j] = new Coordinate(i, j); } } // Coordonnees : la coordonee (cle) dont on connait la plus petite // distance (valeur) a la source HashMap<Coordinate, Integer> distanceSource = new HashMap<Coordinate, Integer>(); // Coordonnees : les coordonnes dont il faut verifier la distance ArrayList<Coordinate> coordinatesToCheck = new ArrayList<Coordinate>(); // Coordonnees : les coordonnes dont on a verifié la distance ArrayList<Coordinate> coordinatesChecked = new ArrayList<Coordinate>(); // tableau contenant l'ordre des cases pour le (un des) plus court // chemin pour chaque case // 1ere coordonnee (cle) : coordonnee dont on veut connaitre le // predecesseur // 2em coordonee (valeur) : predecesseur de la coordonnee cle HashMap<Coordinate, Coordinate> predecessorCoordinate = new HashMap<Coordinate, Coordinate>(); // source du deplacement Coordinate source = coordinates[sourceDisplacement.getCoordX()][sourceDisplacement.getCoordY()]; // initialisation/remplissage de parcours for (int i = 0; i < dimension; i++) { for (int j = 0; j < dimension; j++) { predecessorCoordinate.put(coordinates[i][j], source); distanceSource.put(coordinates[i][j], Integer.MAX_VALUE); } } // ajout de la source dans la Hashmap avec une distance nulle distanceSource.put(source, 0); // ajout de la source a l'arraylist des cases verifiees, et le reste // dans l'arraylist des cases � verifier for (int i = 0; i < dimension; i++) { for (int j = 0; j < dimension; j++) { if (avoidGuardian) { if (grid.isValidGuardian(coordinates[i][j])) coordinatesToCheck.add(coordinates[i][j]); } else { if (grid.isValid(coordinates[i][j])) coordinatesToCheck.add(coordinates[i][j]); } } } coordinatesToCheck.remove(source); coordinatesChecked.add(source); // FIN INITIALISATION // pour chaque case valable de la grille for (int i = 0; i < coordinatesChecked.size(); i++) { Coordinate coordSource = coordinatesChecked.get(i); for (int j = 0; j < coordinatesToCheck.size(); j++) { Coordinate coordEnCoursDeVerif = coordinatesToCheck.get(j); if (areAdjacent(coordSource, coordEnCoursDeVerif)) { coordinatesToCheck.remove(coordEnCoursDeVerif); coordinatesChecked.add(coordEnCoursDeVerif); j--; if (distanceSource.get(coordEnCoursDeVerif) > distanceSource.get(predecessorCoordinate.get(coordSource)) + 1) { distanceSource.put(coordEnCoursDeVerif, distanceSource.get(coordSource) + 1); predecessorCoordinate.put(coordEnCoursDeVerif, coordSource); // System.out.println("Coordonnee : " + coordEnCoursDeVerif + " --- distance a la // source "+ source +" : " + // distanceSource.get(coordEnCoursDeVerif) + " --- predecesseur pour chemin le // plus court : "+ // parcours.get(coordEnCoursDeVerif)+" destination "+destination); // Coordonnee : (10,17) --- distance a la source : 27 --- predecesseur pour // chemin le plus court : (9,17) } } } } // construire chemin ArrayList<Coordinate> reverseRoute = new ArrayList<Coordinate>(); ArrayList<Coordinate> route = new ArrayList<Coordinate>(); Coordinate coordTemp = coordinates[destinationDisplacement.getCoordX()][destinationDisplacement.getCoordY()]; reverseRoute.add(destinationDisplacement); while (!(predecessorCoordinate.get(coordTemp).equals(source))) { reverseRoute.add(predecessorCoordinate.get(coordTemp)); coordTemp = predecessorCoordinate.get((coordTemp)); } reverseRoute.add(source); for (int i = 0; i < reverseRoute.size(); i++) { route.add(reverseRoute.get(reverseRoute.size() - i - 1)); } // itineraire.get(0) = coordSource // itineraire.get(itineraire.size()-1) = destination return route; }
/** * Calculates patrol's <b>Coordinates</b>.</br> * * @param guardians : a list of <b>Guardians</b> to share the patrol. * @return a list containing the <b>Coordinates</b> checkpoints of the patrol. (Debug) */ public ArrayList<Coordinate> calculCoordinatesPatrouille(ArrayList<Guardian> guardians) { // long debut = System.currentTimeMillis(); int dimension = grid.getDimension(); // ArrayList de coordonnees pour l'itineraire de patrouille ArrayList<Coordinate> validCoordinates = new ArrayList<Coordinate>(); // ArrayList de coordonnees pour l'itineraire de patrouille // HashMap de coordonnees, et de l'ArrayList contenant le champ de vision a partir de cette // coordoneee HashMap<Coordinate, ArrayList<Coordinate>> visible = new HashMap<Coordinate, ArrayList<Coordinate>>(); // init ArrayList, tableau et HashMap for (int i = 0; i < dimension; i++) { for (int j = 0; j < dimension; j++) { Coordinate coordTemp = new Coordinate(i, j); // System.out.println(grid); if (grid.isValid(coordTemp) && grid.isDirectlyAccessible(coordTemp)) { validCoordinates.add(coordTemp); visible.put(coordTemp, visualFieldCalculation(coordTemp)); } } } // Remplissage d'une HashMap avec les gardians pour Cle, et une ArrayList de coordonnees // atteignables en Valeur HashMap<Guardian, ArrayList<Coordinate>> guardianToCoordinates = new HashMap<Guardian, ArrayList<Coordinate>>(); for (Guardian guard : guardians) { ArrayList<Coordinate> accessibleCoordinatesGuardian = new ArrayList<Coordinate>(); for (Coordinate coord : validCoordinates) { ArrayList<Coordinate> itineraireTemp = routeCalculation(guard.getPosition(), coord, false); if (itineraireTemp.size() > 2 || areAdjacent(guard.getPosition(), coord)) // Coord accessible accessibleCoordinatesGuardian.add(coord); } accessibleCoordinatesGuardian.add(guard.getPosition()); Collections.sort(accessibleCoordinatesGuardian, new Tri.SortByCoordinate()); guardianToCoordinates.put(guard, accessibleCoordinatesGuardian); } // System.out.println(guardianVersCoordinates); // System.out.println(); // System.out.println(); // Fusion en ArrayList si plusieurs gardiens ont les mêmes coordonnees atteignables HashMap<ArrayList<Coordinate>, ArrayList<Guardian>> coordinatesToGuardians = new HashMap<ArrayList<Coordinate>, ArrayList<Guardian>>(); for (Guardian guard : guardians) { ArrayList<Guardian> guardiansCoord = coordinatesToGuardians.get(guardianToCoordinates.get(guard)); if (guardiansCoord == null) { guardiansCoord = new ArrayList<Guardian>(); } if (!guardiansCoord.contains(guard)) guardiansCoord.add(guard); coordinatesToGuardians.put(guardianToCoordinates.get(guard), guardiansCoord); } // System.out.println(coordinatesVersGuardian); // A ce moment, coordinatesVersGuardian contient des ArrayList de coordonnees atteignables // comme clé, // et des ArrayList des guardiens qui peuvent les atteindre comme valeur // HashMap inverse de CoordinatesVersGuardians HashMap<ArrayList<Guardian>, ArrayList<Coordinate>> guardiansToCoordinates = new HashMap<ArrayList<Guardian>, ArrayList<Coordinate>>(); for (ArrayList<Coordinate> alCoord : coordinatesToGuardians.keySet()) { guardiansToCoordinates.put(coordinatesToGuardians.get(alCoord), alCoord); } // initialisation des coordonnes a visiter pour effectuer la patrouille (checkpoint) // ne represente pas l'itineraire // ne garde que quelques coordonnes cles ArrayList<Coordinate> patrolCoordinates = new ArrayList<Coordinate>(validCoordinates); // calculer si un ensemble d'ArrayList de coordonnees ne contiendrait pas par hasard toutes les // coordonnees visibles depuis une certaine coordonnee // calculer si le fait de supprimer une coordonnee enleve des cases visibles a l'ArrayList for (int i = 0; i < patrolCoordinates.size(); i++) { ArrayList<Coordinate> coordinatesMinusOne = new ArrayList<Coordinate>(); ArrayList<Coordinate> unsortedVisibleCoordinatesMinusOne = new ArrayList<Coordinate>(); ArrayList<Coordinate> sortedVisibleCoordinatesMinusOne = new ArrayList<Coordinate>(); for (Coordinate coordTest : patrolCoordinates) { coordinatesMinusOne.add(coordTest); } Coordinate coordReference = patrolCoordinates.get(i); coordinatesMinusOne.remove(coordReference); for (Coordinate coordTemp : coordinatesMinusOne) { unsortedVisibleCoordinatesMinusOne.addAll(visible.get(coordTemp)); } Set<Coordinate> mySet = new HashSet<Coordinate>(unsortedVisibleCoordinatesMinusOne); sortedVisibleCoordinatesMinusOne.addAll(mySet); if (sortedVisibleCoordinatesMinusOne.containsAll(validCoordinates)) { patrolCoordinates.remove(coordReference); i--; } } return patrolCoordinates; }
/** * Calculates patrol routes (depending on reachable <b>Coordinates</b> by <b>Guardian</b>) to see * all the <b>Grid</b>.</br> A patrol route is then assigned to each <b>Guardian</b> (If several * <b>Guardians</b> have access to the same <b>Coordinates</b>, their patrol will be the same). * * @param guardians : a list of <b>Guardians</b> in order to directly assign their patrol route. * @return a list containing all the <b>Coordinates</b> of all the patrols routes. (Debug) */ public ArrayList<Coordinate> patrolRouteCalculation(ArrayList<Guardian> guardians) { // long debut = System.currentTimeMillis(); int dimension = grid.getDimension(); // ArrayList de coordonnees pour l'itineraire de patrouille ArrayList<Coordinate> validCoordinates = new ArrayList<Coordinate>(); // ArrayList de coordonnees pour l'itineraire de patrouille // HashMap de coordonnees, et de l'ArrayList contenant le champ de vision a partir de cette // coordoneee HashMap<Coordinate, ArrayList<Coordinate>> visible = new HashMap<Coordinate, ArrayList<Coordinate>>(); // init ArrayList, tableau et HashMap for (int i = 0; i < dimension; i++) { for (int j = 0; j < dimension; j++) { Coordinate coordTemp = new Coordinate(i, j); // System.out.println(grid); if (grid.isValid(coordTemp) && grid.isDirectlyAccessible(coordTemp)) { validCoordinates.add(coordTemp); visible.put(coordTemp, visualFieldCalculation(coordTemp)); } } } // Remplissage d'une HashMap avec les gardians pour Cle, et une ArrayList de coordonnees // atteignables en Valeur HashMap<Guardian, ArrayList<Coordinate>> guardianToCoordinates = new HashMap<Guardian, ArrayList<Coordinate>>(); for (Guardian guard : guardians) { ArrayList<Coordinate> accessibleCoordinatesGuardian = new ArrayList<Coordinate>(); for (Coordinate coord : validCoordinates) { ArrayList<Coordinate> itineraireTemp = routeCalculation(guard.getPosition(), coord, false); if (itineraireTemp.size() > 2 || areAdjacent(guard.getPosition(), coord)) // Coord accessible accessibleCoordinatesGuardian.add(coord); } accessibleCoordinatesGuardian.add(guard.getPosition()); Collections.sort(accessibleCoordinatesGuardian, new Tri.SortByCoordinate()); guardianToCoordinates.put(guard, accessibleCoordinatesGuardian); } // System.out.println(guardianVersCoordinates); // System.out.println(); // System.out.println(); // Fusion en ArrayList si plusieurs gardiens ont les mêmes coordonnees atteignables HashMap<ArrayList<Coordinate>, ArrayList<Guardian>> coordinatesToGuardians = new HashMap<ArrayList<Coordinate>, ArrayList<Guardian>>(); for (Guardian guard : guardians) { ArrayList<Guardian> guardiansCoord = coordinatesToGuardians.get(guardianToCoordinates.get(guard)); if (guardiansCoord == null) { guardiansCoord = new ArrayList<Guardian>(); } if (!guardiansCoord.contains(guard)) guardiansCoord.add(guard); coordinatesToGuardians.put(guardianToCoordinates.get(guard), guardiansCoord); } // System.out.println(coordinatesVersGuardian); // A ce moment, coordinatesVersGuardian contient des ArrayList de coordonnees atteignables // comme clé, // et des ArrayList des guardiens qui peuvent les atteindre comme valeur // HashMap inverse de CoordinatesVersGuardians HashMap<ArrayList<Guardian>, ArrayList<Coordinate>> guardiansToCoordinates = new HashMap<ArrayList<Guardian>, ArrayList<Coordinate>>(); for (ArrayList<Coordinate> alCoord : coordinatesToGuardians.keySet()) { guardiansToCoordinates.put(coordinatesToGuardians.get(alCoord), alCoord); } // initialisation des coordonnes a visiter pour effectuer la patrouille (checkpoint) // ne represente pas l'itineraire // ne garde que quelques coordonnes cles ArrayList<Coordinate> globalPatrolCoordinates = new ArrayList<Coordinate>(validCoordinates); // calculer si un ensemble d'ArrayList de coordonnees ne contiendrait pas par hasard toutes les // coordonnees visibles depuis une certaine coordonnee // calculer si le fait de supprimer une coordonnee enleve des cases visibles a l'ArrayList for (int i = 0; i < globalPatrolCoordinates.size(); i++) { ArrayList<Coordinate> coordinatesMinusOne = new ArrayList<Coordinate>(); ArrayList<Coordinate> unsortedVisibleCoordinatesMinusOne = new ArrayList<Coordinate>(); ArrayList<Coordinate> sortedVisibleCoordinatesMinusOne = new ArrayList<Coordinate>(); for (Coordinate coordTest : globalPatrolCoordinates) { coordinatesMinusOne.add(coordTest); } Coordinate coordReference = globalPatrolCoordinates.get(i); coordinatesMinusOne.remove(coordReference); for (Coordinate coordTemp : coordinatesMinusOne) { unsortedVisibleCoordinatesMinusOne.addAll(visible.get(coordTemp)); } Set<Coordinate> mySet = new HashSet<Coordinate>(unsortedVisibleCoordinatesMinusOne); sortedVisibleCoordinatesMinusOne.addAll(mySet); if (sortedVisibleCoordinatesMinusOne.containsAll(validCoordinates)) { globalPatrolCoordinates.remove(coordReference); i--; } } ArrayList<Coordinate> allPatrolsRoutes = new ArrayList<Coordinate>(); // debut boucle for (ArrayList<Guardian> alGuardian : coordinatesToGuardians.values()) { // On ne garde que les coordonnees atteignables par le groupe de gardiens ArrayList<Coordinate> groupPatrolCoordinates = new ArrayList<Coordinate>(globalPatrolCoordinates); // for(Coordinates coord : coordinatesPatrouilleGroupe) { // if(!guardiansVersCoordinates.get(alGuardian).contains(coord)) // coordinatesPatrouilleGroupe.remove(coord); // } for (int i = 0; i < groupPatrolCoordinates.size(); i++) { Coordinate coord = groupPatrolCoordinates.get(i); if (!guardiansToCoordinates.get(alGuardian).contains(coord)) { groupPatrolCoordinates.remove(coord); i--; } } TreeMap<Integer, Coordinate> patrolRoute = new TreeMap<Integer, Coordinate>(); // Si aucun checkpoint accessible if (groupPatrolCoordinates.size() == 0) { for (Guardian guardTemp : alGuardian) { guardTemp.setPatrolPosition(-2); } } else { ArrayList<Coordinate> routeFinal = new ArrayList<Coordinate>(); ArrayList<Coordinate> routeTemp = new ArrayList<Coordinate>(); Coordinate coordSource = groupPatrolCoordinates.get(0); Coordinate coordSourceTemp = coordSource; Coordinate coordTemp = null; int index = 0; while (groupPatrolCoordinates.size() > 0) { groupPatrolCoordinates.remove(coordSourceTemp); routeFinal.clear(); routeTemp.clear(); for (Coordinate coordDestinationTemp : groupPatrolCoordinates) { routeTemp = routeCalculation(coordSourceTemp, coordDestinationTemp, false); // System.out.println("Itineraire " + coordSourceTemp + " vers " + coordDestinationTemp // + " : " + itineraireTemp); if (routeFinal.size() == 0 || (routeTemp.size() != 0 && routeTemp.size() < routeFinal.size())) { routeFinal = new ArrayList<Coordinate>(routeTemp); coordTemp = coordDestinationTemp; } } // System.out.println(itineraireFinal); coordSourceTemp = coordTemp; for (int i = 0; i < routeFinal.size() - 1; i++) { patrolRoute.put(index, routeFinal.get(i)); index++; } } // Ajout de l'itineraire pour aller e la fin de la patrouille vers le debut routeFinal = routeCalculation(coordTemp, coordSource, false); for (int i = 0; i < routeFinal.size() - 1; i++) { patrolRoute.put(index, routeFinal.get(i)); index++; } // affectation de la patrouille a tous les gardiens, a modifier for (Guardian guardTemp : alGuardian) { guardTemp.setPatrol(patrolRoute); guardTemp.setReachableCoordinates(guardiansToCoordinates.get(alGuardian)); } allPatrolsRoutes.addAll(patrolRoute.values()); } // fin boucle } // entre 100 et 1000ms en fonction de la taille (complexite lineaire) // System.out.println(System.currentTimeMillis() - debut); // System.out.println(itinerairePatrouille); return allPatrolsRoutes; }