今回は評価関数です。Stockfishの評価関数evaluate()は、手番側から見た評価値を返すので、後手番であれば符号を反転して返す、みたいな処理が必要です。
「Stockfish」カテゴリーアーカイブ
Stockfish DD – benchmark ベンチマーク
今回はベンチマーク部です。
UCIプロトコルの拡張コマンドで、”bench”とタイプすると事前に用意してあった局面から探索を開始して、探索終了するまでの時間を計測し、nps(nodes per second=1秒あたりの探索ノード数)などを表示します。
Stockfish DD – SEE (Static Exchange Evaluation) 静的駒交換値
Stockfish DD – position 盤面構造体
今回は盤面構造体であるpositionクラスについて解説します。このpositionクラス、本当によく出来ていて、将棋ソフトに応用する場合でも、よくよく考えていくとこれと同じ構造に辿り着くと思います。
そういう意味では、将棋ソフトを作る場合でも独自に実装するより先に、このpositionクラスのソースコードを読んだほうがいいと思います。
Stockfish DD – thread スレッド
今回はスレッド周りです。
探索を並列化するために並列数だけスレッドの生成が必要です。あと思考時間を監視して、時間になったときに思考を打ち切る判定をするためのスレッドも必要です。
GitHubのC++11用のコードだとスレッド生成はstd::threadを使って実装されています。なお、ここで紹介しているのはC++11用のブランチです。
Stockfish DD – movepick 指し手オーダリング
今回はmove pickerと言って、指し手を段階的に生成して、生成した指し手のなかから1つ一番よさげな指し手を取り出す部分(いわゆる指し手オーダリング)について見ていきます。
killerが2本あったり、なるべくソートが要らないように工夫してあったり、なかなか興味深いです。
Stockfish DD – notation 指し手文字列に変換
今回は指し手をUCIの指し手文字列に変換する部分を見ていきます。将棋ではUCIではなくUSIプロトコルとなっています。以下、UCIと書いてある部分はUSIと読み換えて理解してください。
UCIプロトコルでは、思考を開始する局面は、普通、startpos(平手の初期局面)からの指し手を示す文字列が送られてきます。と言うことは、常識的には、UCI表記での指し手文字列を思考エンジンが内部で使っている指し手構造体に変換する必要があります。ところが、Stockfishにはこの変換をダイレクトに行なう関数は存在しません。さて、どうやっているのでしょうか。
Stockfish DD – timeman 時間制御部
今回は思考時間制御部(time manager)です。現局面での次の1手に使うべき時間を計算します。
maximum search time = 今回の指し手で使える最大思考時間。fail high/fail lowした場合など、この最大時間までは使うものとします。(残りの手数に応じて時間をある程度残しておかないといけないので、この値は残り持ち時間のすべてではありません。)
optimum search time = 今回の指し手で使える平常時の目安時間。
unstable PV Extra Time = 反復深化のiterationを深くしていくときにPV(最善応手列)が変化したときは評価値が不安定な局面だということで与えられる追加の思考時間。
Stockfish DD – bitcount.h
今回はStockfishのbitcount.hです。これは、2進数的に見て1になっているbitの数を数えるというものです。いわゆるpopcountですね。SSE4.1以降であればx86/x64ではpopcnt命令が使えますので簡単なのですが、そうではない環境ではビット演算のテクニックを用いて求めることになります。
Stockfish DD – bitboard
Stockfishのbitboardは、チェスなので盤面が8×8 = 64升であり、64bit変数に収まります。(将棋の場合、81升なので128bit変数もしくは、64bit変数が2つ必要になります。)
あと、magic bitboardと言う仕組みが使われています。これは斜めに利く駒の利きのbitboardに対して掛け算を使って連続するビットに移動させるテクニックです。→ Magic Bitboard – Chess Programming Wiki
Haswell以降であればBMIを使うべきでしょう。→ BMI使ってますか?