- ベストアンサー
教えてください(丸罰ゲーム)
三目ゲーム(9マスの丸罰ゲーム)のプログラムを書いてコンピューターを相手に対戦したとき、コンピュータの勝率をできるだけあげるにはどうしたらいいんでしょうか??何か参考になることなんでも教えてください。ホームページなど教えてもらえれば光栄です。お願いします。
- みんなの回答 (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)
少し検索していて面白そうな質問にたどり着きました。 >例えば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使いですので文法が間違ってたらごめんなさい。
- JaritenCat
- ベストアンサー率37% (122/322)
> 二つ並んでる場合を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;
- επιστημη(@episteme)
- ベストアンサー率46% (546/1184)
> 二つ並んでる場合を1つずつ列挙して、そのときはここ、そのときはここってif文に当てはめていけばいいんですか? いいんじゃないですか。 だらだら書き並べたところで高々8通りですから。
- JaritenCat
- ベストアンサー率37% (122/322)
プログラム例・・・適当に書いたので長いです。すいません。 #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; }
- JaritenCat
- ベストアンサー率37% (122/322)
> 例えば2つ並んだら3つ目は必ず取りに行くようなプログラムは書けるでしょうか? 空いているところに1個ずつ入れてみて3個並ぶかどうか調べればいいと思います。。 試しにゲーム木を作ってみましたが、回転・鏡像を考えないで255168通り(oの勝ち131184通り、xの勝ち77904通り、引き分け46080通り)でした。(違ってるかも)
- επιστημη(@episteme)
- ベストアンサー率46% (546/1184)
> 例えば2つ並んだら3つ目は必ず取りに行くようなプログラムは書けるでしょうか? なにか難しい点がありますか? 二つ並んだ箇所を探すだけでしょうに。
お礼
そーなんですよね。。二つ並んでる場合を1つずつ列挙して、そのときはここ、そのときはここってif文に当てはめていけばいいんですか?
- επιστημη(@episteme)
- ベストアンサー率46% (546/1184)
九つのマスを○×で埋める組み合わせは3024通りしかありませんから、全てを列挙し、負ける手を打たせなければよいのでは、と。
補足
#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つ目は必ず取りに行くようなプログラムは書けるでしょうか?
- JaritenCat
- ベストアンサー率37% (122/322)
対戦プログラムの場合、一般的にはゲーム木を考えます。 3×3マスでしたら全パターンを調べてもそんなに時間はかからないでしょう。将棋やチェスだと木が大きくなるので枝狩りをする必要がありますし、強いプログラムを作ろうと思ったら枝狩りの方法や評価関数など工夫が必要です。 「ゲーム理論」で検索すると参考になるサイトがヒットするかもしれません。。
先手であれば「勝ち」か「引き分け」に持っていけます ということは後手では 「負け」か「引き分け」ですね 説明は長くなります
- twk
- ベストアンサー率29% (18/62)
○×ゲームは、両者最善を尽くすと必ず引き分けになります。 先読みをしても良いですが、パターンは限られているので、ある程度手順を記憶させておいても良いかもしれません。
補足
#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つ目は必ず取りに行くようなプログラムは書けるでしょうか?
補足
なんかうまく書けないんですけど。。プログラム例とゆーか書いてもらえないでしょうか。。すいませんお願いします!!