Skip to content

枝刈りDFS

DFS

ある手牌の向聴数を計算する方法として, すべての和了形との距離を計算するものがある. 重複を許すことにすればすべての和了形を探索することは下図の木のすべての葉ノードを訪問することに対応する(重複を許しても計算結果に影響を与えない). この木では根ノードが空の手牌に, 枝が面子または雀頭を手牌に追加する操作に対応している. なお, この図はイメージであり各ノードの子ノードの数は図の通りではない.

図1: 和了形探索の木

枝刈り

向聴数を計算するためには和了形との距離の最小値がわかれば十分である. そこで最小値を与えない葉ノードを子孫に持つノードへの訪問をできるだけ避けること(枝刈り)を考える. これには手牌への牌の追加に対して距離が(広義)単調増加することを利用する. 例えば手牌hから手牌gへの距離がdとわかっているとする. ここで手牌gに任意の牌を1枚加えた手牌をgとすると, hからgへの距離dddとなる. 枝刈りの方法は次のようになる. 適当な葉ノードを訪問した結果, 手牌hと和了形との距離の最小値の暫定的な値dtmpを得たとする. 現在, 適当なノード(手牌gとする)にいるとする. もしd(g,h)dtmpであれば, その子ノードを訪問してもdtmpが更新されることはない. よってd(g,h)<dtmpを満たすノードだけ訪問すればよい.

木の拡張

向聴数を連立漸化式を解いて求めたい. 参照先のページで定義されるu0,u1,u2,u3,u4,t4は前述の木を探索する過程で同時に計算される. 残りのt0,t1,t2,t3も計算されるように木を拡張する.

図2: 拡張した和了形探索の木

上図の木を探索することで正しくumtmが計算されることを証明する. 手牌hからの距離がt4となる手牌gが存在する. 手牌gから見たとき適当なm面子0雀頭への距離は0だからumt4である. 同様に任意のmについてumt4,tmt4が成り立つ. よって距離がt4以下のすべてのm面子0雀頭形とm面子1雀頭形を探索したときumtmを正しく計算したと言える. ソースコードはmkind.cppを参照すること.

参考

本アルゴリズムは以下のソースコードを参考にした.

https://github.com/gimite/MjaiClients/blob/master/src/org/ymatsux/mjai/client/ShantensuUtil.java