Determinando las manos de póker

19

He estado haciendo un juego de Texas Hold'Em como parte de una evaluación, y he estado reflexionando sobre cómo examinar las 7 cartas disponibles y determinar si existen manos.

El único método posible que se me ocurre es ordenar las cartas numéricamente, luego examinar cada grupo posible de 5 cartas y verificar si coinciden con una lista de cada mano posible. Eso llevaría mucho tiempo y solo sería factible para determinar pares, ya que el palo es irrelevante.

Las cartas son cada una de las cadenas, formadas por un número / a / j / q / k, y un palo (char)3(que hace un pequeño símbolo de espadas).

¿Alguien tiene alguna sugerencia, fórmula o enlace que pueda usar para ayudar a crear un sistema de análisis manual?

No se preocupe por clasificar las manos entre sí todavía, eso es un caldero diferente de peces.

Magicaxis
fuente
1
Solo señalándolo, pero la etiqueta del vector en su contexto es sobre álgebra lineal. No el contenedor.
Sidar
@Sidar Siéntase libre de editar las etiquetas en el futuro si cree que no encajan. Si pasa el mouse sobre las etiquetas y aparece la opción "Editar etiquetas" (¿al menos para mí?), Y puede editar solo las etiquetas sin editar la pregunta.
MichaelHouse
@ Byte56 Tengo esta extraña costumbre de pensar que no estoy seguro de si estoy en lo cierto, así que lo hago pasivamente a través de un comentario ... Es por eso que no edité la publicación. Tal vez me perdí algo en la publicación, así que estaba esperando su respuesta.
Sidar
También hay un buen artículo aquí que apareció en Game Developer hace unos años: cowboyprogramming.com/2007/01/04/programming-poker-ai
celion
1
Hice una implementación en Java por diversión hace un tiempo, puedes encontrarla aquí: codereview.stackexchange.com/questions/10973/… . Si buscas en PokerHand.java encontrarás métodos para probar cada tipo de mano (por ejemplo, isFullHouse). Solo funcionan si las tarjetas se ordenan primero.
bughi

Respuestas:

20

Creo que puedes encontrar la mayoría de las manos de póker simplemente haciendo un par de tablas de cuántas cartas hay en la mano de cada rango y palo.

En otras palabras, crea una matriz de rangos de cartas de mapeo (números y A / J / Q / K) para contar las cartas de ese rango en tu mano. Si el jugador tiene un par o un trío, habrá un elemento en este conjunto igual a 2 o 3, etc. Tienen una casa llena si hay un elemento que es 2 y otro que es 3, y una escalera si hay cinco elementos consecutivos iguales a 1 en esta matriz.

Del mismo modo, puede hacer una matriz similar del recuento de cartas de cada palo, y usarlo para detectar rubores.

Una vez que haya detectado la presencia de una mano específica, es bastante fácil regresar y encontrar las tarjetas específicas en la mano, para resaltarlas en la interfaz de usuario o lo que sea que necesite hacer.

En pseudocódigo:

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
fuente
17

Es un poco complicado porque hay muchas combinaciones. Afortunadamente, tiene un procesador que puede verificar una gran cantidad de combinaciones en muy poco tiempo.

Necesitará algunas estrategias diferentes para detectar diferentes tipos de manos. Afortunadamente, algunos de los diferentes tipos pueden superponer estrategias. Buscaría en orden, por orden de rango de la mano.

  1. Escalera de color
  2. Cuatro de un tipo
  3. Casa llena
  4. Rubor
  5. Derecho
  6. Tres de un tipo
  7. Dos pares
  8. Un par
  9. Carta alta

2, 3, 6, 7, 8Son todos conteo simple. Usando una lista de cartas de As a Rey, simplemente coloque el número de cada valor en la lista, incrementando por cada carta adicional encontrada. Luego revise la lista de 4s, si no hay 4s, no tiene un 4 de su clase. Verifíquelo por 3s, si no hay 3s, no tiene un 3 de su clase. Si tienes un 3, busca un 2 (que indica la casa completa). Y así...

Para 1, 5puede usar la misma lista y buscar secuencias donde todas las tarjetas tienen una o más entradas en la lista para una secuencia de 5 tarjetas. Si también tienen el mismo palo, es una escalera de color.

4puede tener la misma configuración de lista pero esta vez estás contando el palo. Busque números de 5 o más.

Finalmente, 9tiene la carta más alta, que debería ser una simple cuestión de mirar el último valor más alto de una de sus listas anteriores.

Puede buscar una vez que haya encontrado una coincidencia si busca en orden. Aunque sería trivial continuar la búsqueda y encontrar todas las coincidencias si desea proporcionar toda esa información al usuario.


Esencialmente, estás llenando cubos. Luego verificando los cubos para las combinaciones. Para ilustrar:

ingrese la descripción de la imagen aquí

Comenzando con una matriz, con un cubo para cada tarjeta, recorra las tarjetas y cuente la instancia de cada tarjeta. Luego puede iterar fácilmente la matriz y verificar ciertas combinaciones. En este ejemplo, está claro que hay un 4 en su tipo porque uno de los cubos tiene 4 elementos.

MichaelHouse
fuente
6

Me topé con este algoritmo una vez. Multiplica los números primos para determinar las manos y es una lectura muy interesante. Evaluador de manos de póker de Cactus Kev

Petervaz
fuente
1
Ese es interesante, pero no estoy seguro de que lo haya leído todo. Ese algoritmo es para 5 cartas . Es posible que haya encontrado en una búsqueda de Google relacionada con 7 tarjetas, ya que el autor afirma que tienen un algoritmo para 7 tarjetas, pero no lo comparten. Vea el texto gris cerca de la parte superior de la página. Así que no estoy seguro de qué tan útil es ese algoritmo para un conjunto de 7 cartas.
MichaelHouse
1
Como solo se pueden hacer 21 manos de 5 cartas diferentes a partir de una mano de 7 cartas, una opción es usar un evaluador de 5 cartas en cada una y elegir la mejor.
Adam
@ Byte56 Tienes razón, recuerdo que lo usé para 7 cartas pero tuve que determinar las mejores 5 cartas de antemano, lo que minó un poco la eficiencia.
petervaz
El enlace en esta respuesta se ha podrido desde entonces, y el dominio fue recogido por un spammer. Redirigí el enlace a un archivo de la página original, pero para que esta respuesta sea más sólida, sería ideal editar la respuesta para incluir un resumen del algoritmo que se propone dentro del cuerpo de la respuesta.
DMGregory
2

Para complementar las excelentes respuestas que esta pregunta ya ha recibido, pensé que sería útil ofrecer una de las formas más directas de comparar las manos una vez que la técnica de clasificación básica esté en su lugar. En primer lugar, querrá etiquetar las manos con su clase , como lo han sugerido numerosas respuestas: la mayoría de sus comparaciones de '¿es la mano X mejor que la mano Y?' entonces puede hacerse simplemente comparando las clases de las dos manos y viendo qué clase es mejor. Por lo demás, en realidad tendrá que comparar tarjeta por tarjeta, y resulta que un poco más de trabajo en la clasificación lo hará más fácil.

Como caso de referencia, considere la situación en la que ambas manos son manos de 'cartas altas'; en este caso, primero compararía las dos cartas más altas, luego (si coincidían) las siguientes dos cartas, etc. Si asume que cada mano de entrada está ordenada de la carta más alta a la más baja, este enfoque lleva a un código similar esta:

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

Ahora, la buena noticia: resulta que este ordenamiento lexicográfico , ajustado adecuadamente, funciona para comparar dos manos en cualquierde las clases, siempre que su clase sea la misma. Por ejemplo, dado que la forma de comparar pares es comparar primero los pares, luego las otras tres cartas, puede ordenar su mano para poner el par primero (¡o incluso una carta del par primero!) Y ejecutar esta misma comparación. (Entonces, por ejemplo, una mano como A9772 se almacenaría como 77A92 o, mejor aún, 7A927; la mano A9972 se almacenaría como 9A729, y en comparación con el código anterior, comenzaría enfrentando 7 contra 9 y encontrará que A9972 ganó). Una mano de dos pares se almacenaría con el más alto de los dos pares primero, luego el más bajo, luego el 'pateador' (entonces, por ejemplo, A9977 se almacenaría como 97A97); tres de un tipo se almacenarían con una tarjeta de las tres primero, luego los pateadores, luego las otras tarjetas (por ejemplo, A7772 sería 7A277); una casa completa se almacenaría con uno de sus tres y luego uno de sus dos (por ejemplo, 99777 se almacenaría como 79779); y las rectas y los colores pueden almacenarse en orden 'lexicográfico directo' ya que ambos se comparan al igual que las manos de cartas altas. Esto lleva a una función de comparación externa directa que funciona para todas las clases de manos con la función ya dada:

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

¡Espero que esto sea de alguna ayuda!

Steven Stadnicki
fuente
1

Hay algunas paralelizaciones posibles utilizando representaciones de tarjetas adecuadas y juegos de bits. Por ejemplo, este código Java evalúa las dificultades de 7 cartas que devuelven un número entero que se puede usar para comparar dos manos. Se podría adaptar para informar el tipo de la mano de una manera más fácil de usar. Las ideas centrales provienen de la página de Cactus Kev referenciada en una respuesta anterior.

Si solo está interesado en posibles implementaciones para nombrar la mano en varios idiomas en lugar de la eficiencia y la claridad del código, también puede ver el desafío Nombre de la mano de póker en codegolf.SE.

Peter Taylor
fuente
1

Primero, necesitas saber el rango y el palo de todas las cartas; trivial pero necesario.

Luego, gire a través de estas 7 cartas y cree dos histogramas; uno por rango (usando una matriz con 13 índices, todos inicializados a cero e incrementados en 1 si se encuentra una carta en la mano con ese rango) y uno por palo (usando una matriz de cuatro elementos construidos de manera similar al rango) . Estas son operaciones lineales y puede realizar ambas operaciones para cada tarjeta para un solo conjunto de recorridos.

Luego puede determinar si existe alguna de las siguientes manos simplemente examinando cada histograma en busca de cubos que coincidan con los criterios, y / o una simple prueba de seguimiento:

  • Par: ¿Tiene exactamente un cubo de rango un valor exactamente de 2, sin que otro cubo tenga un valor superior a 1 y sin color?
  • Dos pares: ¿Dos o más cubos de rango tienen un valor exactamente de 2, sin un cubo que tenga más de 2 y sin color? (obviamente tres pares no son una mano, pero es una posibilidad si se dan siete cartas; los dos pares más fuertes son las manos del jugador)
  • TOAK: ¿Tiene exactamente un cubo un valor exactamente de 3, sin que otro cubo tenga un valor mayor que 1 y sin vaciado?
  • Recto: ¿Cinco cubos de rango consecutivos tienen un valor de 1 o más sin color? (No olvide que los Ases son altos y bajos; podría usar un histograma de rango de 14 elementos y contar Ases en dos cubos si lo desea)
  • Rubor: ¿algún cubo de palo tiene 5 o más cartas? (si es así, escanea la mano en busca de cartas de ese palo y elige los 5 mejores)
  • Full House: ¿Alguno rango de rango tiene un valor de 3 y cualquier otro cubo tiene un valor de 2 (con 7 cartas, un color es imposible con un full house a menos que estés jugando con un mazo de Pinochle)
  • Four of a Kind: ¿Algún rango tiene un valor de 4? (ninguna otra combinación debería ser posible)
  • Escalera de color : ¿Hay tanto una escalera como una línea de color indicadas por los histogramas? Si es así, ¿hay al menos una carta en el palo de color indicado con un rango que coincida con cada rango de la escalera indicada? (este es probablemente el más costoso desde el punto de vista computacional, pero debería ser simple contar cuántos rangos consecutivos hay, y solo debería tener que escanear la mano una vez por 5 rangos consecutivos, dos veces por 6 y tres veces por 7)

Puede, naturalmente, combinar varios de estos controles:

  • ¿Hay un rubor?
  • ¿Hay una escalera?
    • Si hay ambos, ¿es una escalera de color?
    • Si es una escalera de color, ¿tiene tanto un As como un Rey?
  • ¿Hay un cuatro en su tipo?
  • ¿Cuántos tres tipos hay? (Dos, es una casa llena. Uno, verifica pares)
  • ¿Cuántos pares hay? (Con dos o más, son dos pares. Con uno, si también hay un tres es una casa llena, de lo contrario es un par)
  • Ninguna de las anteriores (carta alta).

Básicamente, si las respuestas a estas dan alguna mano, establezca el valor resultante de "fuerza de la mano" a la fuerza de la mano encontrada, si el valor no es ya mayor. Por ejemplo, si tienes una casa llena, fuerza 7 de 9, entonces también tienes un trío, fuerza 4 y un par, fuerza 2.

Hay algunos atajos y salidas rápidas, pero en general no es realmente tan costoso simplemente ejecutar todos los controles.

KeithS
fuente
0

Puedes hacer manos de póker con relativa facilidad con un enfoque iterativo simple.

Para cada tarjeta, verifique si hay una o dos o tres más con la misma cara para verificar un par o tres / cuatro de un tipo.

Las casas completas son similares. O si encuentra un par y tres de un tipo que no son la misma cara, marque una casa llena como se encuentra.

Para ver si hay color, revisa cada palo para ver si hay cinco del mismo palo.

Verificar en línea recta es fácil, incluso si no está ordenado. Para cada tarjeta, verifique si hay una más alta y repita hasta encontrar cinco tarjetas consecutivas o no.

Los rubores reales y los rubios rectos se pueden encontrar de manera similar a los rectos. Los colores reales tienen algunas condiciones adicionales en que las cartas de menor valor pueden ser ignoradas.

Sí, este enfoque es ineficiente, pero para la mayoría de los juegos de póker, eso es irrelevante. Estás revisando un pequeño puñado de jugadores cada medio minuto más o menos, no controlando miles de manos por segundo.

Existen mejores métodos, pero puede llevar más tiempo codificar, y es probable que tenga cosas más importantes en las que gastar tiempo / dinero para mejorar el juego desde la perspectiva de los jugadores, además de la inteligencia y la eficiencia de un algoritmo.

Sean Middleditch
fuente
0

Una manera simple de encontrar pares, pares dobles, toques, casas completas, póquer, etc. es la siguiente:

compare cada tarjeta entre sí en un bucle anidado como este:

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

los partidos tendrán lo siguiente:
2 para un par
4 para dos pares
6 para toak
8 para un fullhouse
12 para un póker

para optimizar esto: no es necesario ejecutar el j-loop hasta 5, se puede ejecutar en i-1. la comparación "i! = j" se puede eliminar, los valores de coincidencia se reducen a la mitad (1 = par, 2 = 2 pares, etc.)

Thomas Schüler
fuente