#region Copyright & License Information /* * Copyright 2007-2016 The OpenRA Developers (see AUTHORS) * This file is part of OpenRA, which is free software. It is made * available to you under the terms of the GNU General Public License * as published by the Free Software Foundation, either version 3 of * the License, or (at your option) any later version. For more * information, see COPYING. */ #endregion using System; using System.Collections.Generic; using OpenRA.Primitives; namespace OpenRA.Mods.Common.Pathfinder { public interface IPathSearch : IDisposable { /// /// The Graph used by the A* /// IGraph Graph { get; } /// /// Stores the analyzed nodes by the expand function /// IEnumerable> Considered { get; } bool Debug { get; set; } Player Owner { get; } int MaxCost { get; } IPathSearch Reverse(); IPathSearch WithCustomBlocker(Func customBlock); IPathSearch WithIgnoredActor(Actor b); IPathSearch WithHeuristic(Func h); IPathSearch WithCustomCost(Func w); IPathSearch WithoutLaneBias(); IPathSearch FromPoint(CPos from); /// /// Decides whether a location is a target based on its estimate /// (An estimate of 0 means that the location and the unit's goal /// are the same. There could be multiple goals). /// /// The location to assess /// Whether the location is a target bool IsTarget(CPos location); bool CanExpand { get; } CPos Expand(); } public abstract class BasePathSearch : IPathSearch { public IGraph Graph { get; set; } protected IPriorityQueue OpenQueue { get; private set; } public abstract IEnumerable> Considered { get; } public Player Owner { get { return Graph.Actor.Owner; } } public int MaxCost { get; protected set; } public bool Debug { get; set; } protected Func heuristic; protected Func isGoal; // This member is used to compute the ID of PathSearch. // Essentially, it represents a collection of the initial // points considered and their Heuristics to reach // the target. It pretty match identifies, in conjunction of the Actor, // a deterministic set of calculations protected readonly IPriorityQueue StartPoints; protected BasePathSearch(IGraph graph) { Graph = graph; OpenQueue = new PriorityQueue(GraphConnection.ConnectionCostComparer); StartPoints = new PriorityQueue(GraphConnection.ConnectionCostComparer); Debug = false; MaxCost = 0; } /// /// Default: Diagonal distance heuristic. More information: /// http://theory.stanford.edu/~amitp/GameProgramming/Heuristics.html /// /// A delegate that calculates the estimation for a node protected static Func DefaultEstimator(CPos destination) { return here => { var diag = Math.Min(Math.Abs(here.X - destination.X), Math.Abs(here.Y - destination.Y)); var straight = Math.Abs(here.X - destination.X) + Math.Abs(here.Y - destination.Y); // According to the information link, this is the shape of the function. // We just extract factors to simplify. // Possible simplification: var h = Constants.CellCost * (straight + (Constants.Sqrt2 - 2) * diag); return Constants.CellCost * straight + (Constants.DiagonalCellCost - 2 * Constants.CellCost) * diag; }; } public IPathSearch Reverse() { Graph.InReverse = true; return this; } public IPathSearch WithCustomBlocker(Func customBlock) { Graph.CustomBlock = customBlock; return this; } public IPathSearch WithIgnoredActor(Actor b) { Graph.IgnoredActor = b; return this; } public IPathSearch WithHeuristic(Func h) { heuristic = h; return this; } public IPathSearch WithCustomCost(Func w) { Graph.CustomCost = w; return this; } public IPathSearch WithoutLaneBias() { Graph.LaneBias = 0; return this; } public IPathSearch FromPoint(CPos from) { if (Graph.World.Map.Contains(from)) AddInitialCell(from); return this; } protected abstract void AddInitialCell(CPos cell); public bool IsTarget(CPos location) { return isGoal(location); } public bool CanExpand { get { return !OpenQueue.Empty; } } public abstract CPos Expand(); protected virtual void Dispose(bool disposing) { if (disposing) Graph.Dispose(); } public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } } }