Stellen Sie eine 5-Karten-Pokerhand dar

11

Ein Kartenspiel ist 52. Eine Hand ist 5 Karten von den 52 (kann kein Duplikat haben).

Was ist die geringste Anzahl von Bits, um eine 5-Karten-Hand darzustellen, und wie?
Eine Hand ist NICHT auftragsabhängig (KQ = QK). 64329 = 96432

Ja, kann 52 Bit verwenden. Das kann eine Hand aus beliebig vielen Karten darstellen.

Wenn eine Hand genau 5 Karten hat, gibt es eine Möglichkeit, sie mit weniger als 52 Bit darzustellen.

Eine einzelne Karte kann mit 6 Bit = 64 dargestellt werden. Es können also nur 6 Bit * 5 Karten = 30 Bit verwendet werden. Das wäre aber auftragsabhängig. Ich könnte einfach sortieren und das sollte funktionieren. Wenn das nicht funktionieren würde, lass es mich wissen.

Gibt es eine Möglichkeit, den Schlüssel auf 32 Bit oder weniger zu bringen und das 5-Karten-Tupel nicht sortieren zu müssen?

Dies ist für Pokersimulationen gedacht und das Sortieren wäre viel Aufwand im Vergleich zum Generieren der Hand. Wenn ich ein Wörterbuch mit dem relativen Wert jeder Hand habe, sind es zwei einfache Suchvorgänge und ein Vergleich, um den Wert zweier Hände zu vergleichen. Wenn ich zuerst die Hände sortieren muss, ist das im Vergleich zu zwei Suchvorgängen und einem Vergleich groß. In einer Simulation werden Millionen verglichen. Ich werde keine sortierten Hände von der Simulation bekommen. Die Sortierung ist nicht einfach wie 52 51 50 49 48 vor 52 51 50 49 47. Sie können gerade bündige Quads haben ....

Es sind 2598960 5 Kartenhände möglich. Das ist die Anzahl der Zeilen. Der Schlüssel sind die 5 Karten. Ich möchte einen Schlüssel mit 32 Bit oder weniger erhalten, bei dem die Karten nicht zuerst sortiert werden müssen.

Kann nicht einfach die Liste bestellen, da viele Hände binden. Anzug sind Spaten, Keule, Diamant und Herz. 7c 8c 2d 3d 4s = 7s 8s 2c 3c 4h. Es gibt eine große Anzahl von Bindungen.

Der nächste Schritt ist 64 Bit und führt zu einem Treffer der Art, anstatt die Größe des Schlüssels zu verdoppeln.

Ich habe SortedSet<int> quickSort = new SortedSet<int>() { i, j, k, m, n };die Operationszeit getestet und verdoppelt, aber ich kann es trotzdem tun.

Es wird komplexer. Ich muss in der Lage sein, ein Boot zu zweit über fünf darzustellen (22255). Das Sortieren bricht das also. Ich weiß, dass du sagen wirst, aber das geht schnell. Ja, es ist schnell und trivial, aber ich brauche so schnell wie möglich.

C # für die akzeptierte Antwort:

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("");
}
Paparazzo
quelle
4
Verwenden Sie einen handcodierten Sortieralgorithmus, mit dem Listen der Länge 5 sortiert werden können. Dies ist wahrscheinlich schneller als die derzeit verwendete Bibliotheksfunktion.
Yuval Filmus
1
Ich verstehe nicht, warum Sie sagen "Die Sortierung ist nicht einfach" . Die Sortierung ist einfach: Konvertieren Sie jede Karte in eine Zahl von 1 bis 52, sodass die Hand durch eine Liste (Länge 5) von Karten dargestellt wird. Sortieren Sie diese Liste. Das ist nur das Problem, eine Liste von 5 ganzen Zahlen zu sortieren, was sehr schnell gehen kann, wie Yuval erwähnt. Ich schlage vor, dass Sie messen, bevor Sie davon ausgehen, dass es zu langsam ist, aber ich vermute, dass das Sortieren einer solchen Liste sehr schnell und möglicherweise sogar schneller ist als das Lesen eines Arbeitsspeichers mit wahlfreiem Zugriff, der nicht in den Cache gelangt.
DW
@dw Ja, die Sortierung ist einfach, aber was ich mache (millionenfach) ist einfach. Ich habe getestet und eine Sorte verdoppelt die Zeit.
Paparazzo
1
@Paparazzi Nein, Yuval fordert Sie auf, Ihre eigene Sortierroutine zu schreiben, die speziell auf das Sortieren von fünf Zahlen zwischen 1 und 52 abgestimmt ist. Sie haben versucht, eine Bibliotheksroutine zu verwenden, die langsam ist, weil sie viel allgemeiner ist als diese und weil sie rekursiv ist von quicksort macht es auf kurzen Listen sehr ineffizient.
David Richerby
In der Praxis können die meisten Elemente, die nicht <= 16 Bit sind, genauso gut 32 Bit sein. Da Sie also mindestens 23 Bit benötigen, ist wahrscheinlich jede Codierung mit <= 32 Bit möglich. Die triviale Codierung von 6 Bit pro Karte * 5 Karte funktioniert gut genug. Es gibt eine Einschränkung: Ein 23-Bit-Array-Index ist viel besser als ein 32-Bit-Array-Index.
MSalters

Antworten:

10

Sei ein Code. Die Paritätsprüfmatrix von ist eine Bit-Matrix, so dass die minimale Anzahl von Spalten, deren XOR verschwindet, beträgt . Bezeichnen Sie die Spalten mit . Wir können jedes als eine Binärzahl mit einer Länge von Bit identifizieren . Das Versprechen ist, dass der XOR von bis dieser Zahlen niemals . Auf diese Weise können Sie Ihre Hand als , wobei[ 52 , 25 , 11 ] C 27 × 52 11 52 A 1 , , A 52 A i 27 1 10 0 a , b , c , d , e A aA bA cA dA eH 1 , H 2 10 - 2 |C[52,25,11]C27×521152A1,,A52Ai271100a,b,c,d,eAaAbAcAdAeist XOR. In der Tat hängt dies eindeutig nicht von der Reihenfolge ab, und wenn zwei Hände kollidieren, ergibt das XORing der beiden Hash-Werte Zahlen, deren XOR Null ist.H1,H2102|H1H2|10

Bob Jenkins beschreibt einen solchen Code auf seiner Site , und daraus können wir das Array extrahieren

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

Da die ersten 27 Vektoren nur die 27 Zahlen des Hamming-Gewichts 1 sind, genügt es, um zu überprüfen, ob diese Konstruktion korrekt ist, alle möglich nicht trivial zu betrachten Kombinationen der letzten 25 Zahlen, wobei überprüft wird, ob ihre XORs immer mindestens 10 Hamming-Gewicht haben. Beispielsweise hat die allererste Zahl 0x07fe0000 genau 10 Hamming-Gewicht.252271=2251

Yuval Filmus
quelle
Ich folge nicht genau. Wie viele Bits benötigt dies für eine Hand?
Paparazzo
Es benötigt 27 Bit. Sie können eine beliebige Anzahl von Bits verwenden.
Yuval Filmus
Vielen Dank. Ich habe getestet und die Zahlen sind eindeutig und <= 32 Bit. Kann ich die 5 Karten aus der Nummer ableiten? Wenn nicht gut, frag einfach.
Paparazzo
Ja, es ist einfache lineare Algebra. Sie können die richtige Matrix verwenden, um einen Vektor der Länge 52 mit 5 Einsen zurückzugewinnen. Ich lasse dich das herausfinden.
Yuval Filmus
13

nlgnlg2598960=22

Wie funktioniert die Darstellung? Es gibt verschiedene Optionen mit unterschiedlichen Kompromissen. Ich liste zwei unten auf.

Hartcodiertes Wörterbuch

In diesem Fall ist die Anzahl der möglichen 5-Karten-Hände so klein, dass Sie nur ein fest codiertes Wörterbuch haben könnten, in dem alle 2598960 Hände aufgelistet sind, und Sie repräsentieren eine Hand durch ihren Index im Wörterbuch (binär dargestellt).

Mit anderen Worten, das Wörterbuch kann eine sortierte Liste von Händen sein. Jede Hand ist das 5-Tupel der Karten in der Hand in sortierter Reihenfolge. Sie können mithilfe der binären Suche eine Hand im Wörterbuch nachschlagen und den entsprechenden Index finden. und mit einem Index können Sie die entsprechende Hand finden. Sie können das Wörterbuch auch als Hashmap speichern, die von der Hand auf den Index abgebildet wird. Der Index ist eine Ganzzahl zwischen 0 und 2598959, sodass er mit 23 Bit dargestellt werden kann.

Dieser Ansatz funktioniert und ist sehr einfach zu programmieren, ist jedoch platzsparend (Größe der ausführbaren Programmdatei).

Ranking / Unranking

Wenn Sie sich interessieren, gibt es alternativ bessere Methoden. Siehe z. B. eine der folgenden Referenzen:

Das allgemeine Thema ist als "Rangfolge (und Nichtrangierung) von Kombinationen" bekannt. Diese sind etwas komplexer zu implementieren und zu verstehen, vermeiden jedoch die Notwendigkeit, ein fest codiertes Wörterbuch in das Programm aufzunehmen.

DW
quelle
Ich werde die Frage aktualisieren. Ja, es gibt 2598960 Hände. Das Wörterbuch wird so viele Zeilen haben. Mein Problem ist die Generierung des Schlüssels. Aus 5 Karten muss ich einen Schlüssel generieren, um die Wörterbuchsuche durchzuführen.
Paparazzo
@Paparazzi, wenn Sie den Wörterbuch Ansatz verwenden, die Hand ist der Schlüssel. Mit anderen Worten, der Schlüssel ist das 5-Tupel der Karten auf der Hand (in sortierter Reihenfolge). Das Wörterbuch kann als Hashtabelle gespeichert werden, wobei diese als Schlüssel verwendet wird. Wenn Ihnen die Speicherkosten eines Wörterbuchs nicht gefallen, verwenden Sie den alternativen Ansatz: Ranking / Unranking.
DW
Ja, ich weiß, dass ich den Schlüssel mit 30 Bit erhalten kann, wenn ich sortiere. Ich frage mich, ob es eine Möglichkeit gibt, den Schlüssel 32 Bit oder weniger zu erhalten, ohne das 5-Karten-Tupel zu sortieren. Ich werde mich mit Rang und Rang befassen.
Paparazzo
Ich folge nicht dem Ranking / Unranking, aber danke. Ich werde versuchen, es herauszufinden. Haben Sie auch die Möglichkeiten der Krawatten. Es gibt viele Bindungen.
Paparazzo
1
Ebenfalls relevant: cs.stackexchange.com/questions/67664/…
Pseudonym
3

Sie können die fünf Elemente sortieren und gleichzeitig ohne Vergleiche auf einigen Prozessoren nach Duplikaten suchen: Angenommen, ein Prozessor verfügt über einen schnellen Befehl, der die Position des höchsten gesetzten Bits bestimmt, und einen schnellen Befehl, der eine Zahl berechnet, bei der nur das n-te Bit gesetzt ist .

Sei Bit (n) die Zahl, bei der genau das n-te Bit gesetzt ist. Sei das höchste Bit (x) die Nummer des höchsten Bits, das in der Zahl x gesetzt ist, mit einem nicht spezifizierten Wert, wenn x = 0. Sei x ^ y das Exklusiv-oder von x und y.

Gegeben sind fünf Zahlen a, b, c, d und e von jeweils 0 bis 51, die die fünf Karten in der Hand darstellen.

Sei x = Bit (a) ^ Bit (b) ^ Bit (c) ^ Bit (d) ^ Bit (e).

Sei A = höchstes_Bit (x), ändere x in x ^ Bit (A).

Sei B = höchstes Bit (x), ändere x in x ^ Bit (B).

Sei C = höchstes_Bit (x), ändere x in x ^ Bit (C).

Sei D = höchstes Bit (x), ändere x in x ^ Bit (D).

Sei E = höchstes Bit (x).

Wenn x = 0, gab es Duplikate in den Zahlen a, b, c, d und e. Verwenden Sie andernfalls A * Bit (24) + B * Bit (18) + C * Bit (12) + D * Bit (6) + E als Codierung der Hand, wobei A, B, C, D und E sind wie oben definiert. Dadurch wird eine Hand als 30-Bit-Zeichenfolge codiert, während die Sortierung auf sehr effiziente Weise durchgeführt wird.

gnasher729
quelle
Verwendet dies 52 Bit?
Paparazzo
@ Paparazzi, nein. Schauen Sie sich den letzten Absatz noch einmal an. Ich habe es bearbeitet, um noch mehr Klarheit zu schaffen.
DW
1
Es erfordert eine 64-Bit-CPU, aber das Endergebnis ist nur 30 Bit.
Yuval Filmus