/// <param name="coords">The <see cref="HexCoords"/> for this landmark.</param> /// <param name="board">IBoard{IHex} on which the landmark is to be created.</param> /// <param name="queueFactory">TODO</param> private static IList <DirectedLandmark> BackingStore(HexCoords coords, INavigableBoard board, Func <IPriorityQueue <int, HexCoords> > queueFactory) { return(new List <DirectedLandmark> { DirectedLandmark.New(coords, board.MapSizeHexes, queueFactory, board.TryEntryCost), DirectedLandmark.New(coords, board.MapSizeHexes, queueFactory, board.TryExitCost) }.AsReadOnly()); }
// Common settings for both directions /// <param name="board">Board on which this path search is taking place.</param> /// <param name="start">Start hex for this half of the bidirectional path search.</param> /// <param name="goal">Goal hex for this this half of the bidirectional path search.</param> /// <param name="pathHalves"></param> protected DirectionalPathfinder(INavigableBoard <IHex> board, IHex start, IHex goal, IPathHalves pathHalves) : base(board, start, goal, pathHalves.ClosedSet) { PathHalves = pathHalves; OpenSet = new Dictionary <HexCoords, IDirectedPath>(); Queue = new HotPriorityQueue <IDirectedPath>(0, 256); }
/// <summary>TODO</summary> /// <param name="board">Board on which this shortest-path search is taking place.</param> /// <param name="source">Source hex for this shortest-path search.</param> /// <param name="target">Target hex for this shortest-path search.</param> /// <param name="closedSet">Injected implementation of <see cref="ISet{HexCoords}"/>.</param> protected internal Pathfinder(INavigableBoard board, IHex source, IHex target, ISet <HexCoords> closedSet) { if (board == null) { throw new ArgumentNullException("board"); } if (board.Landmarks == null) { throw new ArgumentNullException("board", "Member Landmarks must not be null"); } if (closedSet == null) { throw new ArgumentNullException("closedSet"); } if (source == null) { throw new ArgumentNullException("source"); } if (target == null) { throw new ArgumentNullException("target"); } Board = board; ClosedSet = closedSet; Source = source; Target = target; }
} // TODO: Set this to FOVRange perhaps? public static IPath2 FindPath( ICoordsUser start, ICoordsUser goal, INavigableBoard board ) { return(FindPath(start, goal, board.StepCost, board.Heuristic, board.IsOnBoard)); }
/// <summary>Returns the requested neighbours for this hex.</summary> /// <param name="this">TODO</param> /// <param name="here">TODO</param> /// <returns></returns> public static IEnumerable <NeighbourHex> GetNeighbourHexes( this INavigableBoard <IHex> @this, IHex here ) { if (@this == null) { throw new ArgumentNullException("this"); } return(@this.GetAllNeighbours(here).Where(n => n.Hex != null)); }
/// <summary>All neighbours of this hex, as an <see cref="IEnumerable {NeighbourHex}"/></summary> public static IEnumerable <NeighbourHex> GetAllNeighbours( this INavigableBoard <IHex> @this, IHex here ) { if (@this == null) { throw new ArgumentNullException("this"); } return(HexsideExtensions.HexsideList.Select(hexside => new NeighbourHex(@this[here.Coords.GetNeighbour(hexside)], hexside.Reversed()))); }
/// <summary>TODO</summary> /// <param name="start"></param> /// <param name="goal"></param> /// <param name="board"></param> /// <returns></returns> public static IPath FindPath( HexCoords start, HexCoords goal, INavigableBoard board ) { if (board == null) { throw new ArgumentNullException("board"); } return(FindPath(start, goal, board.StepCost, board.Heuristic, board.IsOnboard)); }
/// <summary>Creates a new <see cref="Pathfinder"/> instance implementing a unidirectional A* from /// <paramref name="source"/> to <paramref name="target"/>.</summary> /// <param name="board">An object satisfying the interface <c>INavigableBoardFwd</c>.</param> /// <param name="source">Coordinates for the <c>first</c> step on the desired path.</param> /// <param name="target">Coordinates for the <c>last</c> step on the desired path.</param> public UnidirectionalPathfinder(INavigableBoard <IHex> board, IHex source, IHex target) : base(board, source, target, new HashSet <HexCoords>() ) { if (board == null) { throw new ArgumentNullException("board"); } StepCost = (hex, hexside) => board.GetDirectedCostToExit(hex, hexside); Heuristic = board.Heuristic; Path = GetPath(); TraceFindPathDone(ClosedSet.Count); }
/// <summary>Returns an <see cref="IPath{THex}"/> for the optimal path using a standard A* algorithm.</summary> /// <param name="board">An object satisfying the interface <see cref="INavigableBoard{THex}"/>.</param> /// <param name="source">Coordinates for the <c>first</c> step on the desired path.</param> /// <param name="target">Coordinates for the <c>last</c> step on the desired path.</param> /// <param name="queue"></param> /// <param name="closedSet"></param> /// <returns>A <see cref="IPath{THex}"/> for the shortest path found, or null if no path was found.</returns> /// <remarks> /// <para>Note that the Heuristic provided by <paramref name="board"/> <b>must</b> be monotonic in order for the algorithm to perform properly.</para> /// </remarks> public static IPath <THex> GetPath <THex>(this INavigableBoard <THex> board, THex source, THex target, IPriorityQueue <int, IDirectedPath> queue, ISet <HexCoords> closedSet) where THex : IHex { source.TraceFindPathDetailInit(target); var vectorGoal = target.Coords.Canon - source.Coords.Canon; queue.Enqueue(0, new DirectedPath(target)); while (queue.TryDequeue(out var item)) { var path = item.Value; var step = path.PathStep; if (closedSet.Contains(step.Coords)) { continue; } step.Hex.TraceFindPathDequeue("A* Rev", path, item.Key >> 16, (int)(item.Key & 0xFFFFu) - 0x7FFF); if (step.Hex == (IHex)source) { return(new Path <THex>(path.ToMaybe(), source, target, closedSet, null)); } closedSet.Add(step.Coords); Hexside.HexsideList.ForEach(hexside => { board[step.Coords.GetNeighbour(hexside)].IfHasValueDo(neighbour => { var cost = step.Hex.TryDirectedCost(hexside); if (cost > 0) { var newPath = path.AddStep(neighbour, hexside.Reversed, cost); board.Estimate(vectorGoal, source, neighbour, newPath.TotalCost) .IfHasValueDo(key => { neighbour.Coords.TraceFindPathEnqueue(key >> 16, (int)(key & 0xFFFFu)); queue.Enqueue(key, newPath); }); } }); }); } return(null); }
/// <summary>Creates a populated <see cref="Collection{T}"/> of <see cref="Landmark"/> /// instances.</summary> /// <param name="board">The board on which the collection of landmarks is to be instantiated.</param> /// <param name="landmarkCoords">Board coordinates of the desired landmarks</param> public static ILandmarkCollection New( INavigableBoard board, IFastList <HexCoords> landmarkCoords ) { int degreeOfParallelism = Math.Max(1, Environment.ProcessorCount - 1); var query = from coords in landmarkCoords.AsParallel() .WithDegreeOfParallelism(degreeOfParallelism) .WithMergeOptions(ParallelMergeOptions.NotBuffered) #if UseSortedDictionary select Landmark.DictionaryPriorityQueueLandmark(coords, board); #else select Landmark.HotPriorityQueueLandmark(coords, board); #endif return(Extensions.InitializeDisposable(() => new LandmarkCollection(query))); }
/// <summary>Calculates an <c>IPath</c> for the optimal path from coordinates .</summary> /// <param name="board">An object satisfying the interface <c>INavigableBoardFwd</c>.</param> /// <param name="source">Coordinates for the <c>first</c> step on the desired path.</param> /// <param name="target">Coordinates for the <c>last</c> step on the desired path.</param> public BidirectionalPathfinder(INavigableBoard <IHex> board, IHex source, IHex target) : base(board, source, target, new HashSet <HexCoords>()) { Pathfinder.TraceFindPathDetailInit(Source.Coords, Target.Coords); _bestSoFar = int.MaxValue; var pathfinderFwd = new BidirectionalPathfinder.DirectionalPathfinder.PathfinderRev(board, source, target, this); var pathfinderRev = new BidirectionalPathfinder.DirectionalPathfinder.PathfinderFwd(board, source, target, this); // Alternate searching from each direction and calling the other direction pathfinderFwd.Partner = pathfinderRev; var pathfinder = pathfinderRev.Partner = pathfinderFwd; while (!pathfinder.IsFinished()) { pathfinder = pathfinder.Partner; } TraceFindPathDone(ClosedSet.Count); }
/// <summary>TODO</summary> public static ILandmark HotPriorityQueueLandmark(HexCoords coords, INavigableBoard board) { var backingStore = BackingStore(coords, board, () => PriorityQueueFactory.NewHotPriorityQueue <HexCoords>(1024)); return(Extensions.InitializeDisposable(() => new Landmark(coords, backingStore))); }
/// <summary>Returns an <see cref="UnidirectionalPathfinder"/>.</summary> /// <param name="this"></param> /// <param name="source"></param> /// <param name="target"></param> /// <returns>Returns an <see cref="IPathfinder{IHex}"/> with a shortest path from <paramref name="source"/> to <paramref name="target"/> /// as well as statistice on the Unidirectional path determination.</returns> public static IPathfinder <IHex> GetUnidirectionalPathfinder(this INavigableBoard <IHex> @this, IHex source, IHex target) { return(new UnidirectionalPathfinder(@this, source, target)); }
static int?Estimate <THex>(this INavigableBoard <THex> board, IntVector2D vectorGoal, IHex start, IHex hex, int totalCost) where THex : IHex => from heuristic in board.Heuristic(start, hex) as int?select((heuristic + totalCost) << 16) + Preference(vectorGoal, start.Coords.Canon - hex.Coords.Canon);
/// <summary>Returns an <see cref="IPath{THex}"/> for the optimal path using a standard A* algorithm.</summary> /// <param name="board">An object satisfying the interface <c>INavigableBoardFwd</c>.</param> /// <param name="source">Coordinates for the <c>first</c> step on the desired path.</param> /// <param name="target">Coordinates for the <c>last</c> step on the desired path.</param> /// <returns>A <see cref="IPath{THex}"/> for the shortest path found, or null if no path was found.</returns> /// <remarks> /// <para>Note that the Heuristic provided by <paramref name="board"/> <b>must</b> be monotonic in order for the algorithm to perform properly.</para> /// </remarks> public static IPath <THex> GetPathStandardAStar <THex>(this INavigableBoard <THex> board, THex source, THex target) where THex : IHex => board.GetPath(source, target, new DictionaryPriorityQueue <int, IDirectedPath>(), new HashSet <HexCoords>());
/// <summary>Create a new instance of <see cref="PathfinderRev"/>, a backward-searching <see cref="DirectionalPathfinder"/>.</summary> /// <param name="board">Board on which this path search is taking place.</param> /// <param name="source">Source hex for this path search, the goal for the directional path search.</param> /// <param name="target">Target hex for this path search, the start for the directional path search.</param> /// <param name="pathHalves"></param> internal PathfinderRev(INavigableBoard <IHex> board, IHex source, IHex target, IPathHalves pathHalves) : base(board, source, target, pathHalves) { TraceFindPathDetailDirection("Fwd", Goal.Coords - Start.Coords); StartPath(Start); }
/// <summary>TODO</summary> /// <param name="start"></param> /// <param name="goal"></param> /// <param name="board"></param> /// <returns></returns> public static IPath FindPath( HexCoords start, HexCoords goal, INavigableBoard board ) { if (board==null) throw new ArgumentNullException("board"); return FindPath(start, goal, board.StepCost, board.Heuristic, board.IsOnboard); }
/// <summary>Creates a new <see cref="IPathfinder"/> instance implementing a unidirectional A*.</summary> /// <param name="board">An object satisfying the interface <c>INavigableBoardFwd</c>.</param> /// <remarks> /// <para>Note that the Heuristic provided by <paramref name="board"/> <b>must</b> be monotonic /// in order for the algorithm to perform properly.</para> /// </remarks> public StandardPathfinder(INavigableBoard board) => Board = board;
/// <summary>Returns an <c>IDirectedPath</c> for the optimal path from coordinates <c>start</c> to <c>goal</c>.</summary> /// <param name="board">An object satisfying the interface <c>INavigableBoardFwd</c>.</param> /// <param name="source">Coordinates for the <c>first</c> step on the desired path.</param> /// <param name="target">Coordinates for the <c>last</c> step on the desired path.</param> /// <returns>A <c>IDirectedPathCollection</c> for the shortest path found, or null if no path was found.</returns> /// <remarks> /// <para>Note that the Heuristic provided by <paramref name="board"/> <b>must</b> be monotonic in order for the algorithm to perform properly.</para> /// <seealso cref="PGNapoleonics.HexUtilities.Pathfinding.UnidirectionalPathfinder"/> /// </remarks> public static IDirectedPath FindDirectedPathFwd(INavigableBoard <IHex> board, IHex source, IHex target) { return((new UnidirectionalPathfinder(board, source, target)).Path); }