namespace SpriteCompiler.AI
{
using System;
using System.Collections.Generic;
using System.Linq;
public abstract class AbstractAISearch
where T : ISearchNode
where C : IComparable
{
// Conceptually the expander is responsible for two things:
//
// 1. Creating a node's successors via the Successor Function
// and wrapping them in SearchNodes (computing path costs
// and heuristics, as well).
//
// 2. Creating a search node from a state. This lets us
// decouple the search algorithm from the state expansion
private INodeExpander expander;
public AbstractAISearch(INodeExpander expander)
{
this.expander = expander;
}
public INodeExpander Expander { get { return expander; } }
public IEnumerable Solution(T node)
{
var sequence = new List();
while (node != null)
{
sequence.Add(node);
node = node.Parent;
}
sequence.Reverse();
return sequence;
}
public IEnumerable ExtendSearch(ISearchProblem problem, IQueue fringe)
{
while (!fringe.Empty)
{
var node = fringe.Remove();
if (problem.IsGoal(node.State))
{
return Solution(node);
}
AddNodes(fringe, node, problem);
}
return Enumerable.Empty();
}
public IEnumerable Expand(ISearchProblem problem, T node)
{
return expander.Expand(problem, node);
}
public bool IsFailure(IEnumerable solution)
{
return !solution.Any();
}
public IEnumerable Search(ISearchProblem problem, IQueue fringe, S initialState)
{
fringe.Enqueue(expander.CreateNode(default(T), initialState));
return ExtendSearch(problem, fringe);
}
protected abstract void AddNodes(IQueue fringe, T node, ISearchProblem problem);
}
}