public void Min_FibonacciHeap_Test() { int nodeCount = 1000 * 10; var minHeap = new FibonacciHeap <int>(); for (int i = 0; i <= nodeCount; i++) { minHeap.Insert(i); } for (int i = 0; i <= nodeCount; i++) { minHeap.UpdateKey(i, i - 1); } int min = 0; for (int i = 0; i <= nodeCount; i++) { min = minHeap.Extract(); Assert.AreEqual(min, i - 1); } //IEnumerable tests. Assert.AreEqual(minHeap.Count, minHeap.Count()); var rnd = new Random(); var testSeries = Enumerable.Range(0, nodeCount - 1).OrderBy(x => rnd.Next()).ToList(); foreach (var item in testSeries) { minHeap.Insert(item); } for (int i = 0; i < testSeries.Count; i++) { var decremented = testSeries[i] - rnd.Next(0, 1000); minHeap.UpdateKey(testSeries[i], decremented); testSeries[i] = decremented; } testSeries.Sort(); for (int i = 0; i < nodeCount - 2; i++) { min = minHeap.Extract(); Assert.AreEqual(testSeries[i], min); } //IEnumerable tests. Assert.AreEqual(minHeap.Count, minHeap.Count()); }
public void Max_FibonacciHeap_Test() { int nodeCount = 1000 * 10; var maxHeap = new FibonacciHeap <int>(SortDirection.Descending); for (int i = 0; i <= nodeCount; i++) { maxHeap.Insert(i); } for (int i = 0; i <= nodeCount; i++) { maxHeap.UpdateKey(i, i + 1); } int max = 0; for (int i = nodeCount; i >= 0; i--) { max = maxHeap.Extract(); Assert.AreEqual(max, i + 1); } //IEnumerable tests. Assert.AreEqual(maxHeap.Count, maxHeap.Count()); var rnd = new Random(); var testSeries = Enumerable.Range(0, nodeCount - 1).OrderBy(x => rnd.Next()).ToList(); foreach (var item in testSeries) { maxHeap.Insert(item); } for (int i = 0; i < testSeries.Count; i++) { var incremented = testSeries[i] + rnd.Next(0, 1000); maxHeap.UpdateKey(testSeries[i], incremented); testSeries[i] = incremented; } testSeries = testSeries.OrderByDescending(x => x).ToList(); for (int i = 0; i < nodeCount - 2; i++) { max = maxHeap.Extract(); Assert.AreEqual(testSeries[i], max); } //IEnumerable tests. Assert.AreEqual(maxHeap.Count, maxHeap.Count()); }
/// <summary> /// Uses A*-algorithm to find the best route between two tiles. /// </summary> /// <param name="start">First tile to search from.</param> /// <param name="goal">Goal to find.</param> /// <param name="previous">Tile just before the first tile.</param> /// <param name="forbidden">List of tiles that should be never used on route.</param> /// <param name="sign">Optional function for building signs.</param> /// <returns></returns> internal static List <PathInfo> FindPath(TileIndex start, TileIndex goal, TileIndex previous, HashSet <TileIndex> forbidden = null, Action <TileIndex, string> sign = null) { // Nodes to evaluate var tilesToProcess = new FibonacciHeap <TileIndex>(); tilesToProcess.Insert(start, 0); // Nodes evaluated var cameFrom = new Dictionary <TileIndex, PathInfo>(); cameFrom[start] = new PathInfo(start, 1, 0, BuildType.Basic, previous != null ? new PathInfo(previous, 1, 0, BuildType.Basic, null) : null); while (tilesToProcess.Count() > 0) { var current = tilesToProcess.Pop(); //AILog.Info($"Processing: {Helper.FormatTile(current)}"); if (current == goal) { // We found the target. return(RoadBuilder.BuildFinalPath(cameFrom[current])); } var neighbors = RoadBuilder.GetNeighbors(current, cameFrom[current]); foreach (var neighborItem in neighbors) { var neighbor = neighborItem.Tile; if ((neighbor == previous) || ((forbidden != null) && forbidden.Contains(neighbor))) { // We can't go here. continue; } var neighborDist = neighborItem.Length; if (!cameFrom.ContainsKey(neighbor)) { tilesToProcess.Insert(neighbor, neighborItem.Cost); } else { if (neighborItem.Cost >= cameFrom[neighbor].Cost) { continue; } } sign?.Invoke(neighbor, neighborItem.Cost.ToString()); cameFrom[neighbor] = neighborItem; } } return(null); }