前回は外観を見始めて、エントリポイントから評価関数のところまで追いかけてみた。そこで評価関数はボナンザ型の評価と駒割りの足し算となっていることがわかった。
今回は駒割りの部分に注目してみる。
駒割りとIArray
IArrayはHaskellにおけるimmutableなarrayのインターフェイス。Haskellにおける配列は配列というよりは順序付きキーによるハッシュマップといった感じ。intだけでなくて色んな物を添え字にして配列を定義できる。例えば、駒を添え字として駒割りの配列としてみたり。
駒割りの評価を返している部分をすべて抜き出してみる。
matVa :: Board.Bd -> Va matVa (Board.Bd _ hs co _ pcl) = co == Piece.B |-> negate $ sum [pcVa pc * hs ! pc | pc <- Board.bothHsRa] + sum [pcVa pc * length (pcl ! pc) | pc <- Piece.pcRa] pcVa :: Piece.Pc -> Va pcVa = (!) $ listArray Piece.pcBnd (a ++ negate `fmap` a) where a = [100, 430, 450, 640, 690, 890, 1040, 15000, 420, 530, 540, 670, -1, 1150, 1300, -1]
matVaは盤面を与えて駒割りの総合計を出す関数。pcVaは駒を与えるとその駒の駒割りを与える関数。 matVaは基本的にはpcVaをすべての盤面上の駒について適用しているだけだ。自駒の場合はそのまま、敵駒の場合はnegateした数を評価とする。
なのでpcVaについて考えてみればすべてわかるはず。
ここで
(!) $ listArray Piece.pcBnd (a ++ negate `fmap` a)
この部分が肝のようだ。
(!)
は配列と添字を与えてその要素を得る関数だ。つまり、評価値の一覧に添字としての駒を与えて駒に対応する評価を得る。
listArray
は配列を作る関数。listArray
の最初の引数は配列の添字のレンジをタプルで与える。その要素をリストとして第二引数として与える。
Piece.pcBnd
は
pcBnd = (Pc B Unp FU, Pc W Pro OU)
つまり、先手の歩から順に後手の王(ここでは成っていることになっている)までをリストアップする。その順序はPiece.Pcで与えられている。具体的な内容は
data P8 = FU | KY | KE | GI | KI | KA | HI | OU deriving (Eq, Ord, Enum, Ix)
という順番にあるので
[BP,BL,BN,BS,BG,BB,BR,BK,BPP,BPL,BPN,BPS,BPG,BPB,BPR,BPK,WP,WL,WN,WS,WG,WB,WR,WK,WPP,WPL,WPN,WPS,WPG,WPB,WPR,WPK]
という具体的な順番に成っている。GHCiで以下のように確かめられる。
ghci GHCi, version 7.8.3: http://www.haskell.org/ghc/ :? for help Loading package ghc-prim ... linking ... done. Loading package integer-gmp ... linking ... done. Loading package base ... linking ... done. Prelude> :load Piece [1 of 2] Compiling Util ( Util.hs, interpreted ) [2 of 2] Compiling Piece ( Piece.hs, interpreted ) Ok, modules loaded: Util, Piece. *Piece> pcBnd Loading package array-0.5.0.0 ... linking ... done. (BP,WPK) *Piece> pcRa [BP,BL,BN,BS,BG,BB,BR,BK,BPP,BPL,BPN,BPS,BPG,BPB,BPR,BPK,WP,WL,WN,WS,WG,WB,WR,WK,WPP,WPL,WPN,WPS,WPG,WPB,WPR,WPK]
三文字の場合の駒の真ん中のPは成っていることを表す。
これの自駒だけに絞って考えると
[BP,BL,BN,BS,BG,BB,BR,BK,BPP,BPL,BPN,BPS,BPG,BPB,BPR,BPK] [100, 430, 450, 640, 690, 890, 1040, 15000, 420, 530, 540, 670, -1, 1150, 1300, -1]
という対応になっている。歩は100になっていて、成っている金と王には負数が割り当ててある(おそらく使われないのだろう)。 王は15000と非常に高い値が割り当てられている。角は歩の8.9倍、飛車は10.4倍の評価が割り当てられているようだ。
まとめ
駒割りが配列で与えられていて、arrayの表現方法がわかった。GHCiで評価をぱっとできるとかなり便利だなあと思う。IntelliJのプラグインにもあるといいなあ。
次はボナンザ型の評価関数を見てみたい。前半戦の本丸になりそうだ。