1. 基本 ~役の成立確率~
自分の手札 2枚とコミュニティカード 5枚の合わせて 7枚が与えられた際に、役ができる確率は厳密に計算できる。Wikipedia - ポーカー・ハンドの一覧 の値を少し加工すると以下の表を得る。
役 組み合わせ 確率 累積確率 1-累積確率 役の名称
HC 23294460 17.4% 17.4% 82.6% ハイカード/ブタ
1P 58627800 43.8% 61.2% 38.8% ワンペア
2P 31433400 23.5% 84.7% 15.2% ツーペア
3K 6461620 4.8% 89.5% 10.5% スリーカード
ST 6180020 4.6% 94.1% 5.9% ストレート
F 4047644 3.0% 97.1% 2.9% フラッシュ
FH 3473184 2.6% 99.7% 0.3% フルハウス
4K 224848 0.17% 99.9% 0.2% フォーカード
SF 41584 0.031% 99.9% 0.0% ストレートフラッシュ
合計 133784560 100%
2. 課題
上記で出てきた 合計組み合わせ数 133784560
は C(52, 7)
であり、python などのインタプリタで簡単に計算できる。一応、32bit にぎりぎり収まる程度の大きさである。
>>> 52*51*50*49*48*47*46/7/6/5/4/3/2/1
133784560.0
>>> 1 << 32
4294967296
それでは、二人の場合はどうだろうか?この場合の組み合わせ数は C(52, 9)
であり、まだ計算の余地はありそうだ。36億。1000万/sec の評価関数を使っても6分くらいかかる。さて、通常ホールデムは 9人でプレイする。その場合は、 C(52, 23)
である。もう計算はできない。352兆。
>>> 52*51*50*49*48*47*46*45*44/9/8/7/6/5/4/3/2/1
3679075400.0
>>> 1 << 32
4294967296
>>> a = [ 52-i for i in range(23) ]
>>> b = range(1,24)
>>> x = 1
>>> for i in a: x = x * i
>>> for i in b: x = x / i
>>> x
352870329957600.06
したがって、シミュレーションをする必要がある。
3.シミュレーション概要
-
n = 2,5,9
人のプレーヤーでゲームを 100万回実施する- 全員がショーダウンすると仮定
- 各回で勝利したハンドを記録し、頻度グラフ(累積密度関数)を生成する
- 横軸はハンドの強さ、縦軸は頻度(100% でノーマライズ)
- ハンドの強さは "Cactus Kev's Poker Hand Evaluator" のアルゴリズムで生成した生成値(1~7462)
- バランスハンドを計算する
- バランスハンドは、「勝利確率」と「勝利ハンドの累積関数」が一致したハンドとする
- 例: 2-player では、0.5 の確率で勝利可能と考えられるので、累積関数が 50% となるハンドを調べる
4.シミュレーション結果
5.考察
- single player の結果は冒頭のWikipedia の確率をよく再現できた
プログラムが正常に動作したと考える。また、Wikipediaの粒度よりも細かい粒度で累積関数を再現できた。
- プレイヤーが増えるとグラフが右にシフトする
この挙動は合理的である。同じハンドでも、プレイヤー数が多くなれば勝利確率は減る。これは x 軸(ハンド)を固定したときに、プレイヤー数が多くなると、累積関数値が下振れするという形で現れる。別の言い方をすると、グラフが右にシフトするともいえる。
- 弱めのツーペア以上の役をつくれそうなときにエントリするべき
これは non-trivial な結果だ。駆け引きをしない場合、ポーカーの勝利確率は 1/n
である。弱いハンドでは 1/n
の確率より負けやすく、強いハンドでは 1/n
の確率より勝ちやすいだろう。それでは、その分岐点となるハンドの強さはどれくらいだろうか?と考えるのは合理的である。今回のシミュレーションでは、どんなハンドが勝利したか?を記録し、1/n
の確率以上で勝つハンドを異なる n = 2,5,9
で計測した。その結果、若干のブレはあるにせよ、n によらず弱めのツーペアを作れるハンドがオッズにあうことが示唆された。
「ホールデムとは、ツーペア以上の役を作れそうなときにエントリするゲームである」という命題は、より深く検証する価値があるように思う。
6.参考文献
ハンドの強さを整数値に変換するというアルゴリズムが本質であった。これに関しては、私の前の記事にサマリを用意した。英語が読める人は、発見者のページにいくのがよい。
ただし、上記のアルゴリズムはホールデムでは使用できない。整数値に変換するアルゴリズムのみが利用できる。7枚のカードで、上述の整数値にマッピングするアルゴリズムは、HenryRLee/PokerHandEvaluator のアルゴリズムである。これを私が JavaScript にポートして利用した。
グラフの可視化には、D3.js を利用した。今回のようにグリッドがかなり複雑なグラフを作成する場合、既存のグラフライブラリでヴィジュアライズするのは無理。JavaScriptのプログラミングパラダイムでSVGを直にいじれる D3.js が最適であった。
バランスハンドという概念は私のオリジナルであるので、何か間違いがあるかもしれない。というかそもそも、勝利確率と、勝利ハンドの累積関数は別の概念であるので、これが一致するだろうというのはかなり大胆な仮定であるように思う。にもかかわらず、比較的よい一致したのは興味深い結果であるように思う。