二人のプレイヤーでじゃんけんを行うようなクラスを作成すること考えます。 「プレイヤー」は「戦略」を持ち、その戦略に従って「手」を出します。 手には Gu, Choki, Pa があります。 プレイヤーは「ボックス」において双方の手を出し、一回の勝敗を決めます。
このようなクラスを作成するため、以下の小問に答えなさい。
以下のプログラムが動作するように、クラス Hand1 を作成しなさい。 なお、Hand1 のヘッダファイルは Hand.h, プログラムファイルは Hand1.m と しなさい。 必要であれば、さらにクラスを追加して良い。
#import <Foundation/NSString.h>
#import "Hand1.h"
int main(void){
int i;
for(i=0; i<3; i++){
Hand1* hand = [[Hand1 alloc] initWithType: i];
NSLog(@"%@",[hand toString]);
[hand release];
}
return 0;
}
Gu Choki Pa
(但し、 NSLog の仕様により、各文字列の左側にプロセス番号などの情報が表 示される)
まず、下記のクラスと interface を追加してください。
#import <Foundation/NSString.h>
@class Hand;
@protocol Hand
- (int) wins: (Hand *) h;
- (int) getType;
- (NSString*)toString;
@end
#import <Foundation/NSObject.h>
#import <Foundation/NSArray.h>
#import "Hand.h"
@protocol HandBuilder
- (Hand*)newHand:(int)hand;
@end
@interface HandBuilder1 : NSObject<HandBuilder>
- (Hand*)newHand:(int)hand;
@end
#import <Foundation/NSObject.h>
#import "Hand.h"
#import "HandBuilder.h"
@implementation HandBuilder1
-(Hand*)newHand:(int)hand{
if(hand <0 || hand>2 ) return nil;
return [[Hand1 alloc] initWithType:hand];
}
-(void) release
{
[super release];
}
@end
そして、問 1-1 で作成した Hand1 のプロトコルとして Hand 指定し、さらに、 次の条件を満たすように getType メソッドと wins メソッドを実装しなさい。
そして、下記のテストプログラムを実行し、出力が予想と一致しているか確か めなさい。
#import <Foundation/NSString.h>
#import <Foundation/NSArray.h>
#import "Hand.h"
#import "HandBuilder.h"
int main(void){
int i,j;
id<HandBuilder> hb = [[HandBuilder1 alloc] init];
NSMutableArray* h = [[NSMutableArray alloc] initWithCapacity: 3];
for(i=0; i<3; i++){
[h addObject: [hb newHand: i]];
}
NSLog(@"\t%@\t%@\t%@\n"
,[[h objectAtIndex: 0 ] toString]
,[[h objectAtIndex: 1 ] toString]
,[[h objectAtIndex: 2 ] toString]
);
for(i=0; i<3; i++){
NSMutableString* line = [[NSMutableString alloc] init];
id<Hand> hand = [h objectAtIndex: i];
[line appendFormat:@"%@\t",[hand toString]];
for(j=0; j<3; j++){
int result = [hand wins:[h objectAtIndex: j ]];
[line appendFormat:@"%d\t",result];
}
NSLog(line);
[line release];
}
[h release];
return 0;
}
Gu Choki Pa Gu 0 1 -1 Choki -1 0 1 Pa 1 -1 0
さらに、下記のクラスを追加します。
#import <Foundation/NSObject.h>
#import "Hand.h"
#import "HandBuilder.h"
@interface Tactics : NSObject
{
id handBuilder;
}
- (void)setHandBuilder: (id) hb;
- (Hand*)newHand;
@end
#import "Tactics.h"
@implementation Tactics
- (void)setHandBuilder:(id) hb
{
if(handBuilder != hb){
[handBuilder release];
handBuilder = [hb retain];
}
}
-(void)dealloc {
[handBuilder release];
[super dealloc];
}
@end
この Tactics を継承し、次の条件を満たすクラス Tactics1, Tactics2 を作 成しなさい。
作成した Tactics1, Tactics2 に対して、下記のテストプログラムを実行し、 正常に動作していることを示しなさい。
@interface Hand0 : NSObject<Hand>
{
NSString* gu;
}
- (int) wins: (Hand *) h;
- (int) getType;
- (NSString*)toString;
@end
#import <Foundation/NSString.h>
#import "Hand.h"
@implementation Hand0
- (id)initWithType:(int)t{
if(self = [super init]){
gu=[[NSString alloc] initWithString:@"Gu"];
}
return self;
}
- (int)getType{
return 0;
}
- (int)wins:(Hand *)hand{
return 0;
}
- (NSString*)toString{
return gu;
}
-(void)dealloc {
[gu release];
[super dealloc];
}
@end;
@interface HandBuilder0 : NSObject<HandBuilder>
- (Hand*)newHand:(int)hand;
@end
#import "HandBuilder.h"
#import "Hand.h"
@implementation HandBuilder0
- (Hand*) newHand:(int) hand{
return [[Hand0 alloc] initWithType: 0];
}
@end
#import <Foundation/NSString.h>
#import "Hand.h"
#import "HandBuilder.h"
#import "Tactics.h"
void examineTactics(Tactics* t, id<HandBuilder> hb){
int i;
NSMutableString* line = [[NSMutableString alloc] init];
[t setHandBuilder:hb];
for(i=1; i<=20 ; i++){
Hand* hand = (Hand*) [t newHand];
[line appendFormat:@"%d: %@ ",i,[hand toString]];
[hand release];
}
NSLog(@"%@",line);
[line release];
}
int main(void){
id<HandBuilder> hb0 = [[HandBuilder0 alloc] init];
id<HandBuilder> hb1 = [[HandBuilder1 alloc] init];
Tactics* t = [[Tactics1 alloc] init];
examineTactics(t, hb0);
[t release];
t = [[Tactics1 alloc] init];
examineTactics(t, hb1);
[t release];
t = [[Tactics2 alloc] init];
examineTactics(t,hb0);
[t release];
t = [[Tactics2 alloc] init];
examineTactics(t,hb1);
[t release];
[hb0 release];
[hb1 release];
return 0;
}
なお、三行目はランダムに出るので、必ず上記のようになるわけではありませ ん。 Gu, Choki, Pa が大体 1/3 出ていれば構いません。 しかし、他の行は必ず上記の出力と一致すること。
下記のクラス Box を追加します。
#import <Foundation/NSObject.h>
#import <Foundation/NSArray.h>
#import "Player.h"
@interface Box:NSObject
{
Player* player1;
Player* player2;
}
- (void)setPlayer1:(Player*) p;
- (void)setPlayer2:(Player*) p;
- (NSArray*)newPlay;
@end;
#import <Foundation/NSObject.h>
#import <Foundation/NSArray.h>
#import "Hand.h"
#import "Player.h"
#import "Box.h"
@implementation Box
- (void)setPlayer1:(Player*) p
{
if(player1!=p){
[player1 release];
player1 = [p retain];
}
}
- (void)setPlayer2:(Player*) p
{
if(player2!=p){
[player2 release];
player2 = [p retain];
}
}
- (NSArray*)newPlay{
NSMutableArray* result = [[NSMutableArray alloc] initWithCapacity:2];
Hand* h1 = [player1 newHand];
Hand* h2 = [player2 newHand];
[result addObject: h1];
[result addObject: h2];
switch([h1 wins:h2]){
case -1:
[player1 lose];
[player2 win];
break;
case 0:
[player1 draw];
[player2 draw];
break;
case 1:
[player1 win];
[player2 lose];
break;
}
[h1 release];
[h2 release];
return result;
}
-(void) dealloc
{
[player1 release];
[player2 release];
[super dealloc];
}
@end
このプログラムが動作するように Player クラスを作成しなさい。 Player クラスには、 getHand,win, lose, draw メソッドを実装し ます。 さらに、次の条件にも合致するようにメソッドを実装して下さい。
名前 : 勝った数 win(s), 負けた数 lose(s), 引き分けの数 draw(s)
そして、下記のテストプログラムで動作を確認しなさい。
@interface Tactics0 : Tactics
{
}
- (Hand*)newHand;
@end
#import "Tactics.h"
@implementation Tactics0
- (Hand*)newHand
{
Hand* hand = [handBuilder newHand: 1];
return hand;
}
@end
#import "Hand.h"
#import "HandBuilder.h"
#import "Tactics.h"
#import "Box.h"
#import "Player.h"
static int round=0;
void test(Tactics* t1, id<HandBuilder> h1, Tactics* t2, id<HandBuilder> h2){
int i;
[t1 setHandBuilder: h1];
[t2 setHandBuilder: h2];
NSLog(@"Test %d",++round);
Player* player1 = [[Player alloc] initWithString:@"Kaiji"];
[player1 setTactics:t1];
Player* player2 = [[Player alloc] initWithString:@"Funai"];
[player2 setTactics:t2];
Box* box = [[Box alloc] init];
[box setPlayer1:player1];
[box setPlayer2:player2];
for(i=1; i<=10; i++){
NSArray* h = [box newPlay];
NSMutableString* line = [[NSMutableString alloc]init];
[line appendFormat:@"%d: %@ v.s. %@"
,i
,[[h objectAtIndex: 0] toString]
,[[h objectAtIndex: 1] toString]
];
NSLog(@"%@",line);
[line release];
[h release];
}
NSLog(@"%@",[player1 result]);
NSLog(@"%@",[player2 result]);
[player1 release];
[player2 release];
[box release];
}
int main(){
id<HandBuilder> hb0 = [[HandBuilder0 alloc] init];
id<HandBuilder> hb1 = [[HandBuilder1 alloc] init];
Tactics* t0;
Tactics* t1;
t0 = [[Tactics1 alloc] init];
t1 = [[Tactics0 alloc] init];
test(t0, hb0, t1 ,hb0);
[t0 release];
[t1 release];
t0 = [[Tactics2 alloc] init];
t1 = [[Tactics0 alloc] init];
test(t0, hb1, t1 ,hb1);
[t0 release];
[t1 release];
t0 = [[Tactics2 alloc] init];
t1 = [[Tactics2 alloc] init];
test(t0, hb1, t1 ,hb0);
[t0 release];
[t1 release];
t0 = [[Tactics1 alloc] init];
t1 = [[Tactics2 alloc] init];
test(t0, hb1, t1 ,hb1);
[t0 release];
[t1 release];
[hb0 release];
[hb1 release];
return 0;
}
Test 1 1: Gu v.s. Gu 2: Gu v.s. Gu 3: Gu v.s. Gu 4: Gu v.s. Gu 5: Gu v.s. Gu 6: Gu v.s. Gu 7: Gu v.s. Gu 8: Gu v.s. Gu 9: Gu v.s. Gu 10: Gu v.s. Gu Kaiji: 0 win(s), 0 lose(s), 10 draw(s) Funai: 0 win(s), 0 lose(s), 10 draw(s) Test 2: 1: Choki v.s. Choki 2: Choki v.s. Choki 3: Gu v.s. Choki 4: Choki v.s. Choki 5: Gu v.s. Choki 6: Choki v.s. Choki 7: Choki v.s. Choki 8: Pa v.s. Choki 9: Choki v.s. Choki 10: Choki v.s. Choki Kaiji: 2 win(s), 1 lose(s), 7 draw(s) Funai: 1 win(s), 2 lose(s), 7 draw(s) Test 3: 1: Gu v.s. Choki 2: Choki v.s. Choki 3: Pa v.s. Choki 4: Gu v.s. Choki 5: Choki v.s. Choki 6: Pa v.s. Choki 7: Gu v.s. Choki 8: Choki v.s. Choki 9: Pa v.s. Choki 10: Gu v.s. Choki Kaiji: 4 win(s), 3 lose(s), 3 draw(s) Funai: 3 win(s), 4 lose(s), 3 draw(s) Test 4: 1: Gu v.s. Gu 2: Choki v.s. Gu 3: Pa v.s. Gu 4: Gu v.s. Gu 5: Choki v.s. Gu 6: Pa v.s. Gu 7: Gu v.s. Gu 8: Choki v.s. Gu 9: Pa v.s. Gu 10: Gu v.s. Gu Kaiji: 3 win(s), 3 lose(s), 4 draw(s) Funai: 3 win(s), 3 lose(s), 4 draw(s) Test 5: 1: Pa v.s. Gu 2: Gu v.s. Choki 3: Pa v.s. Pa 4: Gu v.s. Gu 5: Pa v.s. Choki 6: Choki v.s. Pa 7: Pa v.s. Gu 8: Choki v.s. Choki 9: Gu v.s. Pa 10: Pa v.s. Gu Kaiji: 5 win(s), 2 lose(s), 3 draw(s) Funai: 2 win(s), 5 lose(s), 3 draw(s)
なお、上記の勝敗の数字の一部は乱数によって変化しますので、この通りの出力が必ず出るわけではありません。 自ら行った各テストがそれぞれ成功しているかどうか、理由をつけて説明しなさい。 また、レポート作成時には、テスト結果全てを添付して下さい。
HandBuilder1 クラスの newHand は毎回 Hand オブジェクトを作成しています。 しかし、実際に必要なのは Gu, Choki, Pa のそれぞれのオブジェクトだけで す。 そこで、シングルトンデザインパターンのような考え方で、オブジェクトは Gu, Choki, Pa の 3 つしか生成しない getInstance メソッドを持つ HandBuilder2 を作成しなさい。 なお、必要であれば、 Hand1 など他のクラスも置き換えても構いません。
そして、次のテストプログラムにおいて、 Ok が 3 つ出ることを確認しなさ い。
#import <Foundation/NSArray.h>
#import "Hand.h"
#import "HandBuilder.h"
int main(){
int i,j;
id<HandBuilder> hb = [[HandBuilder2 alloc] init];
NSMutableArray* h = [[NSMutableArray alloc] initWithCapacity: 2];
for(j=0; j<2; j++){
NSMutableArray* ha = [[NSMutableArray alloc] initWithCapacity: 3];
for(i=0; i<3; i++){
[ha addObject: [hb newHand:i]];
}
[h addObject: ha];
[ha release];
}
for(i=0; i<3; i++){
NSMutableString* line = [[NSMutableString alloc] init];
Hand* h0 = [[h objectAtIndex: 0] objectAtIndex: i];
Hand* h1 = [[h objectAtIndex: 1] objectAtIndex: i];
[line appendString:[h0 toString]];
if(h0 == h1){
[line appendString:@" Ok"];
}else{
[line appendString:@" NG"];
}
NSLog(@"%@",line);
[line release];
}
[h release];
[hb release];
return 0;
}
Gu Ok Choki Ok Pa Ok
そして、次のプログラムを動作させ、効果を確かめなさい。 なお、下記のプログラムにおいて heap エラーが出るときは、繰り返し回数を 10万回に減らしても良い。
./test6 1 と動かすと HandBuilder1 が動作し、 ./test6 2 で動かすと HandBuilder2 が動作します。 これをそれぞれでたらめな順番で 5 回位計測して平均をとると、それなりに正確な計測になると期待できます。
#include <sys/timeb.h>
#import <Foundation/NSString.h>
@interface StopWatch : NSObject
{
struct timeb now;
NSString* resultString;
}
- (NSString*) toString;
@end
#include <sys/timeb.h>
#import <Foundation/NSString.h>
#import "StopWatch.h"
@implementation StopWatch
- (id) init
{
if((self = [super init])!=nil){
ftime(&now);
}
return self;
}
- (NSString*) toString
{
struct timeb next;
ftime(&next);
double result = next.time-now.time
+(double)next.millitm/1000-(double)now.millitm/1000;
now = next;
[resultString release];
resultString = [[NSString alloc] initWithFormat:@"%f",result];
return resultString;
}
-(void)dealloc
{
[resultString release];
[super dealloc];
}
@end
#import <Foundation/NSArray.h>
#import "Hand.h"
#import "HandBuilder.h"
#import "Tactics.h"
#import "Box.h"
#import "Player.h"
#import "StopWatch.h"
void test(id<HandBuilder> hb){
int i;
Player* player1 = [[Player alloc] initWithString:@"Kaiji"];
Tactics* t1 = [[Tactics1 alloc] init];
[t1 setHandBuilder: hb];
[player1 setTactics: t1];
Player* player2 = [[Player alloc] initWithString:@"Funai"];
Tactics* t2 = [[Tactics2 alloc] init];
[t2 setHandBuilder: hb];
[player2 setTactics: t2];
Box* box = [[Box alloc] init];
[box setPlayer1:player1];
[box setPlayer2:player2];
NSMutableArray* list = [[NSMutableArray alloc] init];
for(i=1; i<=1000000; i++){
NSArray* result = [box newPlay];
[list addObject: result];
[result release];
}
NSLog(@"%@",[player1 result]);
NSLog(@"%@",[player2 result]);
[player1 release];
[player2 release];
[t1 release];
[t2 release];
[box release];
[list release];
}
int main(int argc, char* argv[]){
id<HandBuilder> hb;
if(argc!=2) return -1;
if(argv[1][0]=='1'){
hb = [[HandBuilder1 alloc] init];
}else{
hb = [[HandBuilder2 alloc] init];
}
StopWatch* sw = [[StopWatch alloc] init];
test(hb);
NSLog(@"%@",[sw toString]);
return 0;
}