GA将?開発日記~王理のその先へ~

ネタ勢最強を目指して絶賛開発中。

リバーシ用評価関数

 初期化・評価する部分は実装完了、明日は学習部分を作る予定*1。以上。

 ・・・だとネタが無いので、ちょっと実装上の工夫を。

 まず、学習を実装しようとすると、「制御構造*2は同じで、その中の処理だけ変えたい」と言う事があります。

 例えば下のコードはリバーシの評価関数から取り出した、局面評価の処理なのですが、ループ内部の処理を変えるだけで学習の為の処理になります。

// 全てのマスに対して処理
for( int x = 1; x <= Config.BOARD_WIDTH; x++ ) {
  for( int y = 1; y <= Config.BOARD_HEIGHT; y++ ) {
    /* ↓ ここの部分だけ色々変えたい */
    // (x,y)とマスの情報(先手・後手・空き)に対応するパラメータの値を、返り値に加算
    result += this.stoneParams[ x ][ y ][ board.getMasuInfo( x, y ) ].getValue();
    /* ↑ 変えたいのはここだけ */
  }// for(..y..)
}// for(..x..)

 んで、以前はコピペして対処していたのですが、さすがにそれは面倒&バグの原因になるので、対処法を考えてみました。

 対処後のコードはこんな感じです。

// 全てのマスに対して処理
for( int x = 1; x <= Config.BOARD_WIDTH; x++ ) {
  for( int y = 1; y <= Config.BOARD_HEIGHT; y++ ) {
    // (x,y)とマスの情報(先手・後手・空き)に対応したパラメータを処理
    ep.process( this.stoneParams[ x ][ y ][ board.getMasuInfo( x, y ) ], result );
  }// for(..y..)
}// for(..x..)

 まず、この制御構造は一つのメソッド(とりあえずforEachという名にしました)に書くだけで済みます。

 ここには書きませんでしたが、forEachメソッドの他に、ElementProcessorというインタフェース*3を作ります。

 で、ElementProcessorを実装するEvaluateProcessorを定義し、process(...)メソッドで評価値計算をします。(本当はpreProcess(...)とかpostProcess(...)というメソッドもあるのですが、それは省略)

 そうすると、forEach(...)メソッドの引数としてEvaluateProcessorを与えてやると、評価値が返ってくる様になります。

 他にLearningProcessorを定義してforEach(...)の引数に与えてやると、今度は学習が出来る様になる、という寸法です。

 んで、これで結構簡単に実装出来る様になりました。コピペしなくて済むし、制御構造を変えるときも楽だし、結構便利です。

 そういえば、今回はJavaなのでインタフェース・クラスでやりましたが、C++だとテンプレート使って出来た様な気もします。

*1:つっても、単なる線形近似だから楽。単に一日置いて頭を切り替えたいだけ

*2:ループとか分岐とか

*3:Javaの場合。C++ならvirtualメソッドを持つクラスでいいはず