Flesh out the AI support classes

This commit is contained in:
Lucas Scharenbroich 2016-11-26 23:39:50 -06:00
parent b3569db950
commit 77f92507b7
14 changed files with 183 additions and 8 deletions

View File

@ -5,7 +5,7 @@
where C : IPathCost<C>
{
public AStarSearch(AbstractAISearch<A, S, T, C> search)
: base(search, new AStarComparator<A, S, T, C>())
: base(search) // , new AStarComparator<A, S, T, C>())
{
}

View File

@ -6,7 +6,7 @@
public abstract class AbstractAISearch<A, S, T, C>
where T : ISearchNode<A, S, T, C>
where C : IComparable<C>
where C : IPathCost<C>
{
// Conceptually the expander is responsible for two things:
//
@ -68,7 +68,7 @@
return !solution.Any();
}
public IEnumerable<T> Search(ISearchProblem<A, S, C> problem, IQueue<T> fringe, S initialState)
public virtual IEnumerable<T> Search(ISearchProblem<A, S, C> problem, IQueue<T> fringe, S initialState)
{
fringe.Enqueue(expander.CreateNode(default(T), initialState));
return ExtendSearch(problem, fringe);

View File

@ -1,5 +1,6 @@
namespace SpriteCompiler.AI
{
using Adapters;
using System.Collections.Generic;
public class BestFirstSearch<A, S, T, C> : ISearch<A, S, T, C>
@ -15,10 +16,10 @@
this.fringe = fringe;
}
public BestFirstSearch(AbstractAISearch<A, S, T, C> search, IComparer<T> comparator)
public BestFirstSearch(AbstractAISearch<A, S, T, C> search)
{
this.search = search;
// this.fringe = new PriorityQueue<T>(INITIAL_CAPACITY, comparator);
this.fringe = new QueueAdapter<T, C>();
}
public IEnumerable<T> Search(ISearchProblem<A, S, C> problem, S initialState)

View File

@ -0,0 +1,38 @@
using System;
using System.Collections.Generic;
namespace SpriteCompiler.AI
{
public class GraphSearch<A, S, T, C> : AbstractAISearch<A, S, T, C>
where T : ISearchNode<A, S, T, C>
where C : IPathCost<C>
{
private readonly ISet<S> closed = new HashSet<S>();
public GraphSearch(INodeExpander<A, S, T, C> expander)
: base(expander)
{
}
/// <summary>
/// Generic graph search. See page 83 in Russell and Norvig. This only works in informed
/// search if the heuristic is admissible.However, if a heuristic is not admissible and
/// you still want to use, that means you should know enough to extend this class or write
/// your own Search class.
/// </summary>
public override IEnumerable<T> Search(ISearchProblem<A, S, C> problem, IQueue<T> fringe, S initialState)
{
closed.Clear();
return base.Search(problem, fringe, initialState);
}
protected override void AddNodes(IQueue<T> fringe, T node, ISearchProblem<A, S, C> problem)
{
if (!closed.Contains(node.State))
{
closed.Add(node.State);
fringe.AddRange(Expand(problem, node));
}
}
}
}

View File

@ -0,0 +1,7 @@
namespace SpriteCompiler.AI
{
public interface IGoalTest<S>
{
bool IsGoal(S state);
}
}

View File

@ -0,0 +1,9 @@
namespace SpriteCompiler.AI
{
using System;
public interface IHeuristicFunction<S, C> where C : IPathCost<C>
{
C Eval(S state);
}
}

View File

@ -11,7 +11,7 @@
/// </summary>
public interface INodeExpander<A, S, T, C>
where T : ISearchNode<A, S, T, C>
where C : IComparable<C>
where C : IPathCost<C>
{
IEnumerable<T> Expand(ISearchProblem<A, S, C> problem, T node);
T CreateNode(T parent, S state);

View File

@ -1,12 +1,15 @@
namespace SpriteCompiler.AI
{
using System;
using System.Collections.Generic;
public interface IQueue<T>
{
void Clear();
bool Empty { get; }
T Remove();
void Enqueue(T item);
void AddRange(IEnumerable<T> items);
}
}

View File

@ -9,13 +9,17 @@
/// <typeparam name="S">State of the search</typeparam>
/// <typeparam name="T">Type of the parent</typeparam>
/// <typeparam name="C">Cost type</typeparam>
public interface ISearchNode<A, S, T, C> where C : IComparable<C>
public interface ISearchNode<A, S, T, C> : ISearchNode<C> where C : IPathCost<C>
{
A Action { get; set; }
C StepCost { get; set; }
C PathCost { get; }
int Depth { get; }
S State { get; }
T Parent { get; }
}
public interface ISearchNode<C>
{
C PathCost { get; }
}
}

View File

@ -0,0 +1,9 @@
namespace SpriteCompiler.AI
{
using System;
public interface IStepCostFunction<A, S, C> where C : IPathCost<C>
{
C StepCost(S fromState, A action, S toState);
}
}

View File

@ -0,0 +1,9 @@
namespace SpriteCompiler.AI
{
using System.Collections.Generic;
public interface ISuccessorFunction<A, S>
{
IDictionary<A, S> Successors(S state);
}
}

View File

@ -0,0 +1,28 @@
using System;
using System.Collections.Generic;
namespace SpriteCompiler.AI
{
public abstract class InformedNodeExpander<A, S, T, C> : INodeExpander<A, S, T, C>
where T : HeuristicSearchNode<A, S, T, C>
where C : IPathCost<C>
{
public abstract T CreateNode(T parent, S state);
public IEnumerable<T> Expand(ISearchProblem<A, S, C> problem, T node)
{
foreach (var successor in problem.Successors(node.State))
{
var action = successor.Key;
var state = successor.Value;
var next = CreateNode(node, state);
next.Action = action;
next.StepCost = problem.StepCost(node.State, action, state);
next.Heuristic = problem.Heuristic(state);
yield return next;
}
}
}
}

View File

@ -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 SearchProblem<A, S, C> : ISearchProblem<A, S, C>
where C : IPathCost<C>
{
private readonly IGoalTest<S> goalTest;
private readonly IStepCostFunction<A, S, C> stepCost;
private readonly ISuccessorFunction<A, S> successorFn;
private readonly IHeuristicFunction<S, C> heuristicFn;
public SearchProblem(IGoalTest<S> goalTest, IStepCostFunction<A, S, C> stepCost, ISuccessorFunction<A, S> successor, IHeuristicFunction<S, C> heuristicFn)
{
this.goalTest = goalTest;
this.stepCost = stepCost;
this.successorFn = successor;
this.heuristicFn = heuristicFn;
}
public IDictionary<A, S> Successors(S state)
{
return successorFn.Successors(state);
}
public bool IsGoal(S state)
{
return goalTest.IsGoal(state);
}
public C StepCost(S fromState, A action, S toState)
{
return stepCost.StepCost(fromState, action, toState);
}
public C Heuristic(S state)
{
return heuristicFn.Eval(state);
}
}
}

View File

@ -0,0 +1,22 @@
using System;
namespace SpriteCompiler.AI
{
public class TreeSearch<A, S, T, C> : AbstractAISearch<A, S, T, C>
where T : ISearchNode<A, S, T, C>
where C : IPathCost<C>
{
public TreeSearch(INodeExpander<A, S, T, C> expander)
: base(expander)
{
}
/// <summary>
/// Generic tree search. See page 72 in Russell and Norvig
/// </summary>
protected override void AddNodes(IQueue<T> fringe, T node, ISearchProblem<A, S, C> problem)
{
fringe.AddRange(Expand(problem, node));
}
}
}