diff --git a/SpriteCompiler/AI/AbstractAISearch.cs b/SpriteCompiler/AI/AbstractAISearch.cs
index 522f3ea..5fa8661 100644
--- a/SpriteCompiler/AI/AbstractAISearch.cs
+++ b/SpriteCompiler/AI/AbstractAISearch.cs
@@ -25,7 +25,7 @@
this.expander = expander;
}
- public INodeExpander Expander { get { return expander; } }
+ public INodeExpander Expander { get { return expander; } set { expander = value; } }
public IEnumerable Solution(T node)
{
diff --git a/SpriteCompiler/AI/CostNodeLimiter.cs b/SpriteCompiler/AI/CostNodeLimiter.cs
new file mode 100644
index 0000000..e24fc20
--- /dev/null
+++ b/SpriteCompiler/AI/CostNodeLimiter.cs
@@ -0,0 +1,24 @@
+namespace SpriteCompiler.AI
+{
+ ///
+ /// Class that taken a search node and detemines whether or not to terminate the
+ /// search at the node. This is different than a goal test and is used in the
+ /// contect of depth-limited searches.
+ ///
+ public class CostNodeLimiter : INodeLimiter
+ where T : ISearchNode
+ where C : IPathCost, new()
+ {
+ private readonly C maxCost;
+
+ public CostNodeLimiter(C maxCost)
+ {
+ this.maxCost = maxCost;
+ }
+
+ public bool Cutoff(T node)
+ {
+ return node.PathCost.CompareTo(maxCost) >= 0;
+ }
+ }
+}
diff --git a/SpriteCompiler/AI/DepthFirstSearch.cs b/SpriteCompiler/AI/DepthFirstSearch.cs
new file mode 100644
index 0000000..42c4db2
--- /dev/null
+++ b/SpriteCompiler/AI/DepthFirstSearch.cs
@@ -0,0 +1,32 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace SpriteCompiler.AI
+{
+ public class DepthFirstSearch : ISearch
+ where T : ISearchNode
+ where C : IPathCost, new()
+ {
+ protected readonly AbstractAISearch search;
+ protected readonly IQueue fringe = new Lifo();
+
+ public DepthFirstSearch(AbstractAISearch search)
+ {
+ this.search = search;
+ }
+
+ public virtual IEnumerable Search(ISearchProblem problem, S initialState)
+ {
+ fringe.Clear();
+ return search.Search(problem, fringe, initialState);
+ }
+
+ public virtual IEnumerable ExtendSearch(ISearchProblem problem)
+ {
+ return search.ExtendSearch(problem, fringe);
+ }
+ }
+}
diff --git a/SpriteCompiler/AI/DepthLimitedNodeExpander.cs b/SpriteCompiler/AI/DepthLimitedNodeExpander.cs
new file mode 100644
index 0000000..5f538f7
--- /dev/null
+++ b/SpriteCompiler/AI/DepthLimitedNodeExpander.cs
@@ -0,0 +1,35 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace SpriteCompiler.AI
+{
+ public class DepthLimitedNodeExpander : NodeExpanderDelegator
+ where T : ISearchNode
+ where C : IPathCost, new()
+ {
+ private readonly INodeLimiter limit;
+ private bool cutoffOccured = false;
+
+ public DepthLimitedNodeExpander(INodeExpander expander, INodeLimiter limit)
+ : base(expander)
+ {
+ this.limit = limit;
+ }
+
+ public bool CutoffOccured { get { return cutoffOccured; } }
+
+ public override IEnumerable Expand(ISearchProblem problem, T node)
+ {
+ if (limit.Cutoff(node))
+ {
+ cutoffOccured = true;
+ return Enumerable.Empty();
+ }
+
+ return base.Expand(problem, node);
+ }
+ }
+}
diff --git a/SpriteCompiler/AI/DepthLimitedSearch.cs b/SpriteCompiler/AI/DepthLimitedSearch.cs
new file mode 100644
index 0000000..de3587d
--- /dev/null
+++ b/SpriteCompiler/AI/DepthLimitedSearch.cs
@@ -0,0 +1,60 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace SpriteCompiler.AI
+{
+ ///
+ /// Depth-first search with a cutoff
+ ///
+ public class DepthLimitedSearch : DepthFirstSearch
+ where T : ISearchNode
+ where C : IPathCost, new()
+ {
+ protected readonly INodeLimiter limit;
+
+ public DepthLimitedSearch(AbstractAISearch search, INodeLimiter limit)
+ : base(search)
+ {
+ this.limit = limit;
+ }
+
+ public override IEnumerable Search(ISearchProblem problem, S initialState)
+ {
+ // Save the old node expander
+ var oldExpander = search.Expander;
+
+ // Wrap the expander with a depth-limied expanded in order to
+ // terminate the search
+ var expander = new DepthLimitedNodeExpander(oldExpander, limit);
+ search.Expander = expander;
+
+ // Run the search
+ var solution = base.Search(problem, initialState);
+
+ // Restore the old expander
+ search.Expander = oldExpander;
+
+ // Check to see we failed and if the reason for failing was not reaching the cutoff depth.
+ if (search.IsFailure(solution) && expander.CutoffOccured)
+ {
+ return null;
+ }
+
+ return solution;
+
+ }
+
+ public override IEnumerable ExtendSearch(ISearchProblem problem)
+ {
+ return base.ExtendSearch(problem);
+ }
+
+ public bool IsCutoff(IEnumerable result)
+ {
+ return result == null;
+ }
+ }
+}
diff --git a/SpriteCompiler/AI/INodeLimiter.cs b/SpriteCompiler/AI/INodeLimiter.cs
new file mode 100644
index 0000000..f836816
--- /dev/null
+++ b/SpriteCompiler/AI/INodeLimiter.cs
@@ -0,0 +1,9 @@
+namespace SpriteCompiler.AI
+{
+ public interface INodeLimiter
+ where T : ISearchNode
+ where C : IPathCost, new()
+ {
+ bool Cutoff(T node);
+ }
+}
diff --git a/SpriteCompiler/AI/ISearchNode.cs b/SpriteCompiler/AI/ISearchNode.cs
index 41435f0..ed6844e 100644
--- a/SpriteCompiler/AI/ISearchNode.cs
+++ b/SpriteCompiler/AI/ISearchNode.cs
@@ -12,15 +12,15 @@
public interface ISearchNode : ISearchNode where C : IPathCost
{
A Action { get; set; }
- C PathCost { get; }
- C StepCost { get; set; }
- int Depth { get; }
S State { get; }
T Parent { get; }
}
public interface ISearchNode
{
+ C PathCost { get; }
+ C StepCost { get; set; }
+ int Depth { get; }
C EstCost { get; }
}
}
diff --git a/SpriteCompiler/AI/IterativeDeepeningAStarSearch.cs b/SpriteCompiler/AI/IterativeDeepeningAStarSearch.cs
new file mode 100644
index 0000000..37c75c2
--- /dev/null
+++ b/SpriteCompiler/AI/IterativeDeepeningAStarSearch.cs
@@ -0,0 +1,45 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace SpriteCompiler.AI
+{
+ public class IterativeDeepeningAStarSearch : ISearch
+ where T : ISearchNode
+ where C : IPathCost, new()
+ {
+ protected readonly AbstractAISearch search;
+ protected readonly C limit;
+
+ public IterativeDeepeningAStarSearch(AbstractAISearch search, C limit)
+ {
+ this.search = search;
+ this.limit = limit;
+ }
+
+ public IEnumerable Search(ISearchProblem problem, S initialState)
+ {
+ C bound = new C();
+ while (bound.CompareTo(limit) < 0)
+ {
+ var dls = new DepthLimitedSearch(search, new CostNodeLimiter(bound));
+ var result = dls.Search(problem, initialState);
+
+ if (!dls.IsCutoff(result))
+ {
+ return result;
+ }
+ }
+
+ // An empty list signals failure
+ return Enumerable.Empty();
+ }
+
+ public IEnumerable ExtendSearch(ISearchProblem problem)
+ {
+ throw new NotImplementedException();
+ }
+ }
+}
diff --git a/SpriteCompiler/AI/Lifo.cs b/SpriteCompiler/AI/Lifo.cs
new file mode 100644
index 0000000..9e2282c
--- /dev/null
+++ b/SpriteCompiler/AI/Lifo.cs
@@ -0,0 +1,41 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace SpriteCompiler.AI
+{
+ public class Lifo : IQueue
+ {
+ private readonly Stack stack = new Stack();
+
+ public void Clear()
+ {
+ stack.Clear();
+ }
+
+ public bool Empty
+ {
+ get { return stack.Count == 0; }
+ }
+
+ public T Remove()
+ {
+ return stack.Pop();
+ }
+
+ public void Enqueue(T item)
+ {
+ stack.Push(item);
+ }
+
+ public void AddRange(IEnumerable items)
+ {
+ foreach (var item in items)
+ {
+ stack.Push(item);
+ }
+ }
+ }
+}
diff --git a/SpriteCompiler/AI/NodeExpanderDelegator.cs b/SpriteCompiler/AI/NodeExpanderDelegator.cs
new file mode 100644
index 0000000..576fabe
--- /dev/null
+++ b/SpriteCompiler/AI/NodeExpanderDelegator.cs
@@ -0,0 +1,26 @@
+namespace SpriteCompiler.AI
+{
+ using System.Collections.Generic;
+
+ public class NodeExpanderDelegator : INodeExpander
+ where T : ISearchNode
+ where C : IPathCost
+ {
+ private readonly INodeExpander expander;
+
+ public NodeExpanderDelegator(INodeExpander expander)
+ {
+ this.expander = expander;
+ }
+
+ public virtual IEnumerable Expand(ISearchProblem problem, T node)
+ {
+ return expander.Expand(problem, node);
+ }
+
+ public virtual T CreateNode(T parent, S state)
+ {
+ return expander.CreateNode(parent, state);
+ }
+ }
+}
diff --git a/SpriteCompiler/SpriteCompiler.csproj b/SpriteCompiler/SpriteCompiler.csproj
index 4a37303..3b50ec8 100644
--- a/SpriteCompiler/SpriteCompiler.csproj
+++ b/SpriteCompiler/SpriteCompiler.csproj
@@ -58,9 +58,14 @@
+
+
+
+
+
@@ -70,6 +75,9 @@
+
+
+