ゼミのお話/一覧/スコアリングのためのモジュール化/officialスコア計算用プログラム の変更点


-以下のcollect.c, player.h, player.cを用意して、コンパイル・実行
--gcc -o game0 collect.c player.c bandit00.o
--gcc -o game1 collect.c player.c bandit01.o
--gcc -o game2 collect.c player.c bandit02.o
--gcc -o game3 collect.c player.c bandit03.o
--gcc -o game4 collect.c player.c bandit04.o
--gcc -o game5 collect.c player.c bandit05.o
--gcc -o game6 collect.c player.c bandit06.o
--gcc -o game7 collect.c player.c bandit07.o
--gcc -o game8 collect.c player.c bandit08.o
--./game0
---bandit00をプレイ
--./gam1
---bandit01をプレイ
--./game2
---bandit02をプレイ
--./game3
---bandit03をプレイ
--./game4
---bandit04をプレイ
--./game5
---bandit05をプレイ
--./game6
---bandit06をプレイ
--./game7
---bandit07をプレイ
--./game8
---bandit08をプレイ

-collect.c

 #include <stdio.h>
 #include <stdlib.h>
 #include "bandit.h"
 #include "player.h"
 
 #define MAX_TRIAL 100000
 
 int main(){
   /* 変数定義・初期化 */
   int i,j,select_arm=0;
   double reward=0.0,score[10000], max_score=0.0, tmp_score;
   for(i=0 ; i<10000 ; i++){
     score[i]=0.0;
   }
 
   init_bandit();              /* バンディット初期化 */
   init_player();              /* プレーヤー初期化 */
   set_arm_num(get_arm_num()); /* バンディットの腕の数を取得 */
 
   /* MAX_TRIAL回まで自動実行 */
   /* 連続した10000回のうち最大のスコアを自動計算・更新 */
   for(i=0 ; i<MAX_TRIAL ; i++){
 
     /* 意思決定・それによるバンディットの実行*/
     select_arm = decision_making(reward);
     reward = bandit(select_arm);
     if(reward < 0.0) reward = 0.0;
 
     /* 連続した10000回の最大スコアの確認 */
     tmp_score=0.0;
     for(j=0 ; j<10000 ; j++) tmp_score += score[j];
     if(tmp_score > max_score) max_score = tmp_score;
 
     /* 連続した10000回のスコアを更新           */
     /* score[0] 〜score[9999] に対し,         */
     /*   最も古いものscore[9999]を消し,       */
     /*   一個ずつずらし(score[j] = score[j-1]) */
     /*   最も新しいものをscore[0]に入れる      */
     for(j=9999 ; j> 0 ; j--) score[j] = score[j-1];
     score[0] = reward;
   }
 
   printf("最大総獲得報酬: %lf\n", max_score);
   close_player();
   return 0;
 }

-player.h

 void init_player();
 void close_player();
 void set_arm_num(int arm_num);
 int decision_making(double previous_reward);

-player.c
--これを作成

 #include "player.h"
 
 static int _arm_num=0; /* このファイルないでしか見えないグローバル変数 */
 
 void init_player(){
 
   return;
 }
 
 void close_player(){
 
   return;
 }
 
 void set_arm_num(int arm_num){
   if(arm_num>0){
     _arm_num = arm_num; /* 使い方の例 */
   }
   return;
 }
 
 int decision_making(double previous_reward){
   /* _arm_numを使えます */
   /* ここに、bandit00〜bandit08を”解く”プログラムを書く */
 
   return 1;
   return _arm_num; // 最後の腕を選択する(腕3本のバンディットなら3番目の腕を選択する)
 }

-分割コンパイルについて補足

#ref(DSC_0032.JPG,zoom,15%)

-player.c
--ヒント1:ファイルスコープ変数を使う
---ファイルスコープ変数とは(教科書・本・webも参考に)
#ref(ファイルスコープ変数.png,zoom,70%)

--ヒント2:decision_makingのprevious_rewardの説明
#ref(decision_making.png,zoom,70%)


--ヒント3:bandit00用player

 #include "player.h"
 /* このファイルないでしか見えないグローバル変数 */
 
 /* バンディットの腕の数 */
 static int _arm_num=0;
 
 /* player(decision_making)が選択した腕番号 */
 static int _player_select_arm;
 
 /* reward[i-1] がi番目の腕の報酬値.適当に超えない数字(20個の腕)にした */
 /* 腕は1から,配列は0から始まるので,腕番号iとreward[ i-1 ]が対応 */
 static double _reward[20];
 
 void init_player(){
   int i;
   _player_select_arm = -5; /* なんとなく,選択した腕がない状態を -5 としてみた */
 
   for(i=0 ; i<20 ; i++){
     _reward[i]=-5.0; /* なんとなく,値の入っていない状態を-5.0とする */
   }
   return;
 }
 
 void close_player(){
 
   return;
 }
 
 void set_arm_num(int arm_num){
   if(arm_num>0){
     _arm_num = arm_num; /* 使い方の例 */
   }
   return;
 }
 
 int decision_making(double previous_reward){
   /* _arm_numを使えます */
   /* bandit00を”解く”プログラム */
   int i;
 
   /* 前回選択した腕がいくつの報酬であったか記録 */
   if( _player_select_arm != -5 ){ /* 1回目のプレイなど前回選択した腕がない(-5)状態か判定 */
     /* 腕は1から,配列は0から始まるので,腕番号iとreward[ i-1 ]が対応 */
     _reward[ _player_select_arm - 1 ] = previous_reward;
   }
   
   /* まずは試していない腕を試してみる */
   for(i=1 ; i <= _arm_num ; i++){
     if(_reward[i-1] == -5.0){ /* i番目の腕を試していない(rewardを持っていない,-5.0の状態) */
       _player_select_arm = i;
       return i;
     }
   }
   
   /* 全部の腕を試していたら、その中から最も高い報酬の腕を選択 */
   int max_reward=0;
   int max_arm=1;
   
   for(i=1 ; i <= _arm_num ; i++){
     if( _reward[ i-1 ] >= max_reward ){
       max_reward = _reward[ i-1 ];
       max_arm = i;
     }
   }
   
   _player_select_arm = max_arm;
   return max_arm;
 }


-player.c
--ヒント4:bandit00用player
---ポインタの演習資料中の4.動的配列を用いて,腕の数ぴったりにreward[]を取得.ヒント3では,腕の数を十分な数(20個)にしていた.

 #include <stdlib.h>
 #include "player.h"
 
 /* このファイルないでしか見えないグローバル変数 */
 
 /* バンディットの腕の数 */
 static int _arm_num=0;
 
 /* player(decision_making)が選択した腕番号 */
 static int _player_select_arm;
 
 /* reward[i-1] がi番目の腕の報酬値.*/
 /* 腕は1から,配列は0から始まるので,腕番号iとreward[ i-1 ]が対応 */
 static double* _reward;
 
 void init_player(){
   _player_select_arm = -5; /* なんとなく,選択した腕がない状態を -5 としてみた */
 
   return;
 }
 
 void close_player(){
   /* 動的配列は free で解放する必要あり */
   free( _reward );
 
   return;
 }
 
 void set_arm_num(int arm_num){
   int i;
 
   if(arm_num>0){
     _arm_num = arm_num; /* 使い方の例 */
   }
 
   /* ここでバンディットの腕の数が得られるので,rewardの初期化 */
   /* reward[ 腕の数分の配列 ] を動的配列で確保 */
   _reward = (double *)malloc(sizeof(double) * _arm_num);
   for(i=0 ; i < _arm_num ; i++){
     _reward[i]=-5.0; /* なんとなく,値の入っていない状態を-5.0とする */
   }
	 
   return;
 }
 
 int decision_making(double previous_reward){
   /* _arm_numを使えます */
   /* bandit00を”解く”プログラム */
   int i;
 
   /* 前回選択した腕がいくつの報酬であったか記録 */
   if( _player_select_arm != -5 ){ /* 1回目のプレイなど前回選択した腕がない(-5)状態か判定 */
     /* 腕は1から,配列は0から始まるので,腕番号iとreward[ i-1 ]が対応 */
     _reward[ _player_select_arm - 1 ] = previous_reward;
   }
   
   /* まずは試していない腕を試してみる */
   for(i=1 ; i <= _arm_num ; i++){
     if(_reward[i-1] == -5.0){ /* i番目の腕を試していない(rewardを持っていない,-5.0の状態) */
       _player_select_arm = i;
       return i;
     }
   }
   
   /* 全部の腕を試していたら、その中から最も高い報酬の腕を選択 */
   int max_reward=0;
   int max_arm=1;
   
   for(i=1 ; i <= _arm_num ; i++){
     if( _reward[ i-1 ] >= max_reward ){
       max_reward = _reward[ i-1 ];
       max_arm = i;
     }
   }
   
   _player_select_arm = max_arm;
   return max_arm;
 }