4

チェスのようなゲームのルール/検証システムを作成するために使用できる設計パターン (これは単なる例であり、実際のゲームにはより複雑なルール セットが必要です)

このサイトでいくつかの質問を読みましたが、決定的な答えも、正しい方向に向ける答えも見つかりませんでした。

このシステムには次のものが必要です。

  • ルールが適用されているすべてのオブジェクトは、検証の開始点となるメソッドを持つ特定のインターフェイスを実装する必要があります。
  • ルールは 2 つのステップで適用する必要があります。まず、検証する必要があります (ポーン A が D4 のマスに移動できるか)。真の場合はメソッド A を実行し、偽の場合はメソッド B を実行します。
  • すべてのオブジェクトには、特定の順序で適用する必要がある複数のルールを含めることができます。ルール 1 が終了すると、ルール 2 の検証が開始されます。
  • すべての個別のルール (たとえば、1 マスしか移動できない、斜めにしか移動できないなど) は、独自のクラスに属し、再利用可能で、ルールが必要なオブジェクトに適用できる必要があります。
  • これは、バックエンドのマルチプレイヤー ゲームで使用されることに注意してください。
  • すべてのルールには、その有効性をテストするために複数のオブジェクトが必要であることに注意してください。たとえば、通常、ポーンは 1 マス移動できますが、ゲームボード上の次のマスは対戦相手のポーンによって埋められます。結果: ポーンは動けません。ポーンには、他のポーンの位置、または検証にゲームボードを含める必要があります。

これらのルールの別の言葉は、行動制限です。

gamedev.stackexchange にも質問を投稿しましたが、これは必ずしもゲーム関連の質問ではなく、誰も答えを持っていないようなので、ここにも投稿します。

4

4 に答える 4

8

問題を見れば見るほど、状態/フローチャートを思い出します。

ここに画像の説明を入力

  • ルールが適用されているすべてのオブジェクトは、検証の開始点となるメソッドを持つ特定のインターフェイスを実装する必要があります。

  • ルールは 2 つのステップで適用する必要があります。まず、検証する必要があります(ポーン A が D4 のマスに移動できるか)。真の場合はメソッド A を実行し、偽の場合はメソッド B を実行します。

状態オブジェクトには、複数の遷移を含めることができます。

トランジションは次のもので構成されます。

  1. 条件)
  2. 行動)
  • すべてのオブジェクトは、特定の順序で適用する必要がある複数のルールを持つことができます。ルール 1 が終了すると、ルール 2 の検証が開始されます。

状態図を使用すると、状態と状態遷移を介して複数のルールと特定のアクション シーケンスを取得できます

  • すべての個別のルール (たとえば、1 マスしか移動できない、斜めにしか移動できないなど) は、独自のクラスに属し、再利用可能で、ルールが必要なオブジェクトに適用できる必要があります。

これは、条件チェック動作をクラスとしてカプセル化することで実現できます。

public class Condition 
{
    public string Name {get; set;}
    public Func<Move,bool> IsMet {get;set;} 
}

// Captures the behaviour of moving diagonally by 1-step
// This can now be referenced/composed by other classes to build
// a more complex condition
var moveDiagonalCondition = new Condition 
{ 
    Name="Move diagonal", 
    IsMet = move => 
                    {
                        var delta = (move.ToPosition - move.FromPosition);
                        // 1 step to the left or right
                        return Math.Abs(delta.X) == 1 
                        // 1 step upwards (if player),
                        // or 1 step downwards (if opponent)
                        && delta.Y == move.IsPlayer1Move ? -1 : 1
                    }
}
  • これは、バックエンドのマルチプレイヤー ゲームで使用されることに注意してください。

  • すべてのルールには、その有効性をテストするために複数のオブジェクトが必要であることに注意してください。たとえば、通常、ポーンは 1 マス移動できますが、ゲームボード上の次のマスは対戦相手のポーンによって埋められます。結果: ポーンは動けません。ポーンには、他のポーンの位置、または検証にゲームボードを含める必要があります。

moveチェスのシナリオでは、パラメーターを渡すことを提案します。

public class Move
{
    public Point FromPosition {get;set;}
    public Point ToPosition {get;set;}
    public Piece Piece {get;set;}
}

同時に、ステートは GameBoard 全体にアクセスできる必要があります。これにより、州は次のようなことを行うことができます

// Check for empty cell
GameBoard.GetPieceAt(move.ToPosition) == null;

// Check for opponent's piece
GameBoard.GetPieceAt(move.ToPosition).IsPlayer2;

これを MMORPG シナリオにさらに拡張するには、パラメーターを介して「ソース」および/または「ターゲット」を渡します。

  • つまり、コリジョン ソース/ターゲット、または直接影響を受けるオブジェクト

結論

状態の問題に非常に似ているため、状態ベースのソリューションを検討することをお勧めします。

例:状態パターン、有限状態マシン、状態遷移表、オートマトンなど。

または、デシジョン テーブルとデシジョン ツリーを調べてみることもできます(これらを自分で実際に使用したことがないため、それらについて多くを語ることはできません)

残念ながら、正確な解決策をお勧めできるとは思いません。

しかし、うまくいけば、上記のいくつかの例/キーワードが、あなたが始めるのに役立つことを願っています.

于 2013-01-16T17:30:17.190 に答える
2

戦略パターンがあなたが探しているものである可能性があると考えています.HuorSwordsが提案する仕様パターンよりも軽いです.もっと簡単に始められるものを探しているなら.

使用したいルールは、戦略として抽象化してから、必要に応じて各部分に組み込むことができます。

各ルールは独自のクラスに保持できます。

各戦略は、要求した順序で適用されるルールのリストから構築できます。

于 2013-01-16T12:31:59.353 に答える
1

これが私がそれを設計する方法です。(一部の設計パターンに対応する場合と対応しない場合があります)。

abstract class Rule<T>
{
    protected abstract bool implementRule(T on, GameWorld gw);

    protected abstract void doIfTrue();

    protected abstract void doIfFalse();

    public void runRule(T on, GameWorld gw)
    {
        if (implementRule(on, gw))
        {
            doIfTrue();
        }
        else
        {
            doIfFalse();
        }
    }

}

次に、getX() メソッドを持つポーンと呼ばれるクラス/インターフェースがあると仮定すると、次のようなことができます

class RuleImpl : Rule<Pawn> // note T is now Pawn
{

    protected override bool implementRule(Pawn on, GameWorld gw) {
        if(on.getX()<gw.getX()){
            return true;
        }

        return false;
    }


    protected override void doIfTrue()
    {
        Console.WriteLine("true");

    }


    protected override void doIfFalse() {
        Console.WriteLine("false");

    }
}

編集: 当然のことながら、Pawn は のようなインターフェイスに変更できますし、変更する必要がありますThingsThatHaveAnXValue。しかし、コードをわかりやすくするために、そのまま残しました

于 2013-01-16T12:01:11.550 に答える
1

あなたの問題に対する仕様パターンのアプローチを考えています。

于 2013-01-16T11:18:26.920 に答える