private IDirectedPath GetPath() { VectorGoal = Target.Coords.Canon - Source.Coords.Canon; OpenSet = new HashSet <HexCoords>(); Queue = new DictionaryPriorityQueue <int, IDirectedPath>(); TraceFindPathDetailInit(Source.Coords, Target.Coords); Queue.Enqueue(0, new DirectedPath(Target)); HexKeyValuePair <int, IDirectedPath> item; while (Queue.TryDequeue(out item)) { var path = item.Value; var step = path.PathStep.Hex; OpenSet.Add(step.Coords); if (ClosedSet.Contains(step.Coords)) { continue; } TraceFindPathDequeue("Rev", step.Coords, path.TotalCost, path.HexsideExit, item.Key >> 16, (int)((int)(item.Key & 0xFFFFu) - 0x7FFF)); if (step.Equals(Source)) { return(path); } ClosedSet.Add(step.Coords); foreach (var neighbour in Board.GetNeighbourHexes(step)) { ExpandNeighbour(path, neighbour); } } return(null); }
/// <summary>Returns an <c>IPath</c> for the optimal path from coordinates <c>start</c> to <c>goal</c>.</summary> /// <param name="start">Coordinates for the <c>last</c> step on the desired path.</param> /// <param name="goal">Coordinates for the <c>first</c> step on the desired path.</param> /// <param name="stepCost">Cost to extend path by hex at <c>coords</c> from hex at direction <c>hexside</c>.</param> /// <param name="heuristic">Returns a monotonic (ie locally admissible) cost estimate from a range value.</param> /// <returns></returns> /// ///<remarks>Note that <c>heuristic</c> <b>must</b> be monotonic in order for the algorithm to perform properly.</remarks> #pragma warning disable 1658, 1584 /// <seealso cref="http://www.cs.trincoll.edu/~ram/cpsc352/notes/astar.html"/> #pragma warning restore 1658, 1584 public static IDirectedPath FindDirectedPathFwd( IHex start, IHex goal, Func <IHex, Hexside, int> stepCost, Func <int, int> heuristic ) { if (start == null) { throw new ArgumentNullException("start"); } if (goal == null) { throw new ArgumentNullException("goal"); } if (stepCost == null) { throw new ArgumentNullException("stepCost"); } var vectorGoal = goal.Coords.Canon - start.Coords.Canon; var closed = new HashSet <HexCoords>(); var open = new HashSet <HexCoords>(); var queue = new DictionaryPriorityQueue <int, DirectedPath>(); TraceFlags.FindPathDetail.Trace(true, "Find path from {0} to {1}; vectorGoal = {2}", start.Coords, goal.Coords, vectorGoal); queue.Enqueue(0, new DirectedPath(goal)); HexKeyValuePair <int, DirectedPath> item; while (queue.TryDequeue(out item)) { var path = item.Value; open.Add(path.PathStep.Hex.Coords); if (closed.Contains(path.PathStep.Hex.Coords)) { continue; } TraceFlags.FindPathDequeue.Trace( "Dequeue Path at {0} w/ cost={1,4} at {2}; estimate={3,4}:{4,4}.", path.PathStep.Hex.Coords, path.TotalCost, path.HexsideExit, item.Key >> 16, (int)((int)(item.Key & 0xFFFFu) - 0x7FFF)); if (path.PathStep.Hex.Equals(start)) { TraceFlags.FindPathDequeue.Trace("Closed: {0,7}", closed.Count); return(path); } closed.Add(path.PathStep.Hex.Coords); foreach (var neighbour in path.PathStep.Hex.GetNeighbourHexes() ) { if (!open.Contains(neighbour.Hex.Coords)) { var cost = stepCost(neighbour.Hex, neighbour.HexsideExit); if (cost > 0) { var newPath = path.AddStep(neighbour, cost); var key = Estimate(heuristic, vectorGoal, start.Coords, neighbour.Hex.Coords, newPath.TotalCost); TraceFlags.FindPathEnqueue.Trace(" Enqueue {0}: estimate={1,4}:{2,3}", neighbour.Hex.Coords, key >> 16, key & 0xFFFFu); queue.Enqueue(key, newPath); } } } } return(null); }