Bestimmung der Pokerhände

19

Ich habe ein Texas Hold'Em-Spiel als Teil einer Bewertung durchgeführt und darüber nachgedacht, wie ich die 7 verfügbaren Karten untersuchen und feststellen kann, ob noch Hände vorhanden sind.

Die einzig mögliche Methode, die ich mir vorstellen kann, ist, die Karten numerisch zu sortieren, dann jede mögliche Gruppe von 5 Karten zu untersuchen und zu überprüfen, ob sie mit einer Liste jeder einzelnen möglichen Hand übereinstimmen. Das würde viel Zeit in Anspruch nehmen und wäre nur für die Paarermittlung sinnvoll, da der Anzug keine Rolle spielt.

Bei den Karten handelt es sich jeweils um Zeichenfolgen, die aus einer Zahl / a / j / q / k und einer Farbe (char)3(die ein kleines Pik-Symbol darstellt) bestehen.

Hat jemand Vorschläge, Formeln oder Links, die ich zur Erstellung eines Handanalysesystems verwenden könnte?

Machen Sie sich noch keine Sorgen, dass Sie Ihre Hände gegeneinander antreten, das ist ein anderer Fischkessel.

Magicaxis
quelle
1
Ich möchte nur darauf hinweisen, aber das Vektor-Tag in seinem Kontext handelt von linearer Algebra. Nicht der Container.
Sidar
@Sidar Fühlen Sie sich frei, die Tags in Zukunft zu bearbeiten, wenn Sie glauben, dass sie nicht passen. Wenn Sie mit der Maus über die Tags fahren, wird die Option "Tags bearbeiten" angezeigt (zumindest für mich?), Und Sie können nur die Tags bearbeiten, ohne die Frage zu bearbeiten.
MichaelHouse
@ Byte56 Ich habe die seltsame Angewohnheit zu denken, dass ich nicht sicher bin, ob ich Recht habe, also mache ich es passiv durch einen Kommentar ... Deshalb habe ich den Beitrag nicht bearbeitet. Vielleicht habe ich etwas in der Post verpasst, also habe ich auf seine Antwort gewartet.
Sidar
Es gibt hier auch einen schönen Artikel, der vor ein paar Jahren in Game Developer erschienen ist: cowboyprogramming.com/2007/01/04/programming-poker-ai
celion
1
Ich habe vor einiger Zeit eine Implementierung in Java zum Spaß gemacht. Sie finden sie hier: codereview.stackexchange.com/questions/10973/… . Wenn Sie in PokerHand.java nachsehen, finden Sie Methoden zum Testen jeder Art von Hand (z. B. isFullHouse). Sie funktionieren nur, wenn die Karten zuerst sortiert werden.
bughi

Antworten:

20

Ich denke, Sie können die Mehrheit der Pokerhände finden, indem Sie einfach ein paar Tische aus der Anzahl der Karten in der Hand machen, die für jeden Rang und jede Farbe vorhanden sind.

Mit anderen Worten, erstellen Sie ein Array, das die Kartenreihen (Zahlen und A / J / Q / K) mit der Anzahl der Karten dieses Ranges in Ihrer Hand verknüpft. Wenn der Spieler ein Paar oder einen Drilling hat, gibt es ein Element in diesem Array, das 2 oder 3 usw. entspricht. Sie haben ein volles Haus, wenn es ein Element gibt, das 2 ist, und ein anderes, das 3 ist, und eine Straße wenn es in diesem Array fünf aufeinanderfolgende Elemente gibt, die gleich 1 sind.

Ebenso können Sie eine ähnliche Anordnung der Kartenzahl jeder Farbe erstellen und sie zum Erkennen von Flushes verwenden.

Sobald Sie das Vorhandensein einer bestimmten Hand erkannt haben, ist es ziemlich einfach, zurück zu gehen und die bestimmten Karten in der Hand zu finden, um sie in der Benutzeroberfläche hervorzuheben oder was auch immer Sie tun müssen.

Im Pseudocode:

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...
Nathan Reed
quelle
17

Es ist etwas knifflig, weil es so viele Kombinationen gibt. Zum Glück haben Sie einen Prozessor, der in kürzester Zeit eine Vielzahl von Kombinationen prüfen kann.

Sie benötigen ein paar verschiedene Strategien, um verschiedene Arten von Händen zu erkennen. Glücklicherweise können einige der verschiedenen Typen Strategien überlappen. Ich würde suchen, um nach Rang der Hand.

  1. Straight Flush
  2. Vier von einer Sorte
  3. Volles Haus
  4. Spülen
  5. Gerade
  6. Drei gleiche
  7. Zwei Paare
  8. Ein Paar
  9. Hohe Karte

2, 3, 6, 7, 8Sind alle einfachen Zählen. Platzieren Sie mithilfe einer Kartenliste Ace to King einfach die Nummer jedes Werts in der Liste und erhöhen Sie sie für jede weitere gefundene Karte. Dann überprüfe die Liste für 4s. Wenn es keine 4s gibt, hast du keine 4 of a kind. Überprüfe es für 3s. Wenn es keine 3s gibt, hast du keinen 3er. Wenn Sie eine 3 haben, suchen Sie nach einer 2 (was bedeutet, dass das Haus voll ist). Und so weiter...

Für 1, 5können Sie die gleiche Liste verwenden und für Sequenzen suchen , wo alle Karten einen oder mehr Einträge in der Liste für eine Folge von 5 Karten haben. Wenn sie auch den gleichen Anzug haben, ist es ein Straight Flush.

4kann die gleiche Liste haben, aber diesmal zählst du den Anzug. Achten Sie auf Zahlen von 5 oder höher.

Schließlich haben 9Sie die höchste Karte, was eine einfache Sache sein sollte, den letzten höchsten Wert aus einer Ihrer obigen Listen zu betrachten.

Sie können ausbrechen, sobald Sie eine Übereinstimmung gefunden haben, wenn Sie nacheinander suchen. Es wäre jedoch trivial, die Suche fortzusetzen und alle Übereinstimmungen zu finden, wenn Sie dem Benutzer alle diese Informationen zur Verfügung stellen möchten.


Im Wesentlichen füllen Sie Eimer. Überprüfen Sie dann die Eimer auf Kombinationen. Um zu veranschaulichen:

Bildbeschreibung hier eingeben

Beginnen Sie mit einem Array und einem Bucket für jede Karte, durchlaufen Sie die Karten und zählen Sie die Instanz jeder Karte. Anschließend können Sie das Array einfach durchlaufen und nach bestimmten Kombinationen suchen. In diesem Beispiel ist klar, dass es sich um einen Vierling handelt, da in einem der Eimer vier Elemente enthalten sind.

MichaelHouse
quelle
6

Ich bin einmal auf diesen Algorithmus gestoßen. Es multipliziert Primzahlen, um Hände zu bestimmen und ist eine sehr interessante Lesart. Cactus Kevs Pokerhand-Bewerter

petervaz
quelle
1
Das ist interessant, aber ich bin mir nicht sicher, ob du alles gelesen hast. Dieser Algorithmus ist für 5 Karten . Möglicherweise haben Sie in einer Google-Suche nach 7 Karten gesucht, da der Autor angibt, dass sie einen Algorithmus für 7 Karten haben, diesen aber nicht freigeben. Siehe den grauen Text oben auf der Seite. Ich bin mir also nicht sicher, wie nützlich dieser Algorithmus für ein 7-Karten-Set ist.
MichaelHouse
1
Da es nur 21 verschiedene 5-Karten-Hände gibt, die aus einer 7-Karten-Hand hergestellt werden können, besteht eine Option darin, jeweils einen 5-Karten-Bewerter zu verwenden und die besten auszuwählen.
Adam
@Byte56 Du hast recht, ich erinnere mich, dass ich 7 Karten verwendet habe, aber vorher die besten 5 Karten ermitteln musste, was die Effizienz irgendwie untergraben hat.
Petervaz
Der Link zu dieser Antwort ist inzwischen verfault und die Domain wurde von einem Spammer abgenommen. Ich habe den Link zu einem Archiv der Originalseite umgeleitet, aber um diese Antwort robuster zu gestalten, ist es ideal, die Antwort so zu bearbeiten, dass sie eine Zusammenfassung des vorgeschlagenen Algorithmus im Hauptteil der Antwort selbst enthält.
DMGregory
2

Als Ergänzung zu den hervorragenden Antworten, die diese Frage bereits erhalten hat, hielt ich es für hilfreich, eine der einfachsten Möglichkeiten zum Vergleichen von Händen anzubieten, sobald die grundlegende Klassifizierungstechnik vorhanden ist. Zunächst möchten Sie die Hände mit ihrer Klasse kennzeichnen , wie zahlreiche Antworten gezeigt haben - die meisten Ihrer Vergleiche mit "Ist Hand X besser als Hand Y?" Sie können dann einfach die Klassen der beiden Hände vergleichen und herausfinden, welche Klasse besser ist. Im Übrigen müssen Sie tatsächlich Karten für Karten vergleichen, und es stellt sich heraus, dass ein bisschen mehr Arbeit bei der Klassifizierung dies einfacher macht.

Betrachten Sie als Grundfall die Situation, in der beide Hände 'High Card'-Hände sind. In diesem Fall würden Sie zuerst die beiden höchsten Karten vergleichen, dann (wenn sie übereinstimmen) die beiden nächsten Karten usw. Wenn Sie annehmen, dass jede Eingabekarte von der höchsten zur niedrigsten Karte sortiert ist, führt dieser Ansatz zu einem Code, der aussieht Dies:

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;
}

Nun die gute Nachricht: Es stellt sich heraus, dass diese lexikografische Anordnung , die in geeigneter Weise optimiert wurde, zum Vergleichen von zwei Händen dient jeder dientder Klassen, solange ihre Klasse gleich ist. Da der Vergleich von Paaren beispielsweise darin besteht, zuerst die Paare und dann die anderen drei Karten zu vergleichen, können Sie Ihre Hand so sortieren, dass das Paar an erster Stelle steht (oder sogar eine Karte des Paares an erster Stelle!) Und denselben Vergleich durchführen. (So ​​würde beispielsweise eine Hand wie A9772 entweder als 77A92 oder, noch besser, als 7A927 gespeichert. Die Hand A9972 würde als 9A729 gespeichert und Sie würden mit dem obigen Code vergleichen, indem Sie 7 gegen 9 spielen und das herausfinden A9972 gewonnen). Eine Hand mit zwei Paaren würde zuerst mit dem höheren der beiden Paare gespeichert, dann mit dem niedrigeren und dann mit dem 'Kicker' (so würde zB A9977 als 97A97 speichern); Drei Gleiche werden mit einer der drei Karten zuerst gespeichert, dann mit den Kickern und dann mit den anderen Karten (z. B. A7772 wäre 7A277). ein volles Haus würde mit einem seiner drei und dann einem seiner zwei gespeichert werden (z. B. würde 99777 als 79779 gespeichert werden); und Straights und Flushes können beide in "direkter lexikografischer" Reihenfolge gespeichert werden, da beide wie High-Card-Hände verglichen werden. Dies führt zu einer einfachen äußeren Komparatorfunktion, die für alle Zeigerklassen mit der bereits gegebenen Funktion funktioniert:

// 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);
  }
}

Hoffentlich hilft das!

Steven Stadnicki
quelle
1

Mit geeigneten Kartendarstellungen und Bit-Twiddling sind einige Parallelisierungen möglich. Beispielsweise wertet dieser Java-Code 7-Karten-Festplatten aus, die eine Ganzzahl zurückgeben, die zum Vergleichen von zwei Händen verwendet werden kann. Es könnte angepasst werden, um die Art der Hand benutzerfreundlicher zu melden. Die Kernideen stammen von Cactus Kevs Seite, auf die in einer früheren Antwort verwiesen wurde.

Wenn Sie nur an möglichen Implementierungen für die Benennung der Hand in verschiedenen Sprachen interessiert sind, anstatt an Effizienz und Code-Klarheit, können Sie sich auch die Herausforderung Name the Poker Hand auf codegolf.SE ansehen.

Peter Taylor
quelle
1

Zunächst müssen Sie den Rang und die Farbe aller Karten kennen. trivial aber notwendig.

Dann drehen Sie sich durch diese 7 Karten und erstellen Sie zwei Histogramme; eine nach Rang (unter Verwendung eines Arrays mit 13 Indizes, alle auf Null initialisiert und um 1 erhöht, wenn eine Karte in der Hand mit diesem Rang gefunden wird) und eine nach Farbe (unter Verwendung eines Arrays mit vier Elementen, die ähnlich wie für Rang aufgebaut sind) . Dies sind lineare Operationen, und Sie können beide Operationen für jede Karte nur für einen Satz von Durchläufen ausführen.

Sie können dann feststellen, ob eine der folgenden Hände vorhanden ist, indem Sie einfach jedes Histogramm auf Buckets untersuchen, die den Kriterien entsprechen, und / oder einen einfachen Folgetest durchführen:

  • Paar: Hat genau ein Rang-Bucket einen Wert von genau 2, während kein anderer Bucket einen Wert über 1 und keinen Flush hat?
  • Zwei Paare: Haben zwei oder mehr Rang-Eimer einen Wert von genau 2, wobei kein Eimer mehr als 2 und kein Flush hat? (Drei Paare sind natürlich keine Hand, aber bei sieben Karten ist dies eine Möglichkeit. Das stärkste Paar ist die Hand des Spielers.)
  • TOAK: Hat genau ein Eimer einen Wert von genau 3, während kein anderer Eimer einen Wert größer als 1 und kein Flush hat?
  • Straight: Haben fünf aufeinanderfolgende Rang-Buckets einen Wert von 1 oder mehr ohne Flush? (Vergessen Sie nicht, dass Asse sowohl hoch als auch niedrig sind. Sie können ein Ranghistogramm mit 14 Elementen verwenden und Asse in zwei Eimern zählen, wenn Sie möchten.)
  • Flush: Hat jeder Anzug Eimer 5 oder mehr Karten? (Wenn ja, scannen Sie die Hand nach Karten dieser Farbe und wählen Sie die Top 5 aus.)
  • Full House: Hat ein Rang-Bucket einen Wert von 3 und ein anderer Bucket einen Wert von 2 (bei 7 Karten ist ein Flush mit einem Full House nur möglich, wenn Sie mit einem Pinochle-Deck spielen)
  • Vierling: Hat ein Rang einen Wert von 4? (keine andere Kombination sollte möglich sein)
  • Straight Flush: Gibt es sowohl einen Straight als auch einen Flush, die durch die Histogramme angezeigt werden? Wenn ja, gibt es mindestens eine Karte in der angezeigten Flush-Farbe, deren Rang mit jedem Rang der angezeigten Straße übereinstimmt? (Dies ist wahrscheinlich der rechenintensivste, aber es sollte einfach zu zählen sein, wie viele aufeinanderfolgende Ränge es gibt, und Sie sollten die Hand nur einmal für 5 aufeinanderfolgende Ränge scannen müssen, zweimal für 6 und dreimal für 7)

Sie können natürlich mehrere dieser Prüfungen kombinieren:

  • Gibt es einen Flush?
  • Gibt es eine Straße?
    • Wenn es beides gibt, ist es ein Straight Flush?
    • Wenn es ein Straight Flush ist, hat es sowohl ein Ass als auch einen König?
  • Gibt es einen Vierling?
  • Wie viele Dreier gibt es? (Zwei, es ist ein volles Haus. Eins, check pairs)
  • Wie viele Paare gibt es? (Bei zwei oder mehr ist es zwei Paare. Bei einem ist es ein volles Haus, wenn es auch drei gibt, sonst ist es ein Paar.)
  • Keine der oben genannten (hohe Karte).

Wenn die Antworten auf diese Fragen eine Hand ergeben, setzen Sie den resultierenden Wert für "Handstärke" auf die Stärke der gefundenen Hand, sofern der Wert nicht bereits höher ist. Wenn Sie zum Beispiel ein volles Haus haben, Stärke 7 von 9, dann haben Sie auch einen Drilling, Stärke 4, und ein Paar, Stärke 2.

Es gibt ein paar Abkürzungen und schnelle Outs, aber insgesamt ist es wirklich nicht , dass teuer, nur laufen alle Prüfungen.

KeithS
quelle
0

Mit einem einfachen iterativen Ansatz können Sie relativ einfach Pokerhände spielen.

Überprüfen Sie für jede Karte, ob es eine oder zwei oder drei andere mit dem gleichen Gesicht gibt, um ein Paar oder drei / vier Gleiche zu finden.

Volle Häuser sind ähnlich. Oder wenn Sie sowohl ein Paar als auch drei Gleiche finden, die nicht dasselbe Gesicht haben, markieren Sie ein volles Haus als gefunden.

Überprüfen Sie bei Flushs jeden Anzug, um festzustellen, ob es fünf gleiche Anzüge gibt.

Gerade zu prüfen ist einfach, auch wenn unsortiert. Überprüfen Sie für jede Karte, ob es eine höhere gibt, und wiederholen Sie den Vorgang, bis fünf aufeinanderfolgende Karten gefunden wurden oder nicht.

Royal Flushes und Straight Flushes sind ähnlich wie Straight Flushes zu finden. Royal Flushes haben einige zusätzliche Bedingungen, so dass Karten mit niedrigerem Wert ignoriert werden können.

Ja, dieser Ansatz ist ineffizient, aber für die meisten Pokerspiele ist das irrelevant. Sie überprüfen jede halbe Minute eine winzige Handvoll Spieler und nicht Tausende von Händen pro Sekunde.

Es gibt bessere Methoden, aber das Codieren kann mehr Zeit in Anspruch nehmen, und Sie müssen wahrscheinlich mehr Zeit / Geld für ein besseres Spiel aus der Sicht der Spieler aufwenden, abgesehen von der Klugheit und Effizienz eines Algorithmus.

Sean Middleditch
quelle
0

Ein einfacher Weg, um Paare, Doppelpaare, Toaks, Full Houses, Poker usw. zu finden, ist der folgende:

vergleiche jede Karte miteinander in einer verschachtelten Schleife wie dieser:

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++;

Die Matches haben folgende Gültigkeit :
2 für ein Paar
4 für zwei Paare
6 für Token
8 für ein Fullhouse
12 für ein Poker

um dies zu beschleunigen, muss die j-loop nicht bis zu 5 ausgeführt werden, sondern kann bis zu i-1 ausgeführt werden. der Vergleich "i! = j" kann dann entfernt werden, die Werte für die Übereinstimmung werden dann halbiert (1 = Paar, 2 = 2 Paare usw.)

Thomas Schüler
quelle