2

Objective-Cの感覚を集めるために、 Cocoaを使用しない非常に基本的なconnect4ゲームを作成しています。

私のプログラムには、次の3つのモジュールがあります。

  • 「ゲーム」:ボード情報を保持する配列が含まれています。main内で作成され、ターンを担当するオブジェクト。PlayerオブジェクトとComputerオブジェクトは、このモジュール内にあります。
  • 「プレイヤー」:プレイヤーの駒を優先列に挿入する機能を保持します(このモジュールはカプセル化の目的でのみ存在します)。
  • 「コンピューター」:現在のボード設定に基づいて、コンピューターが移動する場所を決定し、その場所にピースを配置する機能を保持します。

pieceLoc理想的には、PlayerクラスとComputerクラスが、ある種の継承を通じてGame内に存在する同じインスタンスを編集できるようにしたいのですが、これを行う方法がわかりません。

これが私が現在考えていることの抜粋です:
// startGame exists within the "Game" module

char *pieceLoc[42]; // This is a *temporary* global var. I'm still learning about
                    // the best way to implement this with class and instance 
                    // methods. This is the array that holds the board info.

-(void) startGame {
 Player   *player   =[[Player alloc] init]; // player's symbol = 'X'
 Computer *computer =[[Computer alloc] init]; // computer's symbol = 'O'

 int i = 0;
 while ([game hasPieceWon: 'X'] == NO && [game hasPieceWon: 'O'] == NO) {
  //function for player move

      if ([game hasPieceWon: 'X'] == NO) {
      //function for computer move
      } 
  }
 if ([game hasPieceWon: 'X'] == YES)
   // Tell the player they've won 
 else
  // Tell the player the computer has won.

}

プレーヤーとコンピューターの移動に使用される関数は、配列へのアクセスを何らかの方法で取得するために必要な関数ですpieceLoc(クラスとインスタンスのメソッドについて詳しく知ると、将来的にはインスタンス変数として存在します)。pieceLoc現在、関数パラメーターを介して渡す必要がある場合に備えて、char*として存在します。

これは、OOPについての考え方ではかなり単純な問題のように感じますが、午後のほとんどを検索したにもかかわらず、探していたものに対する答えを見つけることができませんでした。私が集めたものから、私の質問はクラス構成に関連していますが、Objective-Cのそれについての良いリソースを見つけることができませんでした。

pieceLocつまり、繰り返しますが、「親クラス」ゲーム内に存在する単一のインスタンスを、追加のパラメーターを使用せずpieceLocに直接操作できる2つの「子クラス」に渡す方法を探しています。

配列をパラメーターとして渡すことが、より慣用的なことになる場合、Objective-Cで参照による受け渡しがどのように機能するかの例を取得できますか?

助けてくれてありがとう!

4

2 に答える 2

4

すでにお気づきかもしれませんが、Objective-C には、スーパー クラスから継承できる「クラス変数」が実際にはありません。

グローバル変数を持つ必要がないようにこれを構築する 1 つの方法は、次のようになります。

各プレイヤーとボードへの参照を保持する Game オブジェクトがあります。プレーヤーは、ボードへの参照を使用してそれぞれ初期化されます。startGame メソッド (ゲーム内) は次のようなコードになります。

board = [[Board alloc] init];
player = [[Player alloc] initWithBoard: board];
computer = [[ComputerPlayer alloc] initWithBoard: board];

Board クラスには、ボードの状態を照会し、動きを出し、動きが正当かどうか、プレイヤーが勝ったかどうかを判断するメソッドがあります (ただし、ゲーム ルール関連のロジックが含まれる場合があります)。ゲーム)。

Player と ComputerPlayer の initWithBoard メソッドでは、board インスタンスを保持し、それを使用して各プレーヤーが決定した動きを伝えます。ゲームは移動の順序を確立し、グローバルな状態を追跡します。Player と ComputerPlayer がゲームの最後に解放されると、dealloc メソッドでボードへの参照が解放されます。

于 2009-12-29T03:49:36.993 に答える
1

Objective-C にはクラス変数自体がないため (静的変数を使用してシミュレートされているだけです)、同じソース ファイル/コンパイル ユニットでメソッドを定義した場合にのみ、子クラスは静的グローバルに直接アクセスできます。これは、他のベスト プラクティス (コンパイル ユニットごとに 1 つのクラス定義) に違反します。クラス フィールドにアクセスする通常の方法は、アクセサーを使用することです。

この場合、クラスを密結合しすぎないように注意してください。ボードを (配列ではなくオブジェクトとして) に渡す (PlayerコンピューターPersonもプレーヤーであるため、より適切な名前かもしれません)。Computerは、メソッド パラメーターまたはプロパティのいずれであっても、グローバルまたは別のクラスの静的メンバーを参照するよりも柔軟です。プレイヤー オブジェクトは配置する場所を決定し、ボードに配置する場所を伝えます。または、ゲームはボードの読み取り専用バージョンをプレーヤーに渡します。プレーヤーの配置メソッドは、ピースを配置する場所を返します。1 つには、ボード オブジェクトを切り離して使用することで、チートを防ぐことができます。誰かが独自の Player クラスを注入して、自分のターンに複数のピースを配置できるようにすることを想像してみてください。もう 1 つの理由は、間接化によってネットワーク サポートの追加が容易になることです (オブジェクト間のメッセージは、ローカル オブジェクトに対して透過的なプロセスでネットワーク メッセージになります)。

プレーヤーが作成される場所についても考えてください。他の何かでプレーヤーを作成してstartGameメソッドに渡す方が理にかなっているかもしれません。これは、たとえば、プレイヤーがトーナメントで競い合い、プレイヤー オブジェクトが 1 つのゲームより長く存在する必要がある場合に意味があります。

クラス構成は、メンバーとして別のオブジェクトを持つ 1 つのオブジェクトを参照します。たとえば、C は継承をサポートしていませんでしたが、構造体をネストできました。別の言い方をすれば、クラス構成は「has-a」関係であり、継承は「is-a」関係であるということです。たとえば、プレーヤー クラスは、それぞれがピースを配置するために使用するボードへのポインターを持つことができます。

Objective-C にも参照渡しはありません。代わりに、ポインターを使用します。

また、ゲームが引き分けを処理することを確認してください。これを実現するために、ゲーム ループを単純化することをお勧めします。擬似コードでは、

// nextPlayer returns 'nil' if game is over (win or tie)
while currPlayer := [game nextPlayer]:
    // player will tell board where to place piece
    [currPlayer move]

または:

// nextPlayer always returns a valid player
while currPlayer := [game nextPlayer]:
    // player's method returns what and where to place
    [self place:[currPlayer move] for:currPlayer]
    // explicitly test for game end, which includes wins & ties
    if [game isOver]:
        break
于 2009-12-29T03:48:20.713 に答える