5カードのポーカーハンドを表す


11

カードのデッキは52です。手札は52枚の5枚のカードです(重複はできません)。

5カードのハンドを表すための最小ビット数はどれくらいですか?
ハンドは順序に依存しません(KQ = QK)。64329 = 96432

はい、52ビットを使用できます。それは任意の数のカードの手札を表すことができます。

ハンドがちょうど5枚のカードであるとすると、52ビット未満でそれを表す方法があります。

1枚のカードは6ビット= 64で表すことができます。したがって、6ビット* 5カード= 30ビットを使用できます。しかし、それは順序に依存します。私は単にソートすることができ、これはうまくいくはずです。うまくいかない場合はお知らせください。

32ビット以下のキーを取得し、5カードのタプルをソートする必要がない方法はありますか?

これはポーカーシミュレーション用であり、ソーティングはハンドを生成するだけの場合に比べてオーバーヘッドが大きくなります。両手の相対値を持つ辞書がある場合、それは2つの単純な検索と2つの手の値を比較する比較です。最初にハンドをソートする必要がある場合、2つのルックアップと比較と比較すると、それは大きいです。シミュレーションでは数百万を比較します。シミュレーションからソートされた手を取得しません。52 51 50 49 48の前の52 51 50 49 48のように並べ替えは単純ではありません。

2598960の可能な5カードの手があります。それが行数です。キーは5枚のカードです。カードを最初にソートする必要がない32ビット以下のキーを取得したいと考えています。

多くの人が結ぶほどリストを注文することはできません。スーツはスペード、クラブ、ダイヤ、ハートです。7c 8c 2d 3d 4s = 7s 8s 2c 3c 4h。多くの絆があります。

次のステップは64ビットで、キーのサイズを2倍にするのではなく、ソートのヒットになります。

私はテストしSortedSet<int> quickSort = new SortedSet<int>() { i, j, k, m, n };て操作の時間を2倍にしましたが、それでも実行できます。

より複雑になります。ボートを5対2で表すことができる必要があります(22255)。そのため、それらを並べ替えると壊れます。あなたが言うつもりですが、それは速いです。はい、それは速くてささいなことですが、私はできるだけ速くする必要があります。

受け入れられた回答のC#:

private int[] DeckXOR = new int[] {0x00000001,0x00000002,0x00000004,0x00000008,0x00000010,0x00000020,0x00000040,
                                    0x00000080,0x00000100,0x00000200,0x00000400,0x00000800,0x00001000,0x00002000,
                                    0x00004000,0x00008000,0x00010000,0x00020000,0x00040000,0x00080000,0x00100000,
                                    0x00200000,0x00400000,0x00800000,0x01000000,0x02000000,0x04000000,0x07fe0000,
                                    0x07c1f000,0x0639cc00,0x01b5aa00,0x056b5600,0x04ed6900,0x039ad500,0x0717c280,
                                    0x049b9240,0x00dd0cc0,0x06c823c0,0x07a3ef20,0x002a72e0,0x01191f10,0x02c55870,
                                    0x007bbe88,0x05f1b668,0x07a23418,0x0569d998,0x032ade38,0x03cde534,0x060c076a,
                                    0x04878b06,0x069b3c05,0x054089a3};
public void PokerProB()
{
    Stopwatch sw = new Stopwatch();
    sw.Start();
    HashSet<int> cardsXOR = new HashSet<int>();
    int cardXOR;
    int counter = 0;
    for (int i = 51; i >= 4; i--)
    {
        for (int j = i - 1; j >= 3; j--)
        {
            for (int k = j - 1; k >= 2; k--)
            {
                for (int m = k - 1; m >= 1; m--)
                {
                    for (int n = m - 1; n >= 0; n--)
                    {
                        counter++;
                        cardXOR = DeckXOR[i] ^ DeckXOR[j] ^ DeckXOR[k] ^ DeckXOR[m] ^ DeckXOR[n];
                        if (!cardsXOR.Add(cardXOR))
                            Debug.WriteLine("problem");
                    }
                }
            }
        }
    }
    sw.Stop();
    Debug.WriteLine("Count {0} millisec {1} ", counter.ToString("N0"), sw.ElapsedMilliseconds.ToString("N0"));
    Debug.WriteLine("");
}

4
長さ5のリストをソートするために機能する手動コーディングのソートアルゴリズムを使用します。これは、現在使用しているライブラリ関数よりもおそらく高速です。
Yuval Filmus

1
なぜ「並べ替えは簡単ではない」と言うのかわかりません。並べ替え簡単です。各カードを1〜52の数値に変換し、手札を(長さ5の)カードのリストで表します。そのリストを並べ替えます。Yuvalが述べているように、これは5つの整数のリストをソートする問題であり、非常に高速に実行できます。遅すぎると想定する前に測定することをお勧めしますが、そのようなリストのソートは非常に高速で、キャッシュでヒットしないランダムアクセスメモリの読み取りよりも高速になる可能性があると思います。
DW

@dwはい、種類は単純ですが、私が何をしているか(何百万回も)は単純です。私がテストしたところ、ソートにより時間が2倍になりました。
パパラッツォ

1
@Paparazziいいえ、Yuvalは、1から52までの5つの数値をソートするように特別に調整された独自のソートルーチンを書くように指示しています。ライブラリルーチンを使用してみました。クイックソートを使用すると、短いリストでは非常に非効率になります。
David Richerby 2017

実際には、16ビット以下でないほとんどのアイテムは32ビットである可能性があります。したがって、少なくとも23ビットが必要なため、32ビット以下を使用するエンコーディングはおそらく実行可能です。カードあたりの簡単な6ビット* 5カードのエンコーディングは十分に機能します。注意点が1つあります。23ビットの配列インデックスは、32ビットの配列インデックスよりもはるかに優れています。
MSalters 2017

回答:


10

C[52,25,11]C27×521152A1,,A52Ai271100。これを使用して、あなたの手をエンコードすることができますa,b,c,d,eAaAbAcAdAeH1,H2102|H1H2|10

Bob Jenkinsはそのようなコードを彼のサイトで説明しており、そこから配列を抽出できます

0x00000001,0x00000002,0x00000004,0x00000008,0x00000010,0x00000020,0x00000040,
0x00000080,0x00000100,0x00000200,0x00000400,0x00000800,0x00001000,0x00002000,
0x00004000,0x00008000,0x00010000,0x00020000,0x00040000,0x00080000,0x00100000,
0x00200000,0x00400000,0x00800000,0x01000000,0x02000000,0x04000000,0x07fe0000,
0x07c1f000,0x0639cc00,0x01b5aa00,0x056b5600,0x04ed6900,0x039ad500,0x0717c280,
0x049b9240,0x00dd0cc0,0x06c823c0,0x07a3ef20,0x002a72e0,0x01191f10,0x02c55870,
0x007bbe88,0x05f1b668,0x07a23418,0x0569d998,0x032ade38,0x03cde534,0x060c076a,
0x04878b06,0x069b3c05,0x054089a3

252271=2251


私は正確には従いません。これは何ビット必要ですか?
パパラッツォ2017

27ビットが必要です。より多くのビットを使用できます。
Yuval Filmus

ありがとう。私はテストしましたが、番号は一意で<= 32ビットです。番号から5枚のカードを導き出すことはできますか?うまくいかない場合は、質問してください。
パパラッツォ2017

はい、それは単純な線形代数です。正しい行列を使用して、長さが52で、1が5のベクトルを取得できます。それを理解させてあげましょう。
Yuval Filmus

13

nlgnlg2598960=22

表現はどのように機能しますか?さまざまなトレードオフのあるさまざまなオプションがあります。以下に2つ挙げます。

ハードコードされた辞書

この場合、可能な5カードのハンドの数は十分に少ないので、2598960のハンドすべてをリストするハードコードされたディクショナリがあり、ハンドをディクショナリ内のインデックス(バイナリで表される)で表します。

言い換えれば、辞書はソートされた手のリストにすることができます。各手札は、ソートされた順序での、手札の5枚組です。バイナリ検索を使用して辞書で手を調べ、対応するインデックスを見つけることができます。インデックスを指定すると、対応する手が見つかります。または、辞書を手からそのインデックスにマップするハッシュマップとして保存することもできます。インデックスは0〜2598959の整数であるため、23ビットを使用して表すことができます。

このアプローチは機能し、プログラムするのは非常に簡単ですが、スペース(プログラム実行可能ファイルのサイズ)が無駄になります。

ランキング/アンランキング

または、気になる場合は、より良い方法があります。たとえば、次の参考文献のいずれかを参照してください。

一般的なトピックは、「組み合わせのランキング(およびランク解除)」として知られています。これらは実装と理解が少し複雑ですが、プログラムにハードコーディングされた辞書を含める必要はありません。


質問を更新します。はい、2598960ハンドがあります。ディクショナリにはその数の行があります。私の問題は鍵の生成です。5枚のカードから、辞書検索を実行するためのキーを生成する必要があります。
パパラッツォ2017

@Paparazzi、辞書のアプローチを使用する場合、手なります。つまり、キーは手札のカードの5タプルです(ソート順)。辞書はそれをキーとして使用してハッシュテーブルとして保存できます。辞書のメモリコストが気に入らない場合は、別のアプローチを使用してください。
DW

はい、ソートすると30ビットのキーを取得できることがわかっています。5カードのタプルをソートせずに32ビット以下のキーを取得する方法があるかどうか疑問に思っています。ランクとランキングを調べます。
パパラッツォ2017

ランキング・アンランキングはフォローしていませんがありがとうございます。私はそれを理解しようとします。ネクタイの可能性もあります。多くのつながりがあります。
パパラッツォ2017


3

5つの項目を並べ替えて、一部のプロセッサで比較せずに重複を同時にチェックできます。プロセッサには、最上位ビットセットの位置を決定する高速命令と、n番目のビットセットのみで数値を計算する高速命令があると想定します。 。

ビット(n)を、まさにn番目のビットが設定された数値とする。最高のビット(x)を、数値xに設定された最高のビットの数とし、x = 0の場合は未指定の値とします。x^ yをxとyの排他的論理和とします。

与えられているのは、手札の5枚のカードを表す、0〜51の5つの数字a、b、c、d、eです。

x =ビット(a)^ビット(b)^ビット(c)^ビット(d)^ビット(e)とします。

A =最も高いビット(x)とし、xをx ^ビット(A)に変更します。

B =最高ビット(x)とし、xをx ^ビット(B)に変更します。

C =最高ビット(x)とし、xをx ^ビット(C)に変更します。

D =最高ビット(x)とし、xをx ^ビット(D)に変更します。

E =最高ビット(x)とします。

x = 0の場合、番号a、b、c、d、およびeに重複がありました。それ以外の場合は、手のエンコーディングとしてA *ビット(24)+ B *ビット(18)+ C *ビット(12)+ D *ビット(6)+ Eを使用します。A、B、C、D、Eは上記のように定義されます。これは、非常に効率的な方法で並べ替えを行いながら、手を30ビットの文字列としてエンコードします。


これは52ビットを使用しますか?
パパラッツォ2017

@パパラッチ、いいえ。最後の段落をもう一度見てください。さらにわかりやすくするために編集しました。
DW

1
64ビットのCPUが必要ですが、最終的な結果はわずか30ビットです。
Yuval Filmus
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.