2

私はTic-Tac-Toeを実装するためにRx.Netを使用して、機能的反応プログラミングについてもっと学びたいと思っています。私が抱えている問題は、ゲームロジックに循環的な依存関係があるように見えることです。FRP(Rx.Net)の循環依存性をどのようにモデル化すればよいですか?

ストリーム(PlaceToken,ResetGameなど)は、ユーザー入力ストリームから生成されます。

ゲーム(boardStates)の現在の状態が初期状態から開始して、以前の状態にcommandsを適用することによって導出される:

var initialBoardState = new BoardState(); 

var boardStates = commands 
    .Scan(initialBoardState, (boardState, command) => command.Apply(boardState)) 
    .DistinctUntilChanged(); 

しかし、commandsストリームはboardStatesストリームに依存しなければなりません。これは、有効なコマンドセットが現在の状態とともに変更されるためです。

たとえば、ユーザーが空のタイルをクリックしたときにのみ、コマンドを発行する必要がありますが、空のタイルのセットは現在の状態で定義されています。

要約すると、私はお互いに依存しているように見える2つの流れを持っています。機能対応プログラミングでこれを回避するにはどうすればよいですか?

+1

本当に[mcve]が必要です。 – Enigmativity

答えて

1

@ LeeCampbellの解決策は機能しますが、コアモデルクラスを変更可能にする必要があります。代わりに、私はcycle.jsで取ったアプローチをコピーするのが最良であることを発見しました。彼らの説明はhereです。

問題は、サイクルがあることです。アクションの流れを順番に行動の流れに依存する、ボードの状態の流れに依存します。

boardStream = f(actionStream) 
actionStream = g(boardStream) 

cycle.jsソリューションは、一緒にすべてを配線するプロキシ・ストリームを使用することです:

// Create a proxy 
proxyActionStream = new Stream() 

// Create our mutually dependent streams using the proxy 
boardStream = f(proxyActionStream) 
actionStream = g(boardStream) 

// Feed actionStream back into proxyActionStream 
actionStream.Subscribe(x => proxyActionStream.OnNext(x)) 

Rx.Netの土地では、プロキシストリームはReplaySubjectである必要があります。

あなたが注意しなければならない唯一の場所は、逃げ場のフィードバックループです。ストリームが決して安定しないと、無限ループにぶつかることはありません。ストリームを相互再帰と考えることは有益です。

1

すべてがイベントである必要はありません。 Rx /コールバックはあなたが依存しているものを許可する方法で、(あなたに依存することなく)あなたをコールバックすることを忘れないでください。

  1. 循環依存関係が設計上の欠陥
  2. がも

    に変換することができます)イベント

2を受信、コマンドを送信示す経験則として

依存関係のメソッドを呼び出して状態を変更するだけですが、subscri彼らの変更を見るために彼らの出来事にいる

したがって、コマンドをストリームとして考えているのではなく、あなたが聞いたときにコマンドを作成できるストリームとして考えるべきです。

のでBoardStateこの

public class BoardState 
{ 
    public void PlaceToken(PlaceTokenCommand placeToken) 
    { 
     //Process, then raise event 
    } 

    public void Reset() 
    { 
     //Process, then raise event 
    } 

    public IObservable<?> StateUpdates() 
    { 

    } 
} 

のように見えるかもしれませんし、ViewModelに(?)のコードがなくて、この

public class TicTacToeViewModel 
{ 
    private readonly BoardState _board; 
    public TicTacToeViewModel() 
    { 
     _board = new BoardState(); 
     MoveTokenCommand = new DelegateCommand(MoveToken, CanMoveToken); 
     ResetBoardCommand = new DelegateCommand(_board.Reset); 

     board.StateUpdates(state => UpdatePresentation(state)); 
    } 

    public DelegateCommand MoveTokenCommand { get; private set;} 
    public DelegateCommand ResetBoardCommand { get; private set;} 


    private void MoveToken() 
    { 
     var token = CurrentToken; 
     var location = ActiveLocation; 
     var cmd = new PlaceTokenCommand(token, location); 
     _board.PlaceToken(cmd); 
    } 

    private bool CanMoveToken() 
    { 
     //? 
    } 
} 

しかし@Enigmativityとして、コメントでリクエストのようになります。賢明な助けを提供することは非常に難しいです。

最後の注意点は、Rxは機能的でReactiveですが、熱狂者はRxに反対しますFRP(Conal、Behaviorsなどを参照)。

関連する問題