2

iOS用のブラックジャックゲームを開発しています。現在の状態と何をする必要があるかを追跡することは困難になりつつあります。たとえば、現在のゲームを追跡するC++クラスがあります。

class Game {
  queue<Player> playerQueue;
  void hit();
  void stand();
}

現在、イベントを使用して実装しています(方法A):

- (void)hitButtonPress:(id)sender {
  game->hit();
}

void Game::hit() {
  dealCard(playerQueue.top());
}

void Game::stand() {
  playerQueue.pop();
  goToNextPlayersTurn();
}

ゲームに追加されるオプションが増えるにつれ、それぞれのイベントを作成するのは面倒になり、追跡するのが難しくなっています。

私がそれを実装することを考えた別の方法はそのようなものです(方法B):

void Game::playersTurn(Player *player) {
  dealCards(player);
  while (true) {
    string choice = waitForUserChoice();
    if (choice == "stand") break;
    if (choice == "hit")
      dealCard(player);
    // etc.
  }
  playerQueue.pop();
  goToNextPlayersTurn();
}

waitForUserChoiceユーザーがと対話できるようにする特別な関数はどこにありますUIViewControllerか。ユーザーがボタンを押すと、その関数に制御が戻りplayersTurnます。つまり、ユーザーがボタンをクリックするまでプログラムを一時停止します。

方法Aでは、ユーザーとの対話が必要になるたびに関数を分割する必要があります。方法Bを使用すると、すべてをもう少し制御できます。基本的に、方法AとBの違いは次のとおりです。

A:

function A() {
  initialize();
  // now wait for user interaction by waiting for a call to CompleteA
}

function CompleteA() {
  finalize();
}

B:

function B() {
  initialize();
  waitForUserInteraction();
  finalize();
}

Bがコードをより整理された状態に保つ方法に注目してください。Objective-Cでこれを行う方法さえありますか?それとも、私が言及していない別の方法が代わりに推奨されていますか?

私が考えることができる3番目のオプションは、有限状態マシンを使用することです。それらについて少し聞いたことがありますが、それがこの場合に役立つかどうかは確かです。

私の問題に推奨されるデザインパターンは何ですか?

4

1 に答える 1

1

あなたが直面しているジレンマを理解しています。私が初めて iOS を使い始めたとき、オペレーティング システムとの間でコントロールを手放すことに頭を悩ませていました。

一般に、iOS ではメソッド A を使用することをお勧めします。通常、ViewController にはメソッド A() で設定された変数があり、CompleteA() でチェックされて、A() が最初に実行されたことなどを確認します。

有限ステート マシンに関するご質問については、問題の解決に役立つと思います。私がiOSで最初に書いたのはFSMでした(これはかなり悪いコードです)が、ここで見ることができます(FlipsideViewController.mの下部近く:

https://github.com/esromneb/ios-finite-state-machine

一般的な考え方は、これを @interface ブロック内の .h ファイルに入れることです

static int state = 0;
static int running = 0;

そして、あなたの .m にはこれがあります:

- (void) tick {

    switch (state) {
        case 0:
            //this case only runs once for the fsm, so setup one time initializations

            // next state
            state = 1;

            break;
        case 1:
            navBarStatus.topItem.title = @"Connecting...";
            state = 2;
            break;
        case 2:
            // if something happend we move on, if not we wait in the connecting stage
            if( something )
                state = 3;
            else
                state = 1;
            break;
        case 3:
            // respond to something

            // next state
            state = 4;
            break;
        case 4:
            // wait for user interaction
            navBarStatus.topItem.title = @"Press a button!";
            state = 4;

            globalCommand = userInput;

            // if user did something
            if( globalCommand != 0 )
            {
                // go to state to consume user interaction
                state = 5;  
            }

            break;

        case 5:
            if( globalCommand == 6 )
            {
                // respond to command #6
            }
            if( globalCommand == 7 )
            {
                // respond to command #7
                }

                        // go back and wait for user input
                        state = 4;
            break;

        default:
            state = 0;
            break;
    }

    if( running )
    {
        [self performSelector:@selector(tick) withObject:nil afterDelay:0.1];
    }
}

この例 (github のものを変更したもの) では、globalCommand はユーザーの入力を表す int です。globalCommand が 0 の場合、FSM は globalCommand が非ゼロになるまでステート 4 でスピンします。

FSM を開始するには、running を 1 に設定し、viewController から [self tick] を呼び出すだけです。FSM は、running が 0 に設定されるまで、0.1 秒ごとに「ティック」します。

私の最初の FSM 設計では、独自のソフトウェアを実行している Windows コンピューターからのユーザー入力とネットワーク入力に応答する必要がありました。私の設計では、Windows PC も同様であるが異なる FSM を実行していました。この設計では、NSMutuableArray を使用してコマンドの FIFO キュー オブジェクトを 2 つ作成しました。ユーザーの操作とネットワーク パケットはコマンドをキューに入れ、FSM はアイテムをキューから取り出して応答します。キューにhttps://github.com/esromneb/ios-queue-objectを使用することになりました。

説明が必要な場合はコメントしてください。

于 2013-02-21T10:28:34.393 に答える