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); } }