/* DESCRIPTION: * This method implements the A Algorithm. * Uses direct distance to the final city as a heuristic. * At each step finds the best next city to explore from citiesToExplore. * Finds the cities connected to it and examines them. * If the connected city is already found, then it examines is the new path to * it shorter than the already known one. If it is, than it renew the information * about the city in foundCities and citiesToExplore. * If the city has not been found yet, then it add it to citiesToExplore and * foundCities. * When all cities have been explored it finds the minimal path using the idea * that if the city B preceds the destination city A in the minimum path, * then the minimum path also includes the minimum path from the start city * to B. Thus, it goes from city to city in the reverse order and adds them * to the minimum path. */ public List <City> FindOptimalPath() { City nextCity; // Next city to explore CityInfo nextCityInfo; // Next city information List <City> nextCityConnections; // Connections of the nextCity CityInfo nextConnectedCityInfo; // Information about the currently examined city connected to nextCity CityInfo nextConnectedCityOldInfo; // Old information about the currently examined city Coordinates tempStartPoint, tempEndPoint; // Help variables. Store points on the map. City tempCity, tempPrevCity; // Help variables. Store consecutive sities in the optimal path CityInfo tempCityInfo; // Help variable. Stores a city's info LogManager logManager = new LogManager(textBoxLog); // Log manager bool finalCityIsFound = false; // Flag that we found the final city double distanceToFinal = -1; // Length of the found path to the final city // Print log - algorithm start logManager.Clear(); logManager.PrintStartAlg(StartCity, FinalCity, AlgHeuristic); // Start with the start city:)) nextCity = StartCity; nextCityInfo = new CityInfo(StartCity, null, FinalCity, GetCityCoordinates(StartCity), null, GetCityCoordinates(FinalCity), 0, AlgHeuristic); // Initialize foundCities = new Dictionary <City, CityInfo>(); citiesToExplore = new Dictionary <City, CityInfo>(); // Add the start city foundCities.Add(nextCity, nextCityInfo); citiesToExplore.Add(nextCity, nextCityInfo); // While we have cities to explore while (citiesToExplore.Count != 0) { // Print log logManager.PrintFoundExploredCities(); // Clean the layout graphManager.UnmarkAllCities(graphLayout); graphManager.UnmarkAllEdges(graphLayout); // Highlighting graphManager.MarkAllFoundCities(new List <City>(foundCities.Keys), graphLayout); graphManager.MarkAllCitiesToExplore(new List <City>(citiesToExplore.Keys), graphLayout); graphManager.MarkStartCity(StartCity, graphLayout); graphManager.MarkFinalCity(FinalCity, graphLayout); // Wait Wait(); // Find the next best city among citiesToExplore nextCity = FindBestCity(citiesToExplore); // Get its info citiesToExplore.TryGetValue(nextCity, out nextCityInfo); // Stop if all the estimates are greater than the found path length if (finalCityIsFound) { if (nextCityInfo.PathDistance >= distanceToFinal) { break; } } // Get the nextCity connections citiesConnecitons.connections.TryGetValue(nextCity, out nextCityConnections); // Print log - next city to explore logManager.PrintBestCity(nextCity, nextCityInfo); // Highlighting - next city to explore graphManager.UnmarkAllCities(graphLayout); graphManager.UnmarkAllEdges(graphLayout); graphManager.MarkBestCity(nextCity, graphLayout); // Print log - city connections logManager.PrintCityConnections(nextCityConnections); // Highlighting - city connections graphManager.MarkEdges(nextCity, nextCityConnections, graphLayout); graphManager.MarkAllCheckedCities(nextCityConnections, graphLayout); Wait(); // Examine all the connections of the nextCity foreach (City nextConnectedCity in nextCityConnections) { // Get the examined city location and the nextCity location citiesLocations.locations.TryGetValue(nextCity, out tempStartPoint); citiesLocations.locations.TryGetValue(nextConnectedCity, out tempEndPoint); // Create information about the currently examined city if (AlgHeuristic == Heuristic.Distance) { nextConnectedCityInfo = new CityInfo(nextConnectedCity, nextCity, FinalCity, tempEndPoint, tempStartPoint, GetCityCoordinates(FinalCity), FindDistance(tempStartPoint, tempEndPoint) + nextCityInfo.FromStart, AlgHeuristic); } // If we use number of hops as a heuristic else { nextConnectedCityInfo = new CityInfo(nextConnectedCity, nextCity, FinalCity, tempEndPoint, tempStartPoint, GetCityCoordinates(FinalCity), 1 + nextCityInfo.FromStart, AlgHeuristic); } // If the examined city has already been found. // If the current path is better, then update the city's info if (foundCities.ContainsKey(nextConnectedCity)) { // Get the city's old info from foundCities foundCities.TryGetValue(nextConnectedCity, out nextConnectedCityOldInfo); // Compare its old path distance to the new path distance if (nextConnectedCityInfo.PathDistance < nextConnectedCityOldInfo.PathDistance) { // Print log - updated city logManager.PrintUpdatedCity(nextConnectedCity, nextConnectedCityInfo, nextConnectedCityOldInfo); // Highlighting - updated city graphManager.MarkUpdatedCity(nextConnectedCity, graphLayout); // Update the info if the new path is shorter nextConnectedCityOldInfo.PrevCity = nextConnectedCityInfo.PrevCity; nextConnectedCityOldInfo.FromStart = nextConnectedCityInfo.FromStart; // If we updated the final city (found a better path) if (nextConnectedCity.Equals(FinalCity)) { distanceToFinal = nextConnectedCityInfo.FromStart; } } else { // Print log - rejected city logManager.PrintRejectedCity(nextConnectedCity, nextConnectedCityInfo, nextConnectedCityOldInfo); // Highlighting - rejected city graphManager.MarkRejectedCity(nextConnectedCity, graphLayout); } } // If we have not found this city so far. // Add it to foundCities and citiesToExplore. else { // Add the city to foundCities and citiesToExplore. foundCities.Add(nextConnectedCity, nextConnectedCityInfo); citiesToExplore.Add(nextConnectedCity, nextConnectedCityInfo); // Print log - added city logManager.PrintAddedCity(nextConnectedCity, nextConnectedCityInfo); // Highlighting - added city graphManager.MarkAddedCity(nextConnectedCity, graphLayout); // Check wether we added the desired final city if (!finalCityIsFound) { if (nextConnectedCity.Equals(FinalCity)) { finalCityIsFound = true; distanceToFinal = nextConnectedCityInfo.FromStart; } } } } // Wait Wait(); // Mark nextCity as explored. // Remove it from citiesToExplore nextCityInfo.IsExplored = true; citiesToExplore.Remove(nextCity); } // If we were able to reach the destination, // then construct the optimal path. if (foundCities.ContainsKey(FinalCity)) { // Start with the end city tempCity = FinalCity; // Get the end city info foundCities.TryGetValue(tempCity, out tempCityInfo); // Initialize List <City> optimalPath = new List <City>(); // Add the end city to the optimal path optimalPath.Add(tempCity); // Set the city that preceds the end city in the optimal path tempPrevCity = tempCityInfo.PrevCity; // While we have not reached the start city while (tempPrevCity != null) { // Add the city that preceds the current city in the optimal path tempCity = tempPrevCity; optimalPath.Add(tempCity); // Move to the previous city in the path in order to // add it in the next loop iteration. foundCities.TryGetValue(tempCity, out tempCityInfo); tempPrevCity = tempCityInfo.PrevCity; } // Reverse the list ReverseListOrder(ref optimalPath); // Print log - optimal path logManager.PrintPath(optimalPath, Algorithm.CalculateTotalPath(optimalPath, citiesLocations)); // Highlighting - optimal path graphManager.UnmarkAllCities(graphLayout); graphManager.UnmarkAllEdges(graphLayout); graphManager.MarkPath(optimalPath, graphLayout); // Print log - end of the algorithm logManager.PrintEndAlg(true); return(optimalPath); } // Output an error if the destination could not be reached. else { // Highlighting graphManager.UnmarkAllCities(graphLayout); graphManager.UnmarkAllEdges(graphLayout); graphManager.MarkStartCity(StartCity, graphLayout); graphManager.MarkFinalCity(FinalCity, graphLayout); // Print log - end of the algorithm logManager.PrintEndAlg(false); // Output an error that the path was not found MessageBox.Show("Cannot find a path between the chosen cities.", "Path Finder", MessageBoxButton.OK, MessageBoxImage.Warning); return(null); } }
/// <summary> /// Stop the algorithm execution and kill the algorithm thread /// </summary> public void StopAlgorithm() { if (algThread != null) { algThread.Abort(); } if (algorithm != null) { algorithm.IsRunning = false; algorithm = null; } }
public LogicManager(MainWindow _window) { graphToVisualize = null; citiesLocations = null; citiesConnections = null; defaultCitiesLocations = new CitiesLocations(); defaultCitiesConnections = new CitiesConnections(); algCitiesLocations = new CitiesLocations(); startCity = null; finalCity = null; algSpeed = Alg_Speed.Fast; algHeuristic = Heuristic.Distance; resources = _window.Resources; window = _window; graphManager = new GraphManager(window); algorithm = null; algThread = null; IsRunningAlg = false; }
/// <summary> /// Start A-star algorithm in a separate thread /// </summary> /// <param name="graphLayout"></param> /// <param name="richTextBoxLog"></param> /// <param name="window"></param> public void StartAlgorithm(ref GraphLayoutCity graphLayout, ref TextBox richTextBoxLog, MainWindow window) { // If already running if (IsRunningAlg) { algorithm.WaitMutex.WaitOne(); algorithm.CanContinue = true; algorithm.WaitMutex.ReleaseMutex(); } // If not, then start a new thread else { algorithm = new Algorithm(citiesLocations, citiesConnections, startCity.City, finalCity.City, algSpeed, algHeuristic, ref graphLayout, ref richTextBoxLog, resources, graphManager); // Set window and create a mutex algorithm.Window = window; algorithm.WaitMutex = new Mutex(); // Null the start and end cities startCity = null; finalCity = null; // Create and start the thread algThread = new Thread(new ThreadStart(algorithm.RunAlgThread)); algThread.SetApartmentState(ApartmentState.STA); algThread.Start(); // Allow the algorithm to continue algorithm.WaitMutex.WaitOne(); algorithm.CanContinue = true; algorithm.WaitMutex.ReleaseMutex(); } }