プログラム完成
後、これの解説をレポートにまとめなきゃなんないんですよねぇ。
戦略とかは、まぁ書くべきだとは思いますが、コメント付きのプログラムリストも載せるのに、わざわざプログラムを見なくても何をするかがわかるような解説、書かせる必要はないですよねぇ……
完成ついでに全文貼り付けてみる。(約180行)
#include <stdio.h> #include <stdlib.h> #include <time.h> /*最大解析深度*/ #define MAXDEPTH 5 /*ログ解析&次の手予想の関数*/ unsigned short logcheck(unsigned short depth); /*プレイヤーの手のログ用構造体*/ struct{ unsigned short *ary;/*ログ記憶配列*/ unsigned short size;/*配列サイズ*/ unsigned short cnt;/*現在の記憶数*/ } log; int main(void){ unsigned short /*PC側の手*/cpu,/*プレイヤーの手*/p; #ifdef _DEBUG unsigned short i;/*デバッグ時に使用するカウンタ変数*/ #endif char tmp[4];/*入力受付用文字列*/ char hand[3][7]={{"グー"},{"チョキ"},{"パー"}};/*手表示用配列*/ unsigned short game[3]={0,0,0};/*勝敗カウンタ*/ /*ログのサイズ設定*/ log.size = 10; log.ary = malloc(sizeof(unsigned short)*log.size); /*乱数初期化*/ srand((unsigned)time(NULL)); /*メイン(無限)ループ*/ for(log.cnt=0;1;log.cnt++){ /*PC側の手を決定*/ cpu = logcheck( MAXDEPTH ); #ifdef _DEBUG printf("%d\n",cpu);/*PC側の手を表示(デバッグ用)*/ #endif /*入力の受付*/ printf("グーチョキパーをそれぞれ1,2,3として入力してください。(1,2,3以外で終了)\n"); scanf("%3s",&tmp); p=(unsigned short)atoi(tmp);/*文字列を数値へ*/ if(p<1||3<p)break;/*範囲外なら終了*/ fflush(stdin);/*次回入力のためのバッファ消去*/ printf("あなたの手 : %s\nコンピュータの手 : %s\n",hand[p-1],hand[cpu]); /*プレイヤーの出した手をログに記憶*/ log.ary[log.cnt]=p; /*勝敗判定と結果の記憶*/ switch((cpu-p+4)%3){ case 0: printf("あいこです。\n"); game[2]++; break; case 1: printf("あなたの勝ちです。\n"); game[0]++; break; case 2: printf("あなたの負けです。\n"); game[1]++; break; } #ifdef _DEBUG /*プレイヤーの手のログを表示(デバッグ用)*/ for(i=0;i<=log.cnt;i++) printf("%d ",log.ary[i]); printf("\n"); #endif /*手を記憶するログのサイズが足らなくなったら再確保*/ if(log.cnt>=log.size-1){ log.size +=(short) 10; log.ary=realloc(log.ary,sizeof(unsigned short)*log.size); } } printf("\n%d戦して、あなたは%d勝%d敗%d分け、勝率%.3lfでした。\n",log.cnt,game[0],game[1],game[2],(float)(game[0])/(float)(log.cnt==0?1:log.cnt)); /*割り当てたメモリを解放*/ free(log.ary); return 0; } /*ログ解析&次の手予想の関数*/ unsigned short logcheck(unsigned short depth/*解析深度*/){ unsigned short i,j,k;/*全てカウンタ変数*/ unsigned short ptn[3]={0,0,0};/*出現パターン記憶用配列*/ unsigned short lmt;/*近似の揺れの範囲*/ if(log.cnt<depth){ if(log.cnt<3) return (unsigned short)(rand()%3); else depth=(unsigned short)(log.cnt-1); } /*指定深度以下でのパターンの検索*/ for(i=1;i<=depth;i++){ for(j=0;j<log.cnt-i-1;j++){ for(k=0;k<i;k++){ if(log.ary[j+k]!=log.ary[(log.cnt-i)+k]) break;/*パターン合致しなければ脱出*/ } /*パターン合致(forが完了)したならば、そのパターンでの予想を記憶 長いパターンに合致した時ほど、記憶時に加算する値を大きくする*/ if(k>=i) ptn[log.ary[j+i]-1]+=i; } } #ifdef _DEBUG /*パターンの出現回数(デバッグ)*/ printf("%2d %2d %2d ",ptn[0],ptn[1],ptn[2]); #endif /*近似の揺れの決定*/ if(ptn[0]>ptn[1]){ if(ptn[0]>ptn[2]) lmt=(unsigned short)(ptn[0]/5); else lmt=(unsigned short)(ptn[1]/5); }else{ if(ptn[1]>ptn[2]) lmt=(unsigned short)(ptn[1]/5); else lmt=(unsigned short)(ptn[2]/5); } /*記憶した出現回数に併せて予想を立てる*/ if(abs(ptn[0]-ptn[1])<=lmt){/*グーとチョキがほぼ同数か?*/ if(abs(ptn[1]-ptn[2])<=lmt){/*チョキとパーがほぼ同数か?*/ return (short)(rand()%3);/*予想不能(全部ほぼ同じ回数)*/ }else if(ptn[1]<ptn[2]){ return 1;/*パーを予想*/ }else{ if(abs(ptn[2]*1.5-ptn[1])<=lmt){/*パーがそこそこ多いか?*/ return (short)((rand()%2)*2);/*グーかチョキを予想(パーも結構ある)*/ }else{ return 0;/*グーかチョキを予想(パーは少ない)*/ } } }else if(ptn[0]>ptn[1]){ if(abs(ptn[0]-ptn[2])<=lmt){/*グーとパーがほぼ同数か?*/ if(abs(ptn[1]*1.5-ptn[2])<=lmt){/*チョキがそこそこ多いか?*/ return (short)((rand()%2)+1);/*グーかパーを予想(チョキも結構ある)*/ }else{ return 2;/*グーかパーを予想(チョキは少ない)*/ } }else if(ptn[0]>ptn[2]){ return 2;/*グーを予想*/ }else{ return 1;/*パーを予想*/ } }else{ if(abs(ptn[1]-ptn[2])<=lmt){/*チョキとパーがほぼ同数か?*/ if(abs(ptn[0]*1.5-ptn[1])<=lmt){/*グーがそこそこ多いか?*/ return (unsigned short)((rand()%2));/*チョキかパーを予想(グーも結構ある)*/ }else{ return 1;/*チョキかパーを予想(グーは少ない)*/ } }else if(ptn[1]>ptn[2]){ return 0;/*チョキを予想*/ }else{ return 1;/*パーを予想*/ } } }