NNCardDeck version0.4(5)
いつまでやっているんでしょうか、ひとつのクラスの設計を(笑)。……自分でも早く次へ取りかかりたい、と思いつつ(笑)。
できれば先送りできる問題は先送りして(笑)、とりあえず「BlackJack version0.4」を完成させたいとは思っているのですが。……いやいや、これでも未完成だが(笑)。とにかく、問題なく動くレベルまでは早くもって行きたい、と。
さっさと片づけてしまいましょう。
次はカード配列を作るメソッド。
さて、内部で保持するカード用の値の配列が整理できた所で、今度はカードオブジェクトを保持するNSMutableArray *cardArrayに、カードオブジェクトを初期化して埋め込んで行くメソッド。
これ自体はヴァージョン0.3でもやっていたことで、見かけ上は複雑ですが、中身は単純作業をカードの枚数だけ繰り返すだけ。
ただし、今回はNNCardDeckオブジェクトにカードがもつ値を保持しています。ゲーム中にカードの固有値を変える必要がないのなら、この内部定数でカードオブジェクトを作り直すことが可能。
つまり、いちいち初期化しないで、内部定数でカードオブジェクトの生成が可能です。
という訳で、初期化メソッドに加えて、同じNNCardDeckオブジェクトを保持したままカード配列を作り直すメソッドを追加することに。
具体的には、メモリーの確保からカードオブジェクトの埋め込みまで行なう初期化メソッドとは別に、現在のオブジェクトにカード配列だけを作り直すメソッドを加えます。
両方ともカード配列を作る部分は一緒で、初期化メソッド(プリミティブ・メソッド)の場合は定数配列を初期化してそこからカード配列を作るのに対し、「作り直し」メソッドではすでに作られた定数配列を利用します。
これは内部のカード配列carrdArrayから全てのカードオブジェクトを取り除き、新たに生成したカードを埋め込むことになります。
で、この場合カードオブジェクトの生成は両方で共通のコードになりますので、この部分を別のメソッドとして用意します。
ヴァージョン0.3とは違い、今回は53枚それぞれに個別のデータを埋め込みます。ある程度の汎用性を持たせるなら、それぞれのカードに独自の値を振り分けられるようにするためです。そのために、1セット53枚ごとにリセットされるvalueIndex変数を用意してあります。
- (void)makeCardArray { int i,j,k; int l = 0; unsigned valueIndex; id object; for (i=0; i < deckValue; i++) { valueIndex = 0; for (j=0; j < 4; j++) { for (k=0; k < 13; k++) { char suit = charSuits[j]; char num = charNumbers[k]; int stdValue = [[stdValues objectAtIndex:valueIndex] intValue]; int altValue = [[altValues objectAtIndex:valueIndex] intValue]; BOOL valueFlag = [[valueFlags objectAtIndex:valueIndex] boolValue]; BOOL boolFlag = [[boolFlags objectAtIndex:valueIndex] boolValue]; int intFlag = [[intFlags objectAtIndex:valueIndex] intValue]; object = [[NNCard alloc] initWithSuit:suit charNum:num stdValue:stdValue altValue:altValue valueFlag:valueFlag boolFlag:boolFlag intFlag:intFlag]; if (object != nil) { [cardArray addObject:object]; } valueIndex++; } } if (jokerValue > l) { // ジョーカーカードの初期化メソッド object = [[NNCard alloc] initWithSuit:charSuits[4] charNum:charNumbers[13] stdValue:[[stdValues objectAtIndex:52] intValue] altValue:[[altValues objectAtIndex:52] intValue]]; if (object != nil) { [cardArray addObject:[object autorelease]]; } l++; } } }
このメソッドをcardArrayを初期化したあと(あるいは全てのカードオブジェクトを取り除いたあと)に呼び出すことになるわけです。
これまでの試行錯誤(笑)を踏まえた初期化メソッド(プリミティブ・メソッド)は、こうなります。
- (id)initWithStdValues:(NSArray *)sValues altValues:(NSArray *)aValues valueFlags:(NSArray *)vFlags boolFlags:(NSArray *)bFlags intFlags:(NSArray *)iFlags deckValue:(unsigned)dValue jokerValue:(unsigned)jValue { self = [super init]; if (self != nil) { randomPosition = 0; deckValue = dValue; jokerValue = jValue; cardArray = [[NSMutableArray alloc] init]; int i; // 内部の定数配列の初期化 if (sValues == nil) { NSMutableArray *tempArray; tempArray = [NSMutableArray arrayWithCapacity:53]; for (i=0; i < 53; i++) { id object; object = [[NSNumber alloc] initWithInt:initialValues[i]]; [tempArray addObject:object]; } stdValues = [[NSArray alloc] initWithArray:tempArray]; } else { stdValues = [[NSArray alloc] initWithArray:sValues]; } if (aValues == nil) { NSMutableArray *tempArray; tempArray = [NSMutableArray arrayWithCapacity:53]; for (i=0; i < 53; i++) { id object; object = [[NSNumber alloc] initWithInt:initialValues[i]]; [tempArray addObject:object]; } altValues = [[NSArray alloc] initWithArray:tempArray]; } else { altValues = [[NSArray alloc] initWithArray:aValues]; } if (vFlags == nil) { NSMutableArray *tempArray; tempArray = [[NSMutableArray alloc] initWithCapacity:53]; for (i=0; i < 53; i++) { id object; object = [[NSNumber alloc] initWithBool:NO]; [tempArray addObject:object]; } valueFlags = [[NSArray alloc] initWithArray:tempArray]; } else { valueFlags = [[NSArray alloc] initWithArray:vFlags]; } if (bFlags == nil) { NSMutableArray *tempArray; tempArray = [[NSMutableArray alloc] initWithCapacity:53]; for (i=0; i <53; i++) { id object; object = [[NSNumber alloc] initWithBool:NO]; [tempArray addObject:object]; } boolFlags = [[NSArray alloc] initWithArray:tempArray]; } else { boolFlags = [[NSArray alloc] initWithArray:bFlags]; } if (iFlags == nil) { NSMutableArray *tempArray; tempArray = [[NSMutableArray alloc] initWithCapacity:53]; for (i=0; i < 53; i++) { id object; object = [[NSNumber alloc] initWithInt:0]; [tempArray addObject:object]; } intFlags = [[NSArray alloc] initWithArray:tempArray]; } else { intFlags = [[NSMutableArray alloc] initWithArray:iFlags]; } // カード生成 [self makeCardArray]; } return self; }
さらにカードオブジェクトの再配置メソッドとして、-(void)reshuffleメソッドを加えます。
これは単純(笑)
- (void)reShuffle { [cardArray removeAllObjects]; [self makeCardArray]; }
あとは、独自のメソッド。
ランダムに一枚カードを引くメソッドですが、ランダムなカードを渡すメソッドと、渡したカードを配列から抜いてしまうメソッドを作ってみました。-(id)objectAtRandomは、ランダムに選んだカードを返すメソッド。cardArray配列からカードを抜くことはありません。-(id)oneCardは以前のヴァージョンからあった名前ですが、ランダムに選んだカードを返し、そのカード(オブジェクト)を配列から抜き取るメソッドです。
- (id)objectAtRandom { id object; srand((unsigned)time(0)); randomPosition = rand() % [cardArray count]; object = [cardArray objectAtIndex:randomPosition]; return object; } - (id)oneCard { id object; object =[[self objectAtRandom] retain]; [self removeObjectAtIndex:randomPosition]; return [object autorelease]; }
returnでメソッドを終了する前にremoveObjectAtIndex:を実行するわけですが、そうするとカードオブジェクトにreleaseが送られてしまいます(そのはず)。なので、一旦retainしてから、autoreleaseプールへ渡します。これで、コントローラでオブジェクトを解放した時に、メモリーも解放されるはず。
ここまでで、やっとソースコードがひと通り完了したことになるでしょうか。
ついでと言っては何ですが、ついでに-(id)initメソッドもオーバーライドし(一組のカードセットを作る)、さらに+cardArrayメソッドも作ってしまいました。必要かどうかはともかく(笑)。
その辺の全貌は、公開するソースコードを参照してください。……って、ただいま公開準備中(笑)。