じゃんけんマシン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);
}