2016-04-18 6 views
0

"Artificial Intelligence - A Modern Approach"の本に続いて、さまざまな問題(AからBへのパス、スライディングブロックパズルなど)で動作する検索アルゴリズムの実装(DFS、A *など)をしようとしています。 )特定の問題の1つだけではなく、私はこの基本Problemクラスからメソッドを実装し、探索アルゴリズムにその具体的なインスタンスを渡すことができることを行うためにここで子クラスのオブジェクト/キャストを回避する方法はありますか?

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を受け付け)。

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

しかし、私は私のクラスのデザインと1つの不便を参照してください。具象クラスの実装コードに私がobjectからキャストの多くを持っている必要があります。それを避ける方法はありますか?私は一般的なProblemクラスを作成し、その後、私はProblemを経由して、それを使用することはできませんProblem<Something>からConcreteProblemを継承...

+0

問題は、問題の 'IsGoalState'メソッドです。もっと具体的なものの代わりに本当に 'オブジェクト'が必要ですか?さらに、実際の問題を示すクラスだけにできるだけコードを制限することができますか?私はこの質問のために 'Node'、' DepthFirstSearch'と 'Action'が必要だと疑っていますか? – HimBromBeere

+0

もっと具体的にはどういう意味ですか? 'IState' /' State'のようなもの?多分、基礎クラスは具体的な問題状態の表現に必要なデータがないので、 'IState'から' MyProblemState'へのキャストでも同じ問題があります。 – AlexP11223

答えて

1

場合 あなたが実際に実際の状態にジェネリックのparamセットでProblemはジェネリック作ることができます。あなたは今、単に一般的なパラメータとしてIStateの実際の型を渡すProblemから派生させることができ、あなたの派生クラス内

public abstract class Problem<T> where T : IState{ 
    public abstract bool IsGoalState(T state); 
} 

class MyDerived : Problem<MyState> { 
    public override bool IsGoalState(MyState state) { ... } 
} 
+0

しかし、私が理解しているように、私はそれを '問題を受け入れる' DepthFirstSearch'メソッドで使うことはできません。 – AlexP11223

+0

これには、外部で使うことができる非ジェネリックなものを継承する一般的な 'Problem'クラスの両方を簡単に紹介することができます。 – HimBromBeere

+0

このような意味ですか? https://gist.github.com/AlexP11223/2f7e538202bb8b0d94906ec8e782227a 'パブリック抽象クラスProblemGeneric :問題 {公共オーバーライドブールIsGoalState(オブジェクトの状態) {リターンIsGoalStateGeneric((T)の状態)。 } 公開抽象ブールIsGoalStateGeneric(T状態); } ' – AlexP11223

1

なぜあなたはあまりにもあなたのGoalStateを注入して使用してGameStateもプラグイン可能なことはありません。以下のようなインターフェース。このようにして、具体的なクラスの2つの状態で実行したい操作を実装でき、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 
    } 
} 
+0

アイデアをありがとう、私はやろうとしています次の状態を 'Problem'の代わりに' IState'に取り出すためのメソッドを移動します。 – AlexP11223

関連する問題