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

2018-04-16 (月) 15:53:00 (928d)
  • 以下の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 _arm_num; // 最後の腕を選択する(腕3本のバンディットなら3番目の腕を選択する)
}
  • 分割コンパイルについて補足
DSC_0032.JPG
  • player.c
    • ヒント1:ファイルスコープ変数を使う
      • ファイルスコープ変数とは(教科書・本・webも参考に)
        ファイルスコープ変数.png
  • ヒント2:decision_makingのprevious_rewardの説明
    decision_making.png
  • ヒント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;
}