じゃんけんマシンC試作品 篠本2003/01/22 修正03/04,05/28

詳しくは「情報処理概論-予測とシミュレーション」(岩波書店)pp101-107を参照のこと.

 

janken030304.c

 

#include<stdio.h>

#include<math.h>

 

#define N 5

 

 

/*1(グー),2(チョキ),3(パー)を入力すると,前もって決めていた

マシンの手を示します.そして「勝ち,負け,引き分け」を表示.

累積度数も示します.0以下の数を入力すると終了.*/

 

int perceptron(int m, int x[], int w[], int v[])

/* 過去のデータx[]にもとづいてw[]をかけた入力v[]の最大値をとる

予想ユニットの番号(1(グー),2(チョキ),3(パー))を返す.*/

{

        int i,j,k,kmax,vmax,prec[3];

        if(m <= 0) goto end;

 

/* 前回の相手プレイヤーの手 m=1,2,3 のバイナリー表現:

グー (m=1)prec={+1,-1,-1}

チョキ(m=2)prec={-1,+1,-1}

パー (m=3)prec={-1,-1,+1} */

        for(k=0;k<3;k++)prec[k] = -1;

        prec[m-1] = +1;

       

/* 各予測ユニットの入力と相手の新しい手のコードの符号が

一致していない場合に誤り訂正学習を行う */

        for(k=0;k<3;k++){

                if(prec[k]*v[k] <= 0){

                        for(j=0;j<3*N+1;j++)  w[(3*N+1)*k+j] += prec[k]*x[j];

                }

        }

       

/* x[0] から x[3*N-1] を3ビット分右に移動 */

                /*for(i=0;i<3*N-4;i++) x[3*N-1-i]=x[3*N-4-i];オリジナル*/

for(i=0;i<3*N-3;i++) x[3*N-1-i]=x[3*N-4-i];/*青木高明氏によりバグ修正2003/03/04 */

               

/* 前回の相手プレイヤーの手{prec[0], prec[1], prec[2]}

入力スロット最前列{x[0],x[1],x[2]}に挿入 */

                for(i=0;i<3;i++)x[i]=prec[i];

               

/* 予測ユニットへの入力信号の算定 */

        for(k=0;k<3;k++)v[k]=0;

        for(k=0;k<3;k++){for(j=0;j<3*N+1;j++){

                v[k] += w[(3*N+1)*k+j]*x[j];}}

       

/* 最大入力を受けたユニットの番号(から1を引いたもの) */

        vmax=-1000000;

        for(k=0;k<3;k++){

                if(v[k] >= vmax){

                        vmax=v[k];

                        kmax=k;

                        }

        }

 

/* 最大入力を受けた予測ユニットの番号(1,2,3)を返す */

        end:   

        return(kmax+1);

}

 

 

int main()

{

        char line[100];

        int i,pred,m,v[3],x[3*N+1],w[9*N+3],fw[3];

       

/* 初期化 */

        for(i=0;i<3;i++){

                v[i] = 0;       /* 予測入力 */

                fw[i] = 0;      /* 勝敗累積 */

        }

        for(i=0;i<3*N;i++)x[i] = 0;             /* 内部状態 */

        x[3*N]=-1;                                              /* しきい */

        for(i=0;i<9*N+3;i++)w[i] = 0;   /* 重み */

       

/* ゲームの開始 */

       

        m=1;while(m>0){

 

/* パーセプトロン予測を前もって行う */

                pred=perceptron(m,x,w,v);/* pred は予測手(1,2,3) */

 

/* ここで相手プレイヤーの手をインプット */

                printf("{1(グー),2(チョキ),3(パー)}:");

                fgets(line, sizeof(line), stdin);

                sscanf(line, "%d", &m);

                if(m > 3) m = 3;

                printf("\n%1d",m); /* m はプレイヤーの手*/

 

/* パーセプトロンの「手」を示す */

                printf("<->%1d:   ",(pred+1)%3+1);

/* (pred+1)%3+1はパーセプトロンの予測手predに対して勝つ「手」

pred=1(グー)   :(pred+1)%3+1=3(パー)

pred=2(チョキ) :(pred+1)%3+1=1(グー)

pred=3(パー)   :(pred+1)%3+1=2(チョキ)*/

               

/* これ以降は勝ち負け表示 */

                if(pred==m){printf("[マシンの勝ち]"); fw[2]++;}

/* 相手プレイヤーがマシンの予測通りの手を打ったのでマシンの勝ち*/

                else if((pred%3) == (m-1)){printf("[あなたの勝ち]"); fw[0]++;}

/* 相手プレイヤーの勝ち:つまり

pred%3=0(予測がパー)だからチョキを出す:相手プレイヤーは m-1=0 グー

pred%3=1(予測がグー)だからパーを出す :相手プレイヤーは m-1=1 チョキ

pred%3=2(予測がチョキ)だからグーを出す:相手プレイヤーは m-1=2 パー 

戸田皓治氏によりコメント訂正2003/05/28 */

                else {printf("[ 引き分け ]"); fw[1]++;}

 

/* 成績の表示 */

                printf("    マシン%4d, 引き分け%4d, あなた%4d \n",fw[2],fw[1],fw[0]);

 

        }

        return(0);

}