//-------------------------------------------------------------------------------------------------------------------------------- private void EvaluateAirport(AirportData airportData, AStarNode node) { if (airportData == null || node == null) { return; } ulong loaded = node.loaded; ulong unloaded = node.unloaded; if (EvaluateLoad(airportData, routes, ref loaded, ref unloaded)) { AStarNode nextNode = new AStarNode(node, airportData) { loaded = loaded, unloaded = unloaded }; nextNode.costFromStart = CalculateCost(nextNode); nextNode.estimatedCost = EstimateCost(nextNode, routes); nextNode.totalCost = nextNode.costFromStart + nextNode.estimatedCost; lock (listLock) { openList.Add(nextNode); } } }
//-------------------------------------------------------------------------------------------------------------------------------- private void CreateUniqueAirports(IDictionary <string, AirportData> airports) { uniqueAirports.Clear(); for (int i = 0; i < routes.Count; ++i) { Route route = routes[i]; if (!uniqueAirports.ContainsKey(route.from.ICAO)) { uniqueAirports.Add(route.from.ICAO, airports[route.from.ICAO]); } if (!uniqueAirports.ContainsKey(route.to.ICAO)) { uniqueAirports.Add(routes[i].to.ICAO, airports[route.to.ICAO]); } } allRoutesFlag = 0; for (int i = 0; i < routes.Count; ++i) { allRoutesFlag |= BIT << i; } if (Verbose) { Debug.WriteLine(string.Format("Unique airports: {0}", uniqueAirports.Count)); foreach (var kv in uniqueAirports) { AirportData airportData = kv.Value; Debug.WriteLine(string.Format(" {0} {1}", airportData.ICAO, airportData.name)); } } }
//-------------------------------------------------------------------------------------------------------------------------------- public int DistanceTo(AirportData other) { var d1 = latitude * (Math.PI / 180.0); var num1 = longitude * (Math.PI / 180.0); var d2 = other.latitude * (Math.PI / 180.0); var num2 = other.longitude * (Math.PI / 180.0) - num1; var d3 = Math.Pow(Math.Sin((d2 - d1) / 2.0), 2.0) + Math.Cos(d1) * Math.Cos(d2) * Math.Pow(Math.Sin(num2 / 2.0), 2.0); var dist = 6376500.0 * (2.0 * Math.Atan2(Math.Sqrt(d3), Math.Sqrt(1.0 - d3))); return((int)Math.Round(dist * 0.000539957)); }
//-------------------------------------------------------------------------------------------------------------------------------- private void DebugPrintFlightPlan(IList <FlightPlanLeg> flightPlan) { Debug.WriteLine(string.Format("Legs: {0}", flightPlan.Count - 1)); int totalDistance = 0; for (int i = 1; i < flightPlan.Count; ++i) { FlightPlanLeg parent = flightPlan[i - 1]; AirportData from = flightPlan[i - 1].airportData; AirportData to = flightPlan[i].airportData; int distance = from.DistanceTo(to); Debug.WriteLine(string.Format(" {0} -> {1} : {2,5}nm {3,6}lb {4,3}pax", from.ICAO, to.ICAO, distance, parent.cargo, parent.passenger)); totalDistance += distance; } Debug.WriteLine(string.Format(" total : {0}nm", totalDistance)); }
//-------------------------------------------------------------------------------------------------------------------------------- static AirportData() { airports.Clear(); using (TextFieldParser textFieldParser = new TextFieldParser(airportData)) { textFieldParser.SetDelimiters(","); while (!textFieldParser.EndOfData) { string[] elements = textFieldParser.ReadFields(); if (elements != null && elements.Length == 12 && elements[0].Length <= 4) { AirportData airportData = new AirportData(elements); airports.Add(airportData.ICAO, airportData); } } } }
//-------------------------------------------------------------------------------------------------------------------------------- private void EvaluateCargoChange(AirportData airportData, IList <Route> routes, ref ulong loaded, ref int cargo, ref int passenger) { for (int i = 0; i < routes.Count; ++i) { Route route = routes[i]; bool isLoaded = (loaded & (BIT << i)) != 0; if (!isLoaded && route.from == airportData) { cargo += route.cargo; passenger += route.passenger; loaded |= BIT << i; } else if (isLoaded && route.to == airportData) { cargo -= route.cargo; passenger -= route.passenger; } } }
//-------------------------------------------------------------------------------------------------------------------------------- // Check if this airport will do anything useful, e.g. loading or unloading cargo/passengers for a route //-------------------------------------------------------------------------------------------------------------------------------- private bool EvaluateLoad(AirportData airportData, IList <Route> routes, ref ulong loaded, ref ulong unloaded) { bool changedLoad = false; for (int i = 0; i < routes.Count; ++i) { Route route = routes[i]; ulong flag = BIT << i; // already 'done' this route (unloaded cargo) ? if ((unloaded & flag) != 0) { continue; } // load cargo/passengers here? if (route.from == airportData && ((loaded & flag) == 0)) { loaded |= flag; changedLoad = true; } // nothing loaded for this route, no need to test it any further if ((loaded & flag) == 0) { continue; } // unload cargo here? if (route.to == airportData && ((unloaded & flag) == 0)) { unloaded |= flag; changedLoad = true; } } return(changedLoad); }
//-------------------------------------------------------------------------------------------------------------------------------- private void DebugPrintRoutes() { Debug.WriteLine(string.Format("Routes: {0}", routes.Count)); int totalDistance = 0; for (int i = 0; i < routes.Count; ++i) { Route route = routes[i]; AirportData from = route.from; AirportData to = route.to; int distance = route.Distance; Debug.WriteLine(string.Format(" {0} -> {1} : {2,5}nm {3,6}lb {4,3}pax", from.ICAO, to.ICAO, distance, route.cargo, route.passenger)); totalDistance += distance; if (i > 0) { if (routes[i - 1].to != from) { totalDistance += routes[i - 1].to.DistanceTo(from); } } } Debug.WriteLine(string.Format(" total : {0,5}nm", totalDistance)); }
//-------------------------------------------------------------------------------------------------------------------------------- private void Search() { workerThreads = new Thread[uniqueAirports.Count - 1]; threadData = new ThreadData[workerThreads.Length]; lockThreadData = new object[workerThreads.Length]; for (int i = 0; i < workerThreads.Length; ++i) { workerThreads[i] = new Thread(EvaluateAirportThread); threadData[i] = new ThreadData(); lockThreadData[i] = new object(); workerThreads[i].Start(threadData[i]); } while (ContinueSearch) { AStarNode node = PopFromOpenList(); if (node == null) { break; } RoutesComplete = 100.0f * CountCompleteRoutes(node) / routes.Count; if (Verbose) { Debug.WriteLine(node.ToString(routes.Count)); } if (IsPlanValid(node)) { targetNode = node; break; } int index = 0; foreach (var kv in uniqueAirports) { AirportData airportData = kv.Value; if (node.airportData == airportData) { continue; } lock (lockThreadData[index]) { threadData[index].airportData = airportData; threadData[index].node = node; } ++index; } bool isDone = false; while (!isDone) { isDone = true; for (int i = 0; i < threadData.Length; ++i) { if (!threadData[i].isDone) { isDone = false; break; } } if (!isDone) { Thread.Sleep(0); } } openList.Sort(CompareNodes); for (int i = 0; i < threadData.Length; ++i) { lock (lockThreadData[i]) { threadData[i].airportData = null; threadData[i].node = null; threadData[i].isDone = false; } } Thread.Sleep(0); } ContinueSearch = false; if (Verbose) { Debug.WriteLine("------------------------------------------------------------"); } }