ポーカーハンドの決定


19

私はアセスメントの一環としてテキサスホールデムゲームを作成しており、利用可能な7枚のカードを調べて手が存在するかどうかを判断する方法を検討していました。

私が考えることができる唯一の可能な方法は、カードを数字順にソートし、5枚のカードの可能な各グループを調べ、それらがすべての可能なハンドのリストと一致するかどうかを確認することです。訴訟は無関係であるため、それは長い時間がかかり、ペアを決定するためにのみ実行可能です。

カードはそれぞれ文字列であり、数字/ a / j / q / k、およびスーツ(char)3(小さなスペードシンボルを作る)で構成されています。

手分析システムの作成に役立つ提案、数式、リンクはありますか?

まだお互いに手をランク付けすることを心配しないでください、それは魚の異なるやかんです。


1
それを指摘するだけですが、そのコンテキストでのベクトルタグは線形代数に関するものです。コンテナではありません。
シダー

@Sidar適合しないと思われる場合は、将来的にタグを編集してください。タグにカーソルを合わせて「タグの編集」オプションがポップアップすると(少なくとも私にとっては?)、質問を編集せずにタグだけを編集できます。
マイケルハウス

@ Byte56私はこの奇妙な習慣を持っているので、自分が正しいかどうかわからないので、コメントを通して受動的にそれを行います...だから投稿を編集しませんでした。おそらく私は投稿で何かを見逃したので、私は彼の応答を待っていました。
シダー

数年前にゲーム開発者に登場した素晴らしい記事もあります:cowboyprogramming.com/2007/01/04/programming-poker-ai
celion

1
しばらく前から楽しみのためにJavaで実装しました。codereview.stackexchange.com / questions / 10973 / …で見つけることができます。PokerHand.javaを見ると、各タイプのハンドをテストするためのメソッドがあります(isFullHouseなど)。カードが最初にソートされている場合にのみ機能します。
ブギ

回答:


20

ポーカーハンドの大半を見つけるには、各ランクとスーツのハンドにあるカードの枚数を表にしておくだけでよいと思います。

つまり、カードランク(数字とA / J / Q / K)を手札のそのランクのカードの数にマッピングするアレイを作成します。プレーヤーがペアまたはスリーカードを持っている場合、この配列には2または3などの要素があります。2つの要素と3の要素があり、まっすぐな場合、完全な家があります。この配列に1に等しい5つの連続した要素がある場合。

同様に、各スーツのカード数の同様の配列を作成し、それを使用してフラッシュを検出できます。

特定のハンドの存在を検出したら、UIでそれらを強調表示したり、必要な操作を行ったりするために、戻ってハンド内の特定のカードを見つけるのは非常に簡単です。

擬似コードで:

int countByRank[13] = { 0 };        // Initialize counter to zero for each rank
for (cards in hand)
    countByRank[card.rank] += 1;    // Increment counter for this card's rank
if (countByRank.find(2))
    // There's a pair
else if (countByRank.find(3))
    // There's a three-of-a-kind
// etc...

17

組み合わせが非常に多いため、少し注意が必要です。幸いなことに、非常に短い時間で多数の組み合わせをチェックできるプロセッサがあります。

異なる種類の手の検出には、いくつかの異なる戦略が必要です。幸いなことに、いくつかの異なるタイプが戦略をオーバーラップできます。私は手のランクで順番に検索します。

  1. ストレートフラッシュ
  2. 4種類
  3. フルハウス
  4. 流す
  5. まっすぐ
  6. 三種類
  7. ツーペア
  8. ワンペア
  9. ハイカード

23678すべての単純集計しています。Ace to Kingのカードのリストを使用して、リスト内の各値の数を配置し、見つかった追加のカードごとに増分します。次に、4のリストを確認します。4がない場合は、4の種類はありません。3秒間チェックします。3がない場合は、3の種類はありません。3がある場合は、2(フルハウスを示す)を確認します。等々...

の場合15同じリストを使用して、すべてのカードが5つのカードのシーケンスのリストに1つ以上のエントリを持つシーケンスを検索できます。彼らも同じスーツを持っている場合、それはストレートフラッシュです。

4同じリストを設定できますが、今回はスーツを数えています。5以上の数字を探します。

最後に、 9、最高のカードがあります。これは、上記のリストのいずれかで最後の最高値を見るだけの単純な問題です。

順番に検索すれば、一致するものが見つかったらブレークアウトできます。ただし、すべての情報をユーザーに提供する場合は、検索を続行してすべての一致を見つけるのは簡単です。


基本的に、あなたはバケツを埋めています。次に、バケットの組み合わせを確認します。説明する:

ここに画像の説明を入力してください

配列から始め、各カードのバケットを使用して、カードを反復処理し、各カードのインスタンスをカウントします。その後、配列を簡単に反復処理し、特定の組み合わせを確認できます。この例では、バケットの1つに4つのアイテムがあるため、4つの種類があることは明らかです。


6

私は一度このアルゴリズムに出会いました。素数を掛けて手を決定し、非常に興味深い読み物です。Cactus Kevのポーカーハンドエバリュエーター


1
これは面白いですが、すべて読んだかどうかわかりません。そのアルゴリズムは5枚のカード用です。著者は、7枚のカード用のアルゴリズムを持っているが、それを共有していないと述べているため、7枚のカードに関連するGoogle検索で見つけたかもしれません。ページ上部の灰色のテキストを参照してください。そのため、このアルゴリズムが7カードセットにどれほど役立つかはわかりません。
マイケルハウス

1
7枚のカードハンドから作成できる21の異なる5枚のカードハンドしかないため、1つのオプションは、それぞれに5枚のカードエバリュエーターを使用し、最良のものを選択することです。
アダム

@ Byte56あなたは正しい、私はそれを7枚のカードに使用したことを覚えているが、事前に最高の5枚のカードを決定しなければならなかったので、効率が少し損なわれた。
petervaz

その後、この回答のリンクは腐敗し、スパマーがドメインを選択しました。リンクを元のページのアーカイブにリダイレクトしましたが、この回答をより堅牢にするために、回答の本文に提案されているアルゴリズムの要約を含めるように回答を編集することが理想的です。
DMGregory

2

この質問がすでに得ている優れた答えを補うために、基本的な分類手法が整ったら、手を比較する最も簡単な方法の1つを提供することが役立つと思いました。まず、クラスに手をタグ付けします多くの答えが示唆しているようにに -「ハンドXよりハンドXの方が良い」という比較のほとんどです。2つの手のクラスを比較して、どちらのクラスが優れているかを確認するだけで実行できます。残りについては、実際にカードごとに比較する必要がありますが、分類の作業をもう少し行うとこれが簡単になることがわかります。

ベースラインのケースとして、両手が「ハイカード」の手である状況を考えてください。この場合、最初に最高の2枚のカードを比較し、次に(一致した場合)次の2枚のカードなどを比較します。各入力ハンドが最高のカードから最低のカードにソートされると仮定すると、このアプローチはこの:

int CompareHandsOfSameClass(Hand h1, Hand h2) {
  for ( int i = 0; i < 5; i++ ) {
    if ( h1[i].rank > h2[i].rank ) {
      return -1;
    } else if ( h1[i].rank < h2[i].rank ) {
      return 1;
    }
  }
  return 0;
}

さて、朗報:適切に調整されたこの辞書編集の順序は任意のクラスが同じである限り。たとえば、ペアを比較する方法は最初にペアを比較し、次に他の3枚のカードを比較することなので、手を並べ替えてペアを最初に(またはペアの1枚のカードでも!)最初にこの同じ比較を実行できます。(たとえば、A9772のようなハンドは77A92または7A927として保存され、ハンドA9972は9A729として保存され、上記のコードと比較して、7を9にピットして、 A9972ウォン)。2ペアのハンドは、最初に2ペアのうち高い方、次に低い方、「キッカー」の順に格納されます(たとえば、A9977は97A97として格納されます)。種類の3つは、最初の3つのカードのうち1枚、次にキッカー、他のカードの順に格納されます(たとえば、A7772は7A277になります)。満員の家は3つのうちの1つ、2つのうちの1つで保管されます(たとえば、99777は79779として保管されます)。また、ストレートとフラッシュはどちらも「直接辞書編集」の順序で保存できます。両方ともハイカードハンドと同じように比較されるためです。これにより、すでに与えられた機能を備えたすべての手のクラスで機能する簡単な外部コンパレーター機能が実現します。

// Compare two hands, returning -1/0/+1 as hand 1 is less than, equal to,
// or greater than hand 2. Note that this function assumes the hands have
// already been classified and sorted!
int CompareHands(Hand h1, Hand h2) {
  if ( h1.handClass > h2.handClass ) {
    return -1;
  } else if ( h1.handClass < h2.handClass ) {
    return 1;
  } else {
    return CompareHandsOfSameClass(h1, h2);
  }
}

うまくいけば、これが助けになるでしょう!


1

適切なカード表現とビット調整を使用して、いくつかの並列化が可能です。たとえば、このJavaコードは7カードのハードを評価しますし、2つの手を比較するために使用できる整数を返します。より使いやすい方法で手のタイプを報告するように適合させることができます。核となるアイデアは、以前の回答で参照されたCactus Kevのページから来ています。

効率とコードの明瞭さよりも、さまざまな言語でハンドに名前を付けるための可能な実装にのみ興味がある場合は 、codegolf.SEのポーカーハンド名前のチャレンジもご覧ください。


1

まず、すべてのカードのランクとスーツを知る必要があります。些細だが必要。

次に、これらの7つのカードをスピンして、2つのヒストグラムを作成します。ランクごとに1つ(13のインデックスを持つ配列を使用し、すべてがゼロに初期化され、そのランクの手札が見つかった場合に1ずつ増加します)、スーツごとに1つ(ランクと同様に構成された4つの要素の配列を使用) 。これらは線形操作であり、1セットのトラバーサルに対してのみ、各カードに対して両方の操作を実行できます。

次に、基準に一致するバケットの各ヒストグラムを調べるか、単純なフォローアップテストを行うことで、次の手のいずれかが存在するかどうかを判断できます。

  • ペア:1つのランクバケットの値はちょうど2で、他のバケットの値が1を超えず、フラッシュはありませんか?
  • 2ペア:2つ以上のランクバケットの値が正確に2であり、2を超えるバケットがなく、フラッシュもありませんか?(明らかに、3ペアは手ではありませんが、7枚のカードが与えられる可能性があります;最も強い2ペアはプレイヤーの手です)
  • TOAK:ちょうど1つのバケットの値が正確に3で、他のバケットの値が1より大きく、フラッシュがありませんか?
  • ストレート:5つの連続したランクバケットは、フラッシュなしで1以上の値を持ちますか?(エースが高いことも低いことも忘れないでください。14個の要素のランクヒストグラムを使用し、必要に応じて2つのバケットでエースをカウントできます)
  • フラッシュ:スーツバケットには5枚以上のカードがありますか?(もしそうなら、そのスーツのカードを手でスキャンし、トップ5を選択してください)
  • フルハウス:1つのランクバケットの値は3で、他のバケットの値は2です(7枚のカードでは、ピノクルデッキでプレイしていない限り、フルハウスでのフラッシュは不可能です)
  • Four of a Kind:1つのランクの値は4ですか?(他の組み合わせは不可能です)
  • ストレートフラッシュ:ヒストグラムで示されるストレートフラッシュの両方がありますか?ある場合、示されたストレートの各ランクに一致するランクを持つ、示されたフラッシュスーツに少なくとも1つのカードがありますか?(これはおそらく最も計算コストが高くなりますが、連続するランクの数を数えるのは簡単ですし、連続する5つのランクについては1回、6つの場合は2回、7つの場合は3回だけスキャンする必要があります)

ごく自然に、これらのチェックのいくつかを組み合わせることができます。

  • フラッシュはありますか?
  • ストレートはありますか?
    • 両方がある場合、それはまっすぐなフラッシュですか?
    • ストレートフラッシュの場合、エースとキングの両方がありますか?
  • 種類はありますか?
  • スリーカードはいくつありますか?(2、それは完全な家です。1、チェックペア)
  • ペアはいくつありますか?(2つ以上の場合は2ペアです。1つでは、3つある場合はフルハウス、それ以外の場合はペアです)
  • 上記のいずれでもない(高いカード)。

基本的に、これらへの答えが手になる場合、値がまだ高くない場合、結果の「手の強さ」の値を、見つかった手の強さに設定します。たとえば、9の強さ7のフルハウスがある場合、強さ4の3種類と強さ2のペアもあります。

そこいくつかのショートカットや速いアウトがありますが、全体的には本当にないこと、高価なだけですべてのチェックを実行します。


0

単純な反復アプローチでポーカーハンドを比較的簡単に行うことができます。

カードごとに、同じ顔をしている他の人が1人、2人、または3人いるかどうかを確認して、ペアまたは3/4の種類を確認します。

フルハウスも同様です。または、同じ顔ではないペアと3種類の両方を見つけた場合は、検出されたフルハウスにフラグを立てます。

フラッシュの場合、各スーツをチェックして、同じスーツが5つあるかどうかを確認します。

ソートされていなくても、まっすぐに確認するのは簡単です。カードごとに、上位のカードが1つあるかどうかを確認し、連続する5つのカードが見つかるまで繰り返します。

ロイヤルフラッシュとストレートフラッシュは、ストレートと同様に見つかります。ロイヤルフラッシュには、低い値のカードを無視できるという追加条件があります。

はい、このアプローチは非効率的ですが、ほとんどのポーカーゲームでは、それは無関係です。1秒あたり数千のハンドをチェックするのではなく、30分ごとに少数のプレイヤーをチェックしています。

より良いメソッドは存在しますが、コーディングに時間がかかる可能性があり、アルゴリズムの巧妙さと効率性に加えて、プレイヤーの観点からより良いゲームを実現するために、より多くの時間/お金を費やす重要なことがあります。


0

ペア、ダブルペア、トーク、フルハウス、ポーカーなどを見つける簡単な方法は次のとおりです。

次のようなネストされたループで各カードを互いに比較します。

int matches=0;
for (int i=0;i<5;i++)
   for (int j=0;j<5;j++)
      if (i!=j && cardvalue(card[j])==cardvalue(card[i])) matches++;

マッチは以下を保持します:
ペアの
場合は2 ペアの場合は4 ペア2の場合は
6トークの場合は
8 フルハウスの場合は8
ポーカーの 12

これを高速に最適化するには、最大5つのjループを実行する必要はなく、i-1まで実行できます。その後、比較「i!= j」を削除してから、一致の値を半分にすることができます(1 =ペア、2 = 2ペアなど)

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.