遵循这本书"人工智能 - 现代方法"我试图使搜索算法实现(DFS,A *等)可以解决不同的问题(从A到B的路径,滑块拼图等),而不仅仅是一个特定的问题。
public abstract class Problem
{
protected Problem(object initialState)
{
InitialState = initialState;
}
public object InitialState { get; }
/// <summary>
/// Checks if the state is the goal state
/// </summary>
public abstract bool IsGoalState(object state);
/// <summary>
/// Returns the actions available from the state
/// </summary>
public abstract ISet<Action> Actions(object state);
/// <summary>
/// Returns the state that results after performing the action on the state
/// </summary>
public abstract object ResultState(object state, Action action);
/// <summary>
/// Returns the cost of action to reach from state to reachedState
/// </summary>
/// <param name="state">The state from which the action will be performed</param>
/// <param name="action">One of the actions available in the state</param>
/// <param name="reachedState">The state that results after performing the action</param>
public virtual int StepCost(object state, Action action, object reachedState)
{
return 1;
}
}
_
public class Node
{
public Node(object state)
{
State = state;
PathCost = 0;
}
/// <summary>
/// </summary>
/// <param name="action">The action that was applied to the parent to generate the node</param>
/// <param name="stepCost">The cost from the parent node to this node</param>
public Node(object state, Node parent, Action action, int stepCost)
: this(state)
{
Parent = parent;
Action = action;
if (Parent != null)
PathCost = Parent.PathCost + stepCost;
}
public object State { get; }
public Node Parent { get; }
/// <summary>
/// The action that was applied to the parent to generate the node
/// </summary>
public Action Action { get; }
/// <summary>
/// The cost of the path from the initial statee to the node
/// </summary>
public int PathCost { get; }
public bool IsRootNode => Parent == null;
public IEnumerable<Node> PathFromRoot()
{
var path = new Stack<Node>();
var node = this;
while (!node.IsRootNode)
{
path.Push(node);
node = node.Parent;
}
path.Push(node); // root
return path;
}
}
_
public abstract class Action
{
/// <summary>
/// true if it is a "No Operation" action
/// </summary>
public virtual bool IsNoOp()
{
return false;
}
public string Name => GetType().Name;
public override string ToString()
{
return Name;
}
}
public class NoOp : Action
{
public override bool IsNoOp()
{
return true;
}
}
public abstract class EightPuzzleAction : Action
{
}
/// <summary>
/// Move the blank tile to the left
/// </summary>
public class MoveLeft : EightPuzzleAction
{
}
// the same MoveRight, MoveTop, MoveBottom
为了做到这一点,我可以从这个基类Problem
类实现方法,并将该具体实例传递给搜索算法(接受Problem
)。
class EightPuzzleProblem : Problem
{
private readonly int[,] _goalState =
{
{0, 1, 2},
{3, 4, 5},
{6, 7, 8},
};
public EightPuzzleProblem(int[,] initialState) : base(initialState)
{ }
public override bool IsGoalState(object state)
{
var puzzleState = (int[,]) state;
......... <check if puzzleState is the same as _goalState>
}
............
}
class DepthFirstSearch
{
public IEnumerable<Action> Search(Problem p)
{
return DfsRecursive(p, new Node(p.InitialState));
}
public IEnumerable<Action> DfsRecursive(Problem p, Node node)
{
if (p.IsGoalState(node.State))
return node.PathFromRoot();
.......<simple DFS implementation>
}
}
// usage example
var dfs = new DepthFirstSearch();
var result = dfs.Search(new EightPuzzleProblem(initialState));
if (!result.Any)
// fail
if (result.Count == 1 && result[0].IsNoOp)
// already at goal
foreach (var act in result)
{
if (act is MoveLeft) .....
}
但是我看到我的班级设计有一些不便:在具体的类实现代码中,我需要有很多来自object
的强制转换。有什么办法可以避免吗?
如果我将Problem
类设为通用并从ConcreteProblem
继承Problem<Something>
,那么我将无法通过Problem
使用它...
答案 0 :(得分:1)
实际上,您可以将Problem
泛型设置为实际状态的泛型参数。
public abstract class Problem<T> where T : IState{
public abstract bool IsGoalState(T state);
}
在派生类中,您现在可以简单地从Problem
派生实际类型IState
作为通用参数:
class MyDerived : Problem<MyState> {
public override bool IsGoalState(MyState state) { ... }
}
答案 1 :(得分:1)
为什么不注入你的GoalState,并使用如下界面使GameState也可插入。通过这种方式,您可以在具体类中的两个状态上实现您想要执行的任何操作,而Problem类只需要调用这些函数。你也可以有不同类型的州。
public abstract class Problem<T> where T:IGameState
{
protected Problem(T initialState)
{
InitialState = initialState;
}
public T InitialState { get; set; }
/// <summary>
/// Checks if the state is the goal state
/// </summary>
public abstract bool IsGoalState(T state);
}
public class EightPuzzleProblem<T> : Problem<T> where T : IGameState
{
private readonly T _goalState;
public EightPuzzleProblem(T initialState, T goalState)
: base(initialState)
{
_goalState = goalState;
}
public override bool IsGoalState(T state)
{
return _goalState.IsEqual(state);
}
}
public interface IGameState
{
bool IsEqual(IGameState state);
}
public class EightPuzzleGameState : IGameState
{
private readonly int[,] _goalState =
{
{0, 1, 2},
{3, 4, 5},
{6, 7, 8},
};
public bool IsEqual(IGameState state)
{
//Compare state with _goalState
}
}