このページ
ビデオポーカー分析の私の方法論
時々聞かれる質問の一つに、ビデオポーカープログラムでペイテーブルを1分以内に評価する方法があります。このページでは、その質問に答えます。
私のオリジナルのプログラムは、総当たり方式で2,598,960通りのスターティングハンドをすべてループし、その後、5枚すべてを捨てる際に1,533,939枚の交換カードすべてを含む、32通りの捨て方をすべてプレイしていました。これは1998年頃のことです。当時の私のコンピュータでは、完成までに1年以上かかると計算しました。今日であれば、このようなプログラムは約1か月で完了するでしょう。しかし、2つのショートカットを使うことで、約1か月かかっていた時間を約3秒に短縮できます。以下にその方法を説明します。
実行時間を数日に短縮するには、配られたカードの類似ハンドを分析するのを避けることができます。例えば、スターティングハンドが4枚のエースと1枚のキングだった場合、キングのスートは関係ありません。キングに任意のスートを割り当て、その結果を4倍にすれば、時間を節約できます。同じ論理を用いると、スターティングハンドの種類は2,598,960種類から134,459種類に削減できます。以下の表は、各クラスのハンドのランクごとに、スートを並べる方法と、それに応じた重み付けを示しています。
5人の独身者combin(13,5)=1,287通りの可能な組み合わせをすべてループし、13通りの中から5通りのランクを選びます。ランクの組み合わせごとに、スーツ(1から4まで)と重みを以下のように設定します。例えば、最初の行では、各シングルトンのランクをスーツ1に設定します。スーツは4通り考えられるので、これを4回繰り返すのではなく、1回だけ繰り返し、結果に重み4を掛けます。
5つのユニークなランク
歌う。1 | 歌う。2 | 歌う。3 | 歌う。4 | 歌う。5 | class="data-heading">重量|
---|---|---|---|---|---|
1 | 1 | 1 | 1 | 1 | 4 |
2 | 1 | 1 | 1 | 1 | 12 |
1 | 2 | 1 | 1 | 1 | 12 |
1 | 1 | 2 | 1 | 1 | 12 |
1 | 1 | 1 | 2 | 1 | 12 |
1 | 1 | 1 | 1 | 2 | 12 |
2 | 2 | 1 | 1 | 1 | 12 |
2 | 1 | 2 | 1 | 1 | 12 |
2 | 1 | 1 | 2 | 1 | 12 |
2 | 1 | 1 | 1 | 2 | 12 |
1 | 2 | 2 | 1 | 1 | 12 |
1 | 2 | 1 | 2 | 1 | 12 |
1 | 2 | 1 | 1 | 2 | 12 |
1 | 1 | 2 | 2 | 1 | 12 |
1 | 1 | 2 | 1 | 2 | 12 |
1 | 1 | 1 | 2 | 2 | 12 |
2 | 3 | 1 | 1 | 1 | 24 |
2 | 1 | 3 | 1 | 1 | 24 |
2 | 1 | 1 | 3 | 1 | 24 |
2 | 1 | 1 | 1 | 3 | 24 |
1 | 2 | 3 | 1 | 1 | 24 |
1 | 2 | 1 | 3 | 1 | 24 |
1 | 2 | 1 | 1 | 3 | 24 |
1 | 1 | 2 | 3 | 1 | 24 |
1 | 1 | 2 | 1 | 3 | 24 |
1 | 1 | 1 | 2 | 3 | 24 |
1 | 1 | 2 | 2 | 3 | 24 |
1 | 2 | 1 | 2 | 3 | 24 |
1 | 2 | 2 | 1 | 3 | 24 |
1 | 1 | 2 | 3 | 2 | 24 |
1 | 2 | 1 | 3 | 2 | 24 |
1 | 2 | 2 | 3 | 1 | 24 |
1 | 1 | 3 | 2 | 2 | 24 |
1 | 2 | 3 | 1 | 2 | 24 |
1 | 2 | 3 | 2 | 1 | 24 |
1 | 3 | 1 | 2 | 2 | 24 |
1 | 3 | 2 | 1 | 2 | 24 |
1 | 3 | 2 | 2 | 1 | 24 |
3 | 1 | 1 | 2 | 2 | 24 |
3 | 1 | 2 | 1 | 2 | 24 |
3 | 1 | 2 | 2 | 1 | 24 |
4 | 4 | 1 | 2 | 3 | 24 |
4 | 1 | 4 | 2 | 3 | 24 |
4 | 2 | 3 | 4 | 1 | 24 |
4 | 1 | 2 | 3 | 4 | 24 |
1 | 4 | 4 | 2 | 3 | 24 |
1 | 4 | 2 | 4 | 3 | 24 |
1 | 4 | 2 | 3 | 4 | 24 |
2 | 3 | 4 | 4 | 1 | 24 |
2 | 3 | 4 | 1 | 4 | 24 |
1 | 2 | 3 | 4 | 4 | 24 |
ペア
ペアのランクを選ぶための13×combin(12,3)=2,860通りの可能な方法と、残りの12通りのうち3通りのシングルトンのランクをループします。ランクの組み合わせごとに、スーツ(1から4の番号)と重みを以下のように設定します。例えば、最初の行では、ペアのスーツを1と2に、シングルトンのスーツをすべて1に設定します。ペアのスーツを選ぶ方法はcombin(4,2)=6通り、シングルトンのスーツをペアのスーツの1つと同じにする方法は2通りあり、重みは6×2=12となります。
ペア
ペア1 | ペア2 | 歌う。1 | 歌う。2 | 歌う。3 | 重さ |
---|---|---|---|---|---|
1 | 2 | 1 | 1 | 1 | 12 |
1 | 2 | 1 | 1 | 2 | 12 |
1 | 2 | 1 | 2 | 1 | 12 |
1 | 2 | 2 | 1 | 1 | 12 |
1 | 2 | 1 | 1 | 3 | 24 |
1 | 2 | 1 | 3 | 1 | 24 |
1 | 2 | 3 | 1 | 1 | 24 |
1 | 2 | 1 | 3 | 3 | 24 |
1 | 2 | 3 | 1 | 3 | 24 |
1 | 2 | 3 | 3 | 1 | 24 |
1 | 2 | 3 | 3 | 3 | 12 |
1 | 2 | 1 | 2 | 3 | 24 |
1 | 2 | 1 | 3 | 2 | 24 |
1 | 2 | 3 | 1 | 2 | 24 |
1 | 2 | 3 | 4 | 4 | 12 |
1 | 2 | 4 | 3 | 4 | 12 |
1 | 2 | 4 | 4 | 3 | 12 |
1 | 2 | 1 | 3 | 4 | 24 |
1 | 2 | 3 | 1 | 4 | 24 |
1 | 2 | 3 | 4 | 1 | 24 |
ツーペア
2組のペアについて、13段階の中から2つのランクを選び、残りの11段階の中から1つのランクを選ぶために、combin(13,2)×11=858通りの可能な組み合わせをすべてループします。ランクの組み合わせごとに、スーツ(1~4の番号)と重み付けを以下のように設定します。例えば、1行目では、1組目のスーツを1と2、2組目のスーツを3と4、シングルトンのスーツを1に設定します。1組目のスーツの選び方はcombin(4,2)=6通りあります。2組目のペアには他の2つのスーツがあるので、それらを選ぶための1は1つだけです。シングルトンは1組目のスーツのどちらかを選ぶことができるので、2つの可能性があります。したがって、1行目の重み付けは6×1×2=12です。
ツーペア
ペア1 カード1 | ペア1 カード2 | ペア2 カード1 | ペア2 カード2 | 歌う。1 | 重さ |
---|---|---|---|---|---|
1 | 2 | 3 | 4 | 1 | 12 |
1 | 2 | 3 | 4 | 3 | 12 |
1 | 2 | 1 | 3 | 1 | 24 |
1 | 2 | 1 | 3 | 2 | 24 |
1 | 2 | 1 | 3 | 3 | 24 |
1 | 2 | 1 | 3 | 4 | 24 |
1 | 2 | 1 | 2 | 1 | 12 |
1 | 2 | 1 | 2 | 3 | 12 |
スリー・オブ・ア・カインド
スリーカードの13のランクから1つのランクを選ぶ13×combin(12,2)=858通りの可能な方法と、残りの12のランクから2つのシングルトンを選ぶ66通りの方法をループします。ランクの組み合わせごとに、スーツ(1から4の番号)と重み付けを以下のように設定します。例えば、最初の行では、スリーカードのスーツを1、2、3に設定し、2つのシングルトンのスーツをスリーカードで表される3つのスーツのうち2つに設定します。スリーカードの4つのスーツから3つを選ぶ方法はcombin(4,3)=4通り、最初のシングルトンのスーツをその3つから選ぶ方法は3通り、2番目のシングルトンのスーツを選ぶ方法は2通りあります。したがって、最初の行の重み付けは4×3×2=24です。
スリー・オブ・ア・カインド
3種類 カード1 | 3種類 カード2 | 3種類 カード3 | 歌う。1 | 歌う。2 | 重さ |
---|---|---|---|---|---|
1 | 2 | 3 | 1 | 2 | 24 |
1 | 2 | 3 | 1 | 4 | 12 |
1 | 2 | 3 | 4 | 1 | 12 |
1 | 2 | 3 | 1 | 1 | 12 |
1 | 2 | 3 | 4 | 4 | 4 |
フルハウス
スリーカードの場合は13通りの中から1つのランクを選び、ペアの場合は12通りの中から13通りのランクを選び、13×12=156通りの可能な組み合わせをすべてループします。ランクの組み合わせごとに、スーツ(1から4の番号)と重み付けを以下のように設定します。例えば、1行目ではペアのスーツを1と2、スリーカードのスーツを1、2、3に設定します。ペアのスーツの選び方はcombin(4,2)=6通りあります。スリーカードでは、ペアのスーツと残りの2つのスーツのうち1つを使用します。したがって、1行目の重み付けは6×2×2=12です。
フルハウス
ペア カード1 | ペア カード2 | 3種類 カード1 | 3種類 カード2 | 3種類 カード3 | 重さ |
---|---|---|---|---|---|
1 | 2 | 1 | 2 | 3 | 12 |
1 | 4 | 1 | 2 | 3 | 12 |
フォー・オブ・ア・カインド
フォーカードの場合は13通りの中から1つのランクを選ぶ13通り×12=156通りの可能な組み合わせをループし、シングルトンの場合は12通りのランクを選びます。ランクの組み合わせごとに、スーツ(1から4の番号)と重み付けを以下のように設定します。例えば、1行目ではフォーカードのスーツを1、2、3、4に、シングルトンのスーツを1に設定します。スリーカードの場合は4通りの中から4通りを選ぶ方法は1通りしかなく、シングルトンの場合は4通りの中から4通りのスーツを選ぶことができます。したがって、1行目の重み付けは1×4×2=4となります。
フォー・オブ・ア・カインド
4種類 カード1 | 4種類 カード2 | 4種類 カード3 | 4種類 カード4 | 歌う。1 | 重さ |
---|---|---|---|---|---|
1 | 2 | 3 | 4 | 1 | 4 |
上記の手順により計算時間は95%短縮されますが、1,533,939通りの交換カードの組み合わせをループ処理すると、それでも数時間かかります。3秒でプログラムを実行する秘訣は、ドローステップでループ処理を行わないことです。その方法は以下の通りです。
- 次の配列を初期化します。
- 配列1: サイズ 2,598,960
- 配列2: サイズ 270,725 x 16
- 配列3: サイズ 22100 x 16
- 配列4: サイズ1326 x 16
- 配列5: サイズ52×16
- 配列6: サイズ16
- 52枚のカードのうち5枚の組み合わせ、合計2,598,960通りをすべてループします。この時点では134,459ハンドのショートカットは使用しないでください。配られたハンドごとに、以下の手順を実行してください。
- ポーカーの価値に応じてスコアを付けます。
- スコアを配列0に格納します。最初のハンドを配列の要素0に格納し、ハンドごとに1ずつ増加させます。
- 配られた 5 枚のカードから 4 枚を選ぶ 5 つの方法のそれぞれについて、4 枚のカードを 0 から 270,724 までのインデックス番号に変換し (方法については後で説明します)、配列 1 の要素 [インデックス番号][ハンド スコア] を 1 ずつ増やします。
- 配られた 5 枚のカードから 3 枚を選ぶ 10 通りの方法のそれぞれについて、3 枚のカードを 0 から 22,099 までのインデックス番号に変換し、配列 2 の要素 [インデックス番号][ハンド スコア] を 1 ずつ増やします。
- 配られた 5 枚のカードから 2 枚を選ぶ 10 通りの方法のそれぞれについて、2 枚のカードを 0 から 1,325 までのインデックス番号に変換し、配列 3 の要素 [インデックス番号][ハンド スコア] を 1 ずつ増分します。
- 配られた 5 枚のカードから 1 枚を選ぶ 5 つの方法のそれぞれについて、カードを 0 から 51 までのインデックス番号に変換し、配列 4 の要素 [インデックス番号][ハンド スコア] を 1 ずつ増やします。
- 配列5の要素[hand score]を1増加します。
- 次に、上で説明した 134,459 クラスの手をループします。
- 5 枚のカードすべてを保持する価値を決定するには、5 枚のカードをインデックス番号に変換し、ポーカーの価値 lin array0 を検索します。
- 任意の 4 枚のカードを保持することの価値を決定するには、4 枚のカードをインデックス番号に変換し、array1 の対応する要素でドローの可能な結果を検索します。ただし、これには、ディールで捨てたカードを取得することも含まれます。したがって、5 枚のカードすべてを保持するポーカーの価値に関連付けられた配列の要素から 1 を引く必要があります。たとえば、J♣、Q♣、K♣、A♣ を保持し、 2♥を捨てた場合、ロイヤルを取得する方法は 1 つ、フラッシュを取得する方法は 8 つ、ストレートを取得する方法は 3 つ、ジャックのペア以上の方法は 12 通り、負けるハンドを取得する方法は 23 通りあります。ただし、array1 には、ドローで2♥を取得することを含め、負けるハンドを取得する方法が 24 通りあると示されています。したがって、4 枚のカードを保持する 5 通りの可能な結果から、すべてを保持する結果を引く必要があります。
- このステップでは、上記のステップのロジックをしっかりと理解しておきましょう。3枚のカードを保持する10通りの方法については、配列2で可能な結果を調べます。次に、保持している3枚のカードと捨てる各カードについて、配列1から可能な結果を減算します。例えば、2♣ 2♥ 2♠を保持し、 4♥とJ♠を捨てた場合の値を求めるには、配列2の2♣ 2♥ 2&スペードの値から始め、2♣ 2♥ 2♠ 4♥と2♣ 2 ♥ 2♠ J♠の値を減算します。ただし、これは5枚のカードをすべて保持している状態で2回減算することになります。そのため、5枚すべて保持した場合に得られる値を加算し直す必要があります。
- 同じ論理で、任意の 2 枚のカードを保持するには、配列 3 の値から開始し、配列 2 から適切なカード セットを減算し、配列 1 から適切なカード セットを追加し、配列 0 からすべてを保持するための要素を減算します。
- 1 枚のカードを保持するには、配列 4 の関連する値から開始し、配列 3 から適切な値を減算し、配列 2 から適切な値を加算し、配列 1 から適切な値を減算し、配列 0 から適切な値を加算します。
- すべてを破棄するには、配列 5 の値から開始し、配列 4 から適切な値を減算し、配列 3 から適切な値を加算し、配列 2 から適切な値を減算し、配列 1 から適切な値を加算し、配列 0 から適切な値を減算します。
- これで、32通りのプレイ方法すべてについて、あらゆる結果の組み合わせの数が判明したはずです。それぞれの期待値を求めましょう。期待値が最大となるプレイについて、ゲーム全体の可能な結果の配列に、そのプレイの可能な結果を追加します。配られたハンドの重み付けを掛け合わせることを忘れないでください。
- 134,459種類のスターティングハンドをすべてループ処理すると、ドロー時に各ハンドが成立する可能性のある数が得られるはずです。この配列を使用して、ゲーム全体のリターンを決定します。
以下は、2 ~ 5 枚のカード (番号 0 ~ 51) を変換し、インデックス値を返す 4 つのサブルーチンです。
int HandIndex2(int c1, int c2){ int r; r=combin_array[52][2]-combin_array[52-c1][2]; r+=combin_array[51-c1][1]-combin_array[52-c2][1]; return r;}int HandIndex3(int c1, int c2, int c3){ int r; r=combin_array[52][3]-combin_array[52-c1][3]; r+=combin_array[51-c1][2]-combin_array[52-c2][2]; r+=combin_array[51-c2][1]-combin_array[52-c3][1]; return r;}int HandIndex4(int c1, int c2, int c3, int c4){ int r; r=combin_array[52][4]-combin_array[52-c1][4]; r+=combin_array[51-c1][3]-combin_array[52-c2][3]; r+=combin_array[51-c2][2]-combin_array[52-c3][2]; r+=combin_array[51-c3][1]-combin_array[52-c4][1]; return r;}int HandIndex5(int CardIndex[]){ int r; r=combin_array[52][5]-combin_array[52-CardIndex[0]][5]; r+=combin_array[51-カードインデックス[0]][4]-combin_array[52-カードインデックス[1]][4]; r+=combin_array[51-カードインデックス[1]][3]-combin_array[52-カードインデックス[2]][3]; r+=combin_array[51-カードインデックス[2]][2]-combin_array[52-カードインデックス[3]][2]; r+=combin_array[51-カードインデックス[3]][1]-combin_array[52-カードインデックス[4]][1]; rを返す;}
リンク
このサイトでは、著者がビデオ ポーカー アナライザーを 1 年から 7 秒に高速化した方法を説明しています。
VP Genius には、ビデオ ポーカーのプログラミングに関する優れたページがあります。