• ベストアンサー

教えてください(丸罰ゲーム)

三目ゲーム(9マスの丸罰ゲーム)のプログラムを書いてコンピューターを相手に対戦したとき、コンピュータの勝率をできるだけあげるにはどうしたらいいんでしょうか??何か参考になることなんでも教えてください。ホームページなど教えてもらえれば光栄です。お願いします。

質問者が選んだベストアンサー

  • ベストアンサー
  • age_momo
  • ベストアンサー率52% (327/622)
回答No.11

No10です。斜めの判断に記述間違いがあったんでついでに少し書き足して関数にしました。 int tsuginote(int *a) { int i,j,tate,yoko,naname1=0,naname2=0,kari=99; for(i=0;i<3;i++){ for(j=0;j<3;j++){ if(a[j][i]==0){ tate=a[(j+1)%3][i]*a[(j+2)%3][i]; yoko=a[j][(i+1)%3]*a[j][(i+2)%3]; if(i==j){ naname1=a[(j+1)%3][(i+1)%3]*a[(j+2)%3][(i+2)%3]; } if(i+j==2){ naname2=a[(j+1)%3][(i+2)%3]*a[(j+2)%3][(i+1)%3]; } if((tate==4)||(yoko==4)||(naname1==4)||(naname2==4)){ return 10*i+j; }else if((tate==1)||(yoko==1)||(naname1==1)||(naname2==1)){ kari=10*i+j } } } } return kari; } これで戻り値が99のときはランダムに、0-22の時はその指示通りにでどうでしょう。

その他の回答 (10)

  • age_momo
  • ベストアンサー率52% (327/622)
回答No.10

少し検索していて面白そうな質問にたどり着きました。 >例えば2つ並んだら3つ目は必ず取りに行くようなプログラムは書けるでしょうか? 例えば最初は全て0で、相手が取れば1、自分がとれば2を配列に入れておけば for(i=0;i<3;i++){ for(j=0;j<3;j++){ tate=a[(j+1)%3][i]*a[(j+2)%3][i]; yoko=a[j][(i+1)%3]*a[j][(i+2)%3]; if(i+j==4){ naname1=a[(j+1)%3][(i+1)%3]*a[(j+2)%3][(i+2)%3]; naname2=a[(j+1)%3][(i+2)%3]*a[(j+2)%3][(i+1)%3]; }else{naname1=0; naname2=0; } } } でtate,toko,naname1,2に4があれば無条件にループを抜け出して終了、1があれば(i,j)を記憶しておいて一通り調べて他のところに4がなければ優先的に、0,2は放っておくということでどうでしょう?tate,yoko,naname1,2は配列にしてもいいですしループを抜ける条件等を適当に付け足してください。 基本的にはVB使いですので文法が間違ってたらごめんなさい。

回答No.9

> 二つ並んでる場合を1つずつ列挙して、そのときはここ、そのときはここってif文に当てはめていけばいいんですか? だらだら書き並べてみました。。。9通り if (((a[0][0]==AKI)&&(a[0][1]==MARU)&&(a[0][2]==MARU))||((a[0][0]==AKI)&&(a[1][0]==MARU)&&(a[2][0]==MARU))||((a[0][0]==AKI)&&(a[1][1]==MARU)&&(a[2][2]==MARU))) a[0][0]=MARU; if (((a[2][0]==AKI)&&(a[0][0]==MARU)&&(a[1][0]==MARU))||((a[2][0]==AKI)&&(a[2][1]==MARU)&&(a[2][2]==MARU))||((a[2][0]==AKI)&&(a[1][1]==MARU)&&(a[0][2]==MARU))) a[2][0]=MARU; if (((a[0][2]==AKI)&&(a[0][0]==MARU)&&(a[0][1]==MARU))||((a[0][2]==AKI)&&(a[1][2]==MARU)&&(a[2][2]==MARU))||((a[0][2]==AKI)&&(a[1][1]==MARU)&&(a[2][0]==MARU))) a[0][2]=MARU; if (((a[2][2]==AKI)&&(a[2][0]==MARU)&&(a[2][1]==MARU))||((a[2][2]==AKI)&&(a[0][2]==MARU)&&(a[1][2]==MARU))||((a[2][2]==AKI)&&(a[1][1]==MARU)&&(a[0][0]==MARU))) a[2][2]=MARU; if (((a[0][1]==AKI)&&(a[0][0]==MARU)&&(a[0][2]==MARU))||((a[0][1]==AKI)&&(a[1][1]==MARU)&&(a[2][1]==MARU))) a[0][1]=MARU; if (((a[1][0]==AKI)&&(a[0][0]==MARU)&&(a[2][0]==MARU))||((a[1][0]==AKI)&&(a[1][1]==MARU)&&(a[1][2]==MARU))) a[1][0]=MARU; if (((a[1][2]==AKI)&&(a[1][0]==MARU)&&(a[1][1]==MARU))||((a[1][2]==AKI)&&(a[0][2]==MARU)&&(a[2][2]==MARU))) a[1][2]=MARU; if (((a[2][1]==AKI)&&(a[0][1]==MARU)&&(a[1][1]==MARU))||((a[2][1]==AKI)&&(a[2][0]==MARU)&&(a[2][2]==MARU))) a[2][1]=MARU; if (((a[1][1]==AKI)&&(a[0][0]==MARU)&&(a[2][2]==MARU))||((a[1][1]==AKI)&&(a[0][2]==MARU)&&(a[2][0]==MARU))) a[1][1]=MARU;

回答No.8

> 二つ並んでる場合を1つずつ列挙して、そのときはここ、そのときはここってif文に当てはめていけばいいんですか? いいんじゃないですか。 だらだら書き並べたところで高々8通りですから。

回答No.7

プログラム例・・・適当に書いたので長いです。すいません。 #include <stdio.h> #define MARU 1 #define BATU 4 #define DRAW 10 /* 3x3の盤 0:空き MARU:○ BATU:× */ typedef struct { char xy[3][3]; } MATRIX; /* 勝敗チェック 0:未 MARU:○ BATU:× DRAW:引き分け */ int check(MATRIX ban) { int i,j,p; /* 引き分け? */ for (p=0,i=0; i<3; i++) for (j=0; j<3; j++) p += (ban.xy[i][j]==0)?0:1; if (p==9) return DRAW; /* 縦横? */ for (i=0; i<3; i++) { p=ban.xy[i][0]+ban.xy[i][1]+ban.xy[i][2]; if (p==MARU*3) return MARU; else if (p==BATU*3) return BATU; p=ban.xy[0][i]+ban.xy[1][i]+ban.xy[2][i]; if (p==MARU*3) return MARU; else if (p==BATU*3) return BATU; } /* 斜め */ p=ban.xy[0][0]+ban.xy[1][1]+ban.xy[2][2]; if (p==MARU*3) return MARU; else if (p==BATU*3) return BATU; p=ban.xy[2][0]+ban.xy[1][1]+ban.xy[0][2]; if (p==MARU*3) return MARU; else if (p==BATU*3) return BATU; return 0; } void display(MATRIX ban) { int i,j; for (i=0; i<3; i++) { for (j=0; j<3; j++) { switch(ban.xy[i][j]) { case 0: printf(" %d",i*3+j+1); break; case MARU: printf(" O"); break; case BATU: printf(" X"); break; default: printf(" ?"); } } printf("\n"); } printf("\n"); } void man(MATRIX *ban, int turn) { int i; for(;;) { printf("? "); scanf("%d",&i); i--; if ((i<0)||(i>8)) continue; if (ban->xy[i/3][i%3]==0) { ban->xy[i/3][i%3]=turn; break; } } } void com(MATRIX *ban, int turn) { int i,j; MATRIX tmp; tmp= *ban; /* 次の手で勝つ? */ for (i=0; i<3; i++) { for (j=0; j<3; j++) { if (tmp.xy[i][j]==0) { tmp.xy[i][j]=turn; if (check(tmp)>0) { ban->xy[i][j] = turn; return; } tmp.xy[i][j]=0; } } } /* 相手が勝つ? */ for (i=0; i<3; i++) { for (j=0; j<3; j++) { if (tmp.xy[i][j]==0) { tmp.xy[i][j]=(turn==MARU)?BATU:MARU; if (check(tmp)>0) { ban->xy[i][j]=turn; return; } tmp.xy[i][j]=0; } } } /* 空いているところに打つ */ for (i=0; i<3; i++) { for (j=0; j<3; j++) { if (tmp.xy[i][j]==0) { ban->xy[i][j]=turn; return; } } } } int main(void) { MATRIX ban={{{0,0,0},{0,0,0},{0,0,0}}}; int r; display(ban); for (;;) { man(&ban, MARU); display(ban); if ((r=check(ban)) != 0) break; com(&ban, BATU); display(ban); if ((r=check(ban)) != 0) break; } switch(r) { case MARU: printf("○の勝ち\n"); break; case BATU: printf("×の勝ち\n"); break; default: printf("引き分け\n"); } return 0; }

回答No.6

> 例えば2つ並んだら3つ目は必ず取りに行くようなプログラムは書けるでしょうか? 空いているところに1個ずつ入れてみて3個並ぶかどうか調べればいいと思います。。 試しにゲーム木を作ってみましたが、回転・鏡像を考えないで255168通り(oの勝ち131184通り、xの勝ち77904通り、引き分け46080通り)でした。(違ってるかも)

hyokkorri
質問者

補足

なんかうまく書けないんですけど。。プログラム例とゆーか書いてもらえないでしょうか。。すいませんお願いします!!

回答No.5

> 例えば2つ並んだら3つ目は必ず取りに行くようなプログラムは書けるでしょうか? なにか難しい点がありますか? 二つ並んだ箇所を探すだけでしょうに。

hyokkorri
質問者

お礼

そーなんですよね。。二つ並んでる場合を1つずつ列挙して、そのときはここ、そのときはここってif文に当てはめていけばいいんですか?

回答No.4

九つのマスを○×で埋める組み合わせは3024通りしかありませんから、全てを列挙し、負ける手を打たせなければよいのでは、と。

hyokkorri
質問者

補足

#include<stdio.h> #include <stdlib.h> #include <time.h> //座標の構造体 typedef struct{ int gyou; int retu; }matrix_t; //プロトタイプ宣言 matrix_t input(int a[][3]); //プレイヤーの入力 int chk(int a[][3]); //そろったかどうかを判定 void display(int a[][3]); //ボードを表示。 matrix_t sikou(int a[][3]); //コンピュータの思考 (中略) //コンピュータの思考 matrix_t sikou(int a[][3]) { matrix_t temp; int i,j; //ランダムな場所を指定 srand((unsigned int)time(NULL)); while(1){ temp.gyou=rand()%3; temp.retu=rand()%3; if(!a[temp.gyou][temp.retu])return temp; } } コンピュータの思考がランダムに与えられている部分をうまく変えたいんですよ。これだけではわかりにくいと思いますが。。何かいい方法はないでしょうか?例えば2つ並んだら3つ目は必ず取りに行くようなプログラムは書けるでしょうか?

回答No.3

対戦プログラムの場合、一般的にはゲーム木を考えます。 3×3マスでしたら全パターンを調べてもそんなに時間はかからないでしょう。将棋やチェスだと木が大きくなるので枝狩りをする必要がありますし、強いプログラムを作ろうと思ったら枝狩りの方法や評価関数など工夫が必要です。 「ゲーム理論」で検索すると参考になるサイトがヒットするかもしれません。。

noname#8185
noname#8185
回答No.2

先手であれば「勝ち」か「引き分け」に持っていけます ということは後手では 「負け」か「引き分け」ですね 説明は長くなります

  • twk
  • ベストアンサー率29% (18/62)
回答No.1

○×ゲームは、両者最善を尽くすと必ず引き分けになります。 先読みをしても良いですが、パターンは限られているので、ある程度手順を記憶させておいても良いかもしれません。

hyokkorri
質問者

補足

#include<stdio.h> #include <stdlib.h> #include <time.h> //座標の構造体 typedef struct{ int gyou; int retu; }matrix_t; //プロトタイプ宣言 matrix_t input(int a[][3]); //プレイヤーの入力 int chk(int a[][3]); //そろったかどうかを判定 void display(int a[][3]); //ボードを表示。 matrix_t sikou(int a[][3]); //コンピュータの思考 (中略) //コンピュータの思考 matrix_t sikou(int a[][3]) { matrix_t temp; int i,j; //ランダムな場所を指定 srand((unsigned int)time(NULL)); while(1){ temp.gyou=rand()%3; temp.retu=rand()%3; if(!a[temp.gyou][temp.retu])return temp; } } コンピュータの思考がランダムに与えられている部分をうまく変えたいんですよ。これだけではわかりにくいと思いますが。。何かいい方法はないでしょうか?例えば2つ並んだら3つ目は必ず取りに行くようなプログラムは書けるでしょうか?

関連するQ&A