リバーシ用評価関数
初期化・評価する部分は実装完了、明日は学習部分を作る予定*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++だとテンプレート使って出来た様な気もします。