Déterminer les mains de poker

19

J'ai fait un jeu Texas Hold'Em dans le cadre d'une évaluation, et j'ai réfléchi à la façon d'examiner les 7 cartes disponibles et de déterminer si des mains existent.

La seule méthode possible à laquelle je peux penser est de trier les cartes numériquement, puis d'examiner chaque groupe possible de 5 cartes et de vérifier si elles correspondent à une liste de chaque main possible. Cela prendrait beaucoup de temps et ne serait possible que pour déterminer des paires, car la combinaison n'est pas pertinente.

Les cartes sont chacune des chaînes, composées d'un nombre / a / j / q / k, et d'un costume (char)3(qui fait un petit symbole de pique).

Quelqu'un at-il des suggestions, des formules ou des liens que je pourrais utiliser pour aider à créer un système d'analyse manuelle?

Ne vous inquiétez pas encore de classer les mains l'une contre l'autre, c'est une autre marmite de poisson.

Magicaxis
la source
1
Je le signale simplement, mais la balise vectorielle dans son contexte concerne l'algèbre linéaire. Pas le conteneur.
Sidar
@Sidar N'hésitez pas à modifier les tags à l'avenir si vous pensez qu'ils ne correspondent pas. Si vous survolez les balises et que l'option "Modifier les balises" apparaît (au moins pour moi?), Vous pouvez modifier uniquement les balises sans modifier la question.
MichaelHouse
@ Byte56 J'ai cette étrange habitude de penser que je ne sais pas si j'ai raison donc je le fais passivement à travers un commentaire ... C'est pourquoi je n'ai pas édité le post. Peut-être que j'ai raté quelque chose dans le message, alors j'attendais sa réponse.
Sidar
Il y a aussi un bel article ici qui est apparu dans Game Developer il y a quelques années: cowboyprogramming.com/2007/01/04/programming-poker-ai
celion
1
J'ai fait une implémentation en java pour le plaisir il y a quelque temps, vous pouvez la trouver ici: codereview.stackexchange.com/questions/10973/… . Si vous regardez dans PokerHand.java, vous trouverez des méthodes pour tester chaque type de main (par exemple isFullHouse). Ils ne fonctionnent que si les cartes sont triées en premier.
bughi

Réponses:

20

Je pense que vous pouvez trouver la majorité des mains de poker en faisant simplement quelques tableaux du nombre de cartes dans la main de chaque rang et couleur.

En d'autres termes, créez un tableau de mappage des rangs de cartes (nombres et A / J / Q / K) au nombre de cartes de ce rang dans votre main. Si le joueur a une paire ou une paire, il y aura un élément dans ce tableau égal à 2 ou 3, etc. Ils ont une maison pleine s'il y a un élément qui est 2 et un autre qui est 3, et une ligne droite s'il y a cinq éléments consécutifs égaux à 1 dans ce tableau.

De même, vous pouvez créer un tableau similaire du nombre de cartes de chaque couleur et l'utiliser pour détecter les couleurs.

Une fois que vous avez détecté la présence d'une main spécifique, il est assez facile de revenir en arrière et de trouver les cartes spécifiques dans la main, pour les mettre en surbrillance dans l'interface utilisateur ou tout ce que vous devez faire.

En 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
la source
17

C'est un peu délicat car il y a tellement de combinaisons. Heureusement, vous avez un processeur qui peut vérifier un grand nombre de combinaisons en très peu de temps.

Vous aurez besoin de quelques stratégies différentes pour détecter différents types de mains. Heureusement, quelques-uns des différents types peuvent chevaucher les stratégies. Je cherchais à travers, par ordre de rang de la main.

  1. Quinte flush
  2. Quatre d'une sorte
  3. Full house
  4. Affleurer
  5. Tout droit
  6. Un brelan
  7. Deux paires
  8. Une paire
  9. Carte haute

2, 3, 6, 7,8 Sont tout simple comptage. En utilisant une liste de cartes Ace to King, placez simplement le numéro de chaque valeur dans la liste, en incrémentant pour chaque carte supplémentaire trouvée. Ensuite, vérifiez la liste des 4, s'il n'y a pas de 4, vous n'avez pas de 4 du genre. Vérifiez-le pendant 3, s'il n'y a pas de 3, vous n'en avez pas 3. Si vous avez un 3, recherchez un 2 (indiquant la maison pleine). Etc...

Pour 1, 5vous pouvez utiliser la même liste et rechercher des séquences où toutes les cartes ont une ou plusieurs entrées dans la liste pour une séquence de 5 cartes. S'ils ont également le même costume, c'est une quinte flush.

4peut avoir la même configuration de liste mais cette fois vous comptez le costume. Recherchez des nombres de 5 ou plus.

Enfin, 9vous avez la carte la plus élevée, ce qui devrait être une simple question de regarder la dernière valeur la plus élevée de l'une de vos listes ci-dessus.

Vous pouvez éclater une fois que vous avez trouvé une correspondance si vous recherchez dans l'ordre. Bien qu'il soit trivial de continuer la recherche et de trouver toutes les correspondances si vous souhaitez fournir toutes ces informations à l'utilisateur.


Essentiellement, vous remplissez des seaux. Ensuite, vérifiez les seaux pour les combinaisons. Pour illustrer:

entrez la description de l'image ici

En commençant par un tableau, avec un seau pour chaque carte, parcourez les cartes et comptez l'instance de chaque carte. Ensuite, vous pouvez facilement parcourir le tableau et vérifier certaines combinaisons. Dans cet exemple, il est clair qu'il y a un 4 d'une sorte car l'un des compartiments contient 4 éléments.

MichaelHouse
la source
6

Je suis tombé sur cet algorithme une fois. Il multiplie les nombres premiers pour déterminer les mains et est une lecture très intéressante. Évaluateur de main de poker de Cactus Kev

petervaz
la source
1
Celui-ci est intéressant, mais je ne suis pas sûr que vous ayez tout lu. Cet algorithme est pour 5 cartes . Vous l'avez peut-être trouvé dans une recherche Google relative à 7 cartes, car l'auteur déclare qu'ils ont un algorithme pour 7 cartes, mais ne le partagent pas. Voir le texte gris en haut de la page. Je ne suis donc pas sûr de l'utilité de cet algorithme pour un jeu de 7 cartes.
MichaelHouse
1
Puisqu'il n'y a que 21 mains de 5 cartes différentes qui peuvent être faites à partir d'une main de 7 cartes, une option consiste à utiliser un évaluateur de 5 cartes sur chacune d'elles et à choisir la meilleure.
Adam
@ Byte56 Vous avez raison, je me souviens l'avoir utilisé pour 7 cartes mais j'ai dû déterminer les 5 meilleures cartes à l'avance, ce qui a en quelque sorte miné l'efficacité.
petervaz
Le lien sur cette réponse a pourri et le domaine a été récupéré par un spammeur. J'ai redirigé le lien vers une archive de la page d'origine, mais pour rendre cette réponse plus robuste, il serait idéal de modifier la réponse pour inclure un résumé de l'algorithme proposé dans le corps de la réponse elle-même.
DMGregory
2

Pour compléter les excellentes réponses que cette question a déjà obtenues, j'ai pensé qu'il serait utile d'offrir l'une des façons les plus simples de comparer les mains une fois la technique de classification de base en place. Tout d'abord, vous voudrez marquer les mains avec leur classe , comme de nombreuses réponses l'ont suggéré - la plupart de vos comparaisons de «la main X est-elle meilleure que la main Y? peut alors être fait simplement en comparant les classes des deux mains et en voyant quelle classe est meilleure. Pour le reste, vous aurez besoin de comparer carte par carte, et il s'avère qu'un peu plus de travail de classification facilitera les choses.

En tant que cas de référence, considérons la situation où les deux mains sont des mains «high card»; dans ce cas, vous devez d'abord comparer les deux cartes les plus élevées, puis (si elles correspondent) les deux cartes suivantes, etc. Si vous supposez que chaque main en entrée est triée de la carte la plus élevée à la carte la plus basse, cette approche conduit à un code qui ressemble à cette:

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

Maintenant, la bonne nouvelle: il s'avère que cet ordre lexicographique , convenablement modifié, fonctionne pour comparer deux mains dans n'importe queldes classes, tant que leur classe est la même. Par exemple, puisque la façon de comparer les paires est de comparer les paires d'abord, puis les trois autres cartes, vous pouvez trier votre main pour placer la paire en premier (ou même une carte de la paire en premier!) Et exécuter cette même comparaison. (Ainsi, par exemple, une main comme A9772 serait stockée sous la forme 77A92 ou, mieux encore, 7A927; la main A9972 serait stockée sous la forme 9A729, et en comparant avec le code ci-dessus, vous commenceriez par opposer 7 à 9 et constater que A9972 a gagné). Une main de deux paires serait stockée avec la plus élevée des deux paires en premier, puis la plus basse, puis le «kicker» (ainsi, par exemple, A9977 serait stocké sous 97A97); trois d'une sorte seraient stockés avec une carte des trois premiers, puis les kickers, puis les autres cartes (par exemple, A7772 serait 7A277); une maison pleine serait stockée avec l'un de ses trois, puis l'un de ses deux (par exemple, 99777 serait stocké comme 79779); et les lignes droites et les couleurs peuvent toutes les deux être stockées dans un ordre `` lexicographique direct '' car elles sont toutes deux comparées, tout comme les mains à carte élevée. Cela conduit à une fonction de comparateur externe simple qui fonctionne pour toutes les classes de mains avec la fonction déjà donnée:

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

J'espère que cela vous sera utile!

Steven Stadnicki
la source
1

Il existe quelques parallélisations possibles en utilisant des représentations de cartes appropriées et un twiddling de bits. Par exemple, ce code Java évalue les disques durs de 7 cartes retournant un entier qui peut être utilisé pour comparer deux mains. Il pourrait être adapté pour rendre compte du type de main de manière plus conviviale. Les idées de base proviennent de la page de Cactus Kev référencée dans une réponse précédente.

Si vous êtes uniquement intéressé par les implémentations possibles pour nommer la main dans différents langages plutôt que par l'efficacité et la clarté du code, vous pouvez également consulter le défi Nommer la main de poker sur codegolf.SE.

Peter Taylor
la source
1

Tout d'abord, vous devez connaître le rang et la couleur de toutes les cartes; trivial mais nécessaire.

Faites ensuite défiler ces 7 cartes et créez deux histogrammes; un par rang (en utilisant un tableau avec 13 index, tous initialisés à zéro et incrémentés de 1 si et quand une carte dans la main avec ce rang est trouvée) et un par costume (en utilisant un tableau de quatre éléments construits de la même manière que pour le rang) . Ce sont des opérations linéaires et vous pouvez effectuer les deux opérations pour chaque carte pour un seul ensemble de traversées.

Vous pouvez ensuite déterminer si l'une des mains suivantes existe en examinant simplement chaque histogramme pour des compartiments correspondant aux critères et / ou un simple test de suivi:

  • Paire: Existe-t-il exactement un compartiment de rang ayant une valeur d'exactement 2, sans aucun autre compartiment ayant une valeur supérieure à 1 et sans vidage?
  • Deux paires: deux compartiments de rang ou plus ont-ils une valeur d'exactement 2, aucun compartiment n'en ayant plus de 2 et aucun rinçage? (évidemment trois paires ne sont pas une main, mais c'est une possibilité étant donné sept cartes; la paire la plus forte est la main du joueur)
  • TOAK: Exactement un seau a une valeur d'exactement 3, sans aucun autre seau ayant une valeur supérieure à 1 et sans rinçage?
  • Droit: cinq compartiments de rang consécutifs ont-ils une valeur de 1 ou plus sans vidage? (N'oubliez pas que les As sont à la fois hauts et bas; vous pouvez utiliser un histogramme de rang de 14 éléments et compter les As dans deux seaux si vous le souhaitez)
  • Flush: Est-ce que n'importe quel seau de costume a 5 cartes ou plus? (si oui, scannez la main pour trouver les cartes de cette couleur et choisissez le top 5)
  • Full House: un bucket de rang a-t-il une valeur de 3 et tout autre bucket a-t-il une valeur de 2 (avec 7 cartes, un flush est impossible avec un full house sauf si vous jouez avec un deck Pinochle)
  • Four of a Kind: Un rang a-t-il une valeur de 4? (aucune autre combinaison ne devrait être possible)
  • Quinte Flush: Y a-t-il à la fois une quinte et une couleur indiquées par les histogrammes? Si oui, y a-t-il au moins une carte dans la couleur indiquée avec un rang correspondant à chaque rang de la ligne droite indiquée? (c'est probablement le plus coûteux en calcul, mais il devrait être simple de compter le nombre de rangs consécutifs, et vous ne devriez avoir à scanner la main qu'une seule fois pour 5 rangs consécutifs, deux fois pour 6 et trois fois pour 7)

Vous pouvez, tout naturellement, combiner plusieurs de ces contrôles:

  • Y a-t-il une couleur?
  • Y a-t-il une ligne droite?
    • S'il y a les deux, est-ce un flush droit?
    • Si c'est une quinte flush, a-t-elle à la fois un As et un Roi?
  • Existe-t-il un modèle unique en son genre?
  • Combien y en a-t-il de trois? (Deux, c'est une maison pleine. Un, vérifiez les paires)
  • Combien de paires y a-t-il? (Avec deux ou plus, c'est deux paires. Avec une, s'il y a aussi trois c'est une maison pleine, sinon c'est une paire)
  • Aucune de ces réponses (carte haute).

Fondamentalement, si les réponses à celles-ci donnent une main, définissez la valeur de "force de la main" résultante sur la force de la main trouvée, si la valeur n'est pas déjà plus élevée. Par exemple, si vous avez une maison pleine, force 7 sur 9, alors vous avez également un trio de force 4 et une paire force 2.

Il y a quelques raccourcis et sorties rapides, mais dans l'ensemble, ce n'est pas vraiment si cher de simplement exécuter tous les contrôles.

KeithS
la source
0

Vous pouvez faire des mains de poker relativement facilement avec une approche itérative simple.

Pour chaque carte, vérifiez s'il y en a un ou deux ou trois autres avec le même visage pour vérifier la paire ou les trois / quatre d'une sorte.

Les maisons pleines sont similaires. Ou si vous trouvez à la fois une paire et trois d'une sorte qui ne sont pas le même visage, signalez une maison pleine comme trouvée.

Pour les couleurs, vérifiez chaque combinaison pour voir s'il y en a cinq de la même combinaison.

Vérifier directement est facile, même s'il n'est pas trié. Pour chaque carte, vérifiez s'il y en a une plus élevée et répétez jusqu'à ce que cinq cartes consécutives soient trouvées ou non.

Les bouffées royales et les bouffées droites peuvent être trouvées de manière similaire aux lignes droites. Les quinte flush royales ont des conditions supplémentaires en ce que les cartes de moindre valeur peuvent être ignorées.

Oui, cette approche est inefficace, mais pour la plupart des jeux de poker, cela n'est pas pertinent. Vous vérifiez une petite poignée de joueurs toutes les demi-minutes environ, sans vérifier des milliers de mains par seconde.

De meilleures méthodes existent mais peuvent prendre plus de temps à coder, et vous avez probablement des choses plus importantes à consacrer au temps / à l'argent qui rendront le jeu meilleur du point de vue des joueurs en plus de l'intelligence et de l'efficacité d'un algorithme.

Sean Middleditch
la source
0

un moyen simple de trouver des paires, des paires doubles, des toaks, des maisons pleines, des pokers, etc. est le suivant:

comparer chaque carte entre elles dans une boucle imbriquée comme celle-ci:

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

les matchs contiendront les éléments suivants:
2 pour une paire
4 pour deux paires
6 pour toak
8 pour un fullhouse
12 pour un poker

pour accélérer cela: il n'est pas nécessaire d'exécuter la boucle j jusqu'à 5, elle peut être exécutée sur i-1. la comparaison "i! = j" peut alors être supprimée, les valeurs de correspondance sont alors divisées par deux (1 = paire, 2 = 2 paires etc.)

Thomas Schüler
la source