¿Cómo calculo las probabilidades de las manos de póquer?

Este es un tutorial para calcular las probabilidades de póquer desde cero. Es lo que aprendí en mi carrera e incluso antes cuando creé una calculadora de fuerza de mano de sorteo de 5 cartas.

La intención de esta publicación es crear una comunidad más limpia sin preguntas similares que saturen nuestro sitio de preguntas y respuestas, con más personas que comprendan la importancia de las probabilidades y las aprovechen mejor.

Para los programadores, que espero que sean la mayoría de las personas aquí, ya que calculo que la mayoría de las personas aquí visitan primero StackOverflow, este artículo podría ser una pista para crear herramientas de cálculo, sitios web e incluso su propio servidor de póquer con muchas estadísticas. análisis.

Me tomó mucho tiempo escribir este borrador y espero que puedas colaborar si encuentras algún error que pude haber cometido en mis ejemplos.

Podríamos hacer publicaciones como esta para evitar preguntas similares, e incluso enfocarnos como comunidad en temas más amplios.

La metodología comentada aquí sirve no solo para el póquer sino para cualquier juego de cartas con baraja francesa, e incluso con baraja española (cambiando N=12 en lugar de 13), si se hace la pregunta correcta. Esto es como la Sala de los Requisitos de Harry Potter: "si tienes que preguntar, nunca sabrás. Si sabes, solo tienes que preguntar", y la intención de esta pregunta es ponerte en la segunda parte de la oración.

¿Cómo puedo calcular las probabilidades de encontrarme con una determinada mano de póquer o situación que me interese?

¿Debería estar todo el texto en cursiva realmente en la pregunta? Me parece un prefacio a la respuesta.

Respuestas (2)

¡Bienvenido al mundo de las probabilidades!

1. Preguntas, Respuestas, Frecuencias

El cálculo de probabilidades se trata de una pregunta que requiere una respuesta. Se trata de una pregunta que implica:

  • Un estado inicial. Esta es la configuración del mundo que quieres analizar. Este mundo es solo una visión estrecha de lo que quieres analizar. Al analizar las manos de póquer y los enfrentamientos, el mundo que analizas es el mazo barajado.
  • Una condición o predicado que esperas que sea verdadero sobre la configuración actual de dicho mundo.

Por lo general, cuando analizas una proposición lógica, sabes si es VERDADERA o FALSA. Pero en el caso de las probabilidades , estás analizando múltiples instancias de tal proposición . Como ejemplo, puede hacer una proposición verdadero/falso como esta:

¿Esta configuración mundial me trae un 4 de una clase? AA KAAQJ >> Verdadero
¿Esta configuración mundial me trae un 4 de una clase? AK KAAQK >> Falso

Puede notar los siguientes rasgos de la pregunta:

  • El mundo del análisis era solo tu mano y las cartas comunitarias.
  • El estado inicial es cómo se reparte el mazo, después de barajar, para formar tu mano y las cartas comunitarias.
  • La condición era sacar 4 iguales entre las siete cartas.
  • La respuesta era verdadera o falsa, dados todos los datos conocidos.

PERO nuevamente, en probabilidades, analizas no solo una sola proposición sino una proposición amplia que cubre todo el estado inicial posible. Hay dos tipos de dominios para esto:

  • Dominios discretos es cuando la cantidad de estados iniciales es enumerable . Esto significa que, para cualquier estado inicial dado, puede saber cuál sería el siguiente estado inicial que haría, si intentara las preguntas una por una.
  • Dominios continuos es cuando la cantidad de estados iniciales no es enumerable . La mayoría de las veces esto significa involucrar números reales, integrales y un área de gráfico para analizar.

En una pregunta de análisis de manos, la versión final ( reducida , en términos de complejidad computacional) del estado inicial es siempre cómo se barajó la baraja para esta mano , y se pueden contar las barajadas: puede establecer el criterio para contar las barajadas. ¡No tienes que creerme! Puedes probar por ti mismo este código de Python si tienes acceso a un intérprete:

import itertools
deck = range(52) # Each card will be encoded in a number between 0 and 51
for shuffling in itertools.permutations(deck, 52)

Este código se ejecutará sobre todas las mezclas posibles del mazo, por lo que las mezclas son enumerables (¡Este código tomará mucho! Presione Ctrl+C para detenerlo o... espere millones de años para completarse).

Conclusión: El análisis de la mano de póquer pertenece al dominio de las probabilidades discretas .

En los dominios discretos, enumera los casos y los aplica a la condición. Obtendrás algo como esto:

  • Todos los posibles estados iniciales (nuevamente: en última instancia, esto significa todas las posibles barajadas ).
  • Todos los casos esperados (es decir, el subconjunto de todos los casos posibles que pasaron la condición esperada).
  • Ratio : Este es el valor que desea . Será un valor entre 0 y 1 (¡ambos límites pueden ocurrir! 0 significa que nunca sucede y 1 significa que siempre sucede ). Por lo general, verá este valor expresado en un formato de porcentaje (0% a 100%).

Sin embargo, recuerde: no prueba cada caso uno por uno . Aplica fórmulas específicas para probar todo el caso a la vez .

Entonces, como puede ver, la respuesta será una medida de casos a considerar, entre todos los casos posibles , en un formato de frecuencia (dado por el valor devuelto 0..1), calculado por fórmulas dadas que veremos a continuación.

2. Mezclas, Permutaciones, Combinaciones

Ahora te contamos las fórmulas, la razón de ser, y cómo y cuándo las aplicas.

Tenga en cuenta: ya no usaremos las funciones de python indicadas, ya que esas funciones atraviesan todos los casos posibles, y solo nos interesa contarlos, no atravesarlos .

baraja

  • Cuándo usarlo: el último caso de análisis es cuando tienes el mazo completamente barajado. En juegos como 7 card stud con 8 jugadores jugando hasta la última carta, o 5 card draw con todos los jugadores cambiando sus manos, notarás que el barajado inicial del mazo es importante.

El cálculo de posibles mezclas distintas sobre un conjunto se realiza mediante factorial . Factorial es una función recursiva para enteros no negativos que finalmente calcula el producto de una secuencia de N enteros consecutivos. Ejemplos:

5! = 5*4*3*2*1 = 120.

Un caso excepcional es 0! = 1. Los factoriales no están definidos en números negativos.

Esto tiene una relación directa con la cantidad de mezclas posibles, porque:

  • N!se calcula como N * (N - 1)!, donde -nuevamente- 0! = 1por definición.
  • La cantidad de barajas posibles de una baraja de N elementos es N cartas posibles en la parte superior de la baraja, multiplicada por la cantidad de barajas posibles de una baraja restante de (N - 1) elementos, donde tener una baraja de 0 cartas solo tiene una baraja posible: todavía la baraja vacía.
  • N = 52 en juegos de póquer (excepto para modos de póquer con comodines, como el póker caribeño, con un valor de N = 53).

permutaciones

Calcular posibles permutaciones distintas implica barajar un mazo y tomar un cierto número R de cartas de él. Tu mazo de N cartas se barajará así:

D1 D2 D3 D4 ... DN

Y estás tomando cartas R y dejando cartas NR en la baraja:

D1 D2 ... DR tomado, D(R+1) ... DN restante

Notarás que la función de Python que copié ya tiene el nombre permutations. Esto se debe a que una mezcla completa es un caso especial de una permutación, cuando analizamos todos los elementos que se mezclan .

Las cartas NR permanecen en el mazo. A priori este cálculo es el más útil ya que las cartas R tomadas son las que interactúan creando una mano de póquer que involucra a los jugadores. Es cierto que dije que el último caso de análisis es toda la baraja barajada, pero también es cierto que no te importan más de 25 cartas en una mesa de hold'em con 10 jugadores llegando al river. Entonces, para juegos como este, solo te importa un subconjunto de las cartas barajadas, por lo que el valor R (cantidad de cartas tomadas) es menor que el valor N (cantidad de cartas en el mazo) (¡nunca puede ser mayor!) .

Tome este ejemplo: solo 4 cartas (A, B, C, D son solo los cuatro ases) barajadas:

(para este ejemplo, puede ejecutar la función python para generar las muestras: permutar la cadena 'ABCD' por 4 elementos para obtener la siguiente lista)

ABCD ABDC ACBD ACDB ADBC ​​ADCB BACD BADC BCAD BCDA BDAC BDCA CABD CADB CBAD CBDA CDAB CDBA DABC DACB DBAC DBCA DCAB DCBA

Había 24 posibles barajes. Ahora suponga que quiero saber solo los casos posibles para las dos primeras cartas de ese barajado (itere sobre cada elemento y simplemente calcule element[:2]en cada uno, usando una lista de comprensión):

AB AB AC AC AD AD BA BA BC BC BD BD CA CA CB CB CD CD DA DA DB DB DC DC

Todos ellos se repiten, dos veces en este caso. Los casos reales que me importan son mis dos tarjetas que son así:

AB AC AD BA BC BD CA CB CD DA DB DC

Aquí es cuando aplicas permutaciones. Obtiene muchos menos casos para tener en cuenta. Si lo nota, la cantidad de duplicados para cada caso es, en realidad, la cantidad de barajas posibles de las cartas que se ignoran , que en realidad es la barajada de (NR) cartas restantes, o (N-R)!. Tenga en cuenta que aquí se pueden ignorar los duplicados porque el número de duplicados o copias siempre es el mismo para cada caso posible , por lo que preguntar a AB significaría que ambos preguntan:

casos esperados AB AB en AB AB AC AC AD AD BA BA BC BC BD BD CA CA CB CB CD CD DA DA DB DB DC DC

o

caso esperado AB en AB AC AD BA BC BD CA CB CD DA DB DC

(2/24 es lo mismo que 1/12 simplificando o reduciendo la fracción)

La fracción tiene el mismo valor, por lo que puede especializar las mezclas en permutaciones para ignorar el paso intermedio de simplificar ambos lados en su mente.

Sin embargo, en los detalles de implementación, la fórmula:

NpN = N!

se convierte en:

NpR = N!/(N-R)!

Dado que en dicha fórmula, debe tener en cuenta que son cálculos diferentes. En la práctica, el cálculo se convierte en:

NpR = N*(N-1)*...*(N-R+1)

siendo siempre R <= N.

Es importante considerar esto:

  • Esta operación es la base de la mayoría de los cálculos de probabilidades de póquer, excepto en los casos que mencioné.
  • Llegamos a esta operación dividiendo en barajes que no nos importaban. Lo que implica:
    • Cuando estudia casos de posibles casos de conjuntos distintos de tamaño R y sucede que desea considerar barajar los elementos R, debe multiplicar la cantidad de casos por R!.
    • Cuando estudia casos de posibles casos de secuencias distintas de tamaño R y de repente ya no le importa la mezcla en los elementos R, tiene que colapsar todas las mezclas posibles en un caso, lo que implica dividir por R!.
    • Esto significa: Una secuencia es un caso conjunto barajado. Un caso conjunto es el conjunto de elementos de una sucesión, sin tener en cuenta el orden. Preguntar por una secuencia en el dominio de los casos establecidos implica convertir los casos establecidos en secuencias, multiplicando la cantidad de casos por R!(la cantidad de mezclas posibles de un caso establecido).

Lo que conduce al cálculo de...

combinaciones

Ya mostramos por qué dividimos por el factorial de (NR) : para ignorar posibles barajes de las cartas restantes.

Una combinación es esencialmente una permutación para la cual ignoramos su barajado. Un ejemplo de esto es cuando preguntamos sobre nuestras cartas de mano: no nos importa en qué orden recibimos o cartas de mano, sino cuáles son las cartas. Supongamos que quiero contar los casos de tener una escalera real de picas en un sorteo de 5 cartas (sí, la mano final de Maverick):

AKQJT espadas

Solo me importa una combinación de cartas, pero hay 120 ( 5!) permutaciones posibles. Como no me importan las posibles permutaciones, mis casos esperados se reducen a un solo caso.

En Hold'Em, esto solo significa dividir por 2. En 7-stud, esto significa dividir por 6 ( 3!) para las cartas iniciales.

Los cálculos para las combinaciones se convierten en:

NcP = NpR/R!

O ...

NcR = N!/(N-R)!/R!

O ...

NcR = N!/((N-R)!*R!)

En la práctica, la implementación es la misma que NpR pero dividiendo el valor resultante por 1*...*R.

Las implementaciones de Python podrían ser así:

shufflings = lambda n: reduce(operator.mul, range(1, n+1))
permutations = lambda n, r: reduce(operator.mul, range(n-r+1, n+1))
combinations = lambda n, r: permutations(n, r) / shufflings(r)

Si es programador, puede instalar un intérprete de python (la distribución de Linux tiene uno por defecto en la mayoría de los casos) y probar estas funciones con ipython, contando los elementos generados por itertools.combinationsy itertools.permutations. Si no eres programador, este sitio te ayuda a calcular permutaciones y combinaciones . Nuevamente: para calcular las barajas completas, calcule una permutación con R = N = 52.

Ejemplos de uso

  • ¿Cantidad de barajas de baraja estándar posibles? 52!(barajas).
  • ¿Cantidad de posibles combinaciones de palos para cualquier pareja? 4c2(4 palos, tomando dos).
  • ¿Cantidad de posibles manos de 4 iguales? Este es complicado. Involucra todos los casos posibles para las 4 cartas iguales, no importa el orden, y todas las cartas restantes posibles (quedan 48) para cada caso posible de 4 cartas iguales. 13 (possible combinations of 4oak) * 48 (remaining cards).
  • ¿Cantidad de posibles valores de 4 del mismo tipo (es decir, el palo no importa para el pateador)? Este es como una permutación entre los 13 valores posibles: qué valor corresponde al 4 del mismo tipo y cuál corresponde al pateador: 13p12(permutaciones).

3. ¡Se trata de hacer la pregunta correcta!

Te dije que el cálculo de probabilidades se trata de hacer la pregunta correcta, asumir las condiciones correctas y cómo esas condiciones pueden transformarse en diferentes dominios (barajas completas <-> permutaciones por un factor de (N-R)!y permutaciones <-> combinaciones por un factor de R!) .

¿Recuerdas que las probabilidades son la expected / wholerazón en el caso discreto (y expected area / whole areaen el continuo)? Es hora de poner esto en práctica .

La mejor forma de ponerlo en práctica es con el ejemplo. ¡Así que practiquemos!

¿Cuál es la probabilidad de obtener AA en mis cartas ocultas en Texas Hold'Em?

¡El valor real de la tarjeta que pido es irrelevante aquí! Preguntar por AA o KK o 22 traerá el mismo valor

  • Casos completos: como solo me importan mis cartas ocultas, tomo dos cartas de toda la baraja. No importa si soy el primero o el último jugador en recibir cartas. Mientras no tenga más información del estado inicial, sigo tomando dos cartas de 52. Además, no me importa en qué orden recibo esas cartas, por lo que no es una permutación sino una combinación de dos cartas Todos los casos que quiero estudiar son 52c2 = 1326casos posibles.
  • Casos esperados: espero dos ases. Entre las posibles combinaciones de cartas, hay ciertas combinaciones que serán AA. ¿Cuántas combinaciones? Veamos... 4 palos posibles (S, D, H, C) traen 4 ases posibles, y necesito una combinación de dos ases de los cuatro ases posibles. Mis casos esperados son ases de SD SH SC DH DC HC (¡combinaciones!, así que el orden no importa: HC y CH es lo mismo, entonces usamos combinaciones). La fórmula a aplicar aquí es la combinatoria con 4 tomando dos: 4c2 = 6.
  • Probabilidad de obtener: expected / whole= 6 / 1326= 1 / 221, o uno en 221 sorteos .

¿Cuál es la probabilidad de obtener un par (¡y no una mejor mano!) en el flop?

La configuración mundial que quiero, en este caso, debe dividirse en tres casos:

  • Par de agujeros: 6 * 13 (6 es el caso esperado, pero debemos multiplicar sobre los posibles valores de las cartas. La configuración mundial esperada responde al patrón XX ??? (tanto el XX como el ??? son separados y combinatorios, ya que se reparten en momentos separados pero juntos, y no importa en qué orden se tiraron las cartas del flop).
  • Par flop: La configuración mundial esperada responde al patrón ?? XX? (de nuevo: tanto el XX como el ??? pertenecen a espacios separados y combinatorios).
  • Par conectado: ¿La configuración mundial esperada responde al patrón X? ¿¿X?? (de nuevo: tanto el XX como el ??? pertenecen a espacios separados y combinatorios).

Si puede notar, los espacios que se analizan son los mismos cada vez: 2 cartas combinadas de 52 y 3 cartas combinadas de 50 ( si combina al revés, como diciendo 3 de 52 y 2 de 49, el resultado será lo mismo ). Dado que utilizan el mismo espacio, no es necesario convertirlos en espacios más amplios (en este caso, el espacio más amplio que no implica más cartas es 52p5).

El importe total de las condiciones iniciales es: 52c2 * 50c3 = 25989600casos.

Tenga en cuenta: para esta pregunta, que se restringe solo a pares, las cartas en ? no puede tener el mismo valor que X, y también deben ser valores distintos entre sí

¡Entonces necesitamos calcular los casos esperados para cada espacio!

  • Cartas de mano: 13 (different example values for a pair) * 4c2 (two suits out of 4) * 64 (three different suits which can be the same for the flop cards) * 12c3 (three different values for flop cards) = 1098240casos.
  • Tarjetas conectadas: 13 (different example values for a pair) * 4 (one suit out of 4 for the first hole card) * 12 (the value for the second hole card, which will be different) * 4 (one suit out of 4 for the second hole card) * 1 (the same example matching value) * 3 (one suit out of 3 for the flop card matching the hole card) * 4 * 4 (two arbitrary suits for the remaining flop cards) * 11c2 (any combination of two remaining values) = 6589440estuches.
  • Cartas del flop: 4 * 4 (two arbitrary suits in your hand, which could be the same) * 13c2 (a combination of two distinct values) * 4c2 (two suits out of 4 for the paired cards)* 11 (diferentes valores de ejemplo para un par) * 4 (palo para la carta distinta restante) 10 (valores posibles para la carta del flop restante) = 10982400 ` casos.
  • ¡Suma los tres escenarios!:1098240 (hand) + 6589440 (connected) + 3294720 (flop) = 10982400 cases
  • Recuerde la cantidad de casos enteros: 25989600.
  • Proporción: como 0.42o 42%.
  • Agregue los dos escenarios si no quiero el par en la mesa: 1098240 + 6589440 / 25989600 = like 0.29o 29%.

Haciendo un análisis constructivo .

Para el ejemplo de la segunda pregunta (exactamente un par, no hay mejor mano), tiene que hacer tres análisis diferentes:

  • XX??? requieren que el ??? utiliza tres valores diferentes. Considere que robamos un valor para X de los 13 valores disponibles (2..A), y tenemos 12 valores restantes para ? tarjetas Puedo hacer seis (4c2) combinaciones de palos para mis cartas XX, lo que funcionaría, entre 1326 (52c2) combinaciones en mi mano. Dicho esto, sé de antemano que el espacio que quiero considerar para mi mano es combinatorio (de nuevo: el orden en mi mano no importa). Las cartas del flop tienen un valor distinto y pueden tener palos iguales o distintos. No importa el orden entre ellos, por lo que el propio flop también es combinatorio: calculamos 12c3 para la combinación de valores y 4*4*4 para la combinación de palos. Dado que el espacio del flop es combinatorio, calculamos 50c3 para las cartas restantes.
  • ¿X? ¿¿X?? es un poco diferente Puede elegir cualquier valor para la X (de 13, nuevamente). Congele ese valor por un momento. Tendrás 4 palos posibles para ese valor y 48 cartas posibles para la otra carta, entre 52c2 combinaciones posibles. En el flop tendrás 3 palos independientes (que dan 64 combinaciones de palos), con solo una combinación de 2 de los 11 posibles valores restantes. Una vez más, el espacio del flop es combinacional: el orden de las cartas que se reparten no importa. Ahora multiplique por 13 para tener en cuenta los posibles valores de los pares, y estará del otro lado :).
  • ?? XX? es bastante diferente: combinará dos valores diferentes en su mano (13c2), con cualquier emparejamiento independiente arbitrario para los palos (16). El flop tendrá combinaciones de 4c2 palos para las cartas XX y 4 palos posibles para la carta restante, que puede elegir solo entre 11 valores (dos de ellos ya fueron elegidos).

Trivia Si eres inteligente con los números, puedes notar el siguiente patrón:

  • 1098240 corresponde al escenario XX ???.
  • 6589440 es 6 veces 1098240 y cubre X? X??, X? ?X?, X? Escenarios ??X, ?XX??, ?X ?X? y ?X ??X (total: 6) para el par conectado.
  • 3294720 es 3 veces 1098240 y cubre ?? XX?, ?? X?X, y ?? ?XX (total: 3) escenarios para el par en el flop.
  • Puede adivinar que enumerando explícitamente los 10 escenarios posibles y calculándolos en el ámbito de las permutaciones en lugar de las combinaciones (dado que ya estaría permutando las X y las ?), las fórmulas aplicadas serían exactamente las mismas en cada caso, con un diseño diferente. . Los resultados finales de los casos serían similares (no iguales a estas fórmulas aplicadas, pero aún así la misma proporción entre mano, conectado y flop). Las proporciones finales serían exactamente las mismas. Este es un ejercicio que te dejo a ti.

Por lo tanto, siempre trate de verificar si usó la fórmula y los supuestos correctos .

Construir para cualquier juego de póquer

En cada juego de póquer, las cartas recibidas pertenecen a diferentes momentos de su análisis y/o tienen diferentes cualidades. ¡Pero tales cualidades dependen de su pregunta! Ejemplos:

En un análisis que se preocupa por el tiempo de las cartas :

  • Las cartas ocultas de Hold'Em/Omaha tienen las mismas cualidades: son secretas y las recibe en el mismo momento. Entre ellas, tratarás las combinaciones, pues al tener las cartas las mismas cualidades, no darás cuenta del orden de recepción de las mismas.
  • Las cartas flop de Hold'Em/Omaha tienen las mismas cualidades: son públicas y se reciben en el mismo momento. Lo mismo con respecto al pedido se aplica aquí.
  • El turn y el river HE/O tienen cualidades diferentes: son públicos pero se reciben en momentos diferentes.

Entonces, para ellos, calculará su espacio como 52c2 (hole cards) * 50c3 (flop cards) * 47 (turn) * 46 (river)posibilidades generales.

Puedes pensar así:

  • El grupo de cartas que involucra elementos similares puede calcular sus probabilidades mediante combinaciones en casos enteros y esperados.
  • El grupo de cartas que involucra diferentes elementos debe calcular sus probabilidades en términos de permutaciones, no exactamente pero conceptualmente similares. Esto se debe a que no es lo mismo tener la misma carta como un elemento que como otro elemento, por lo que aquí importa el orden.

Asi que:

  • Tomé las primeras 2 cartas de 52 y las consideré en combinación.
  • Tomé las siguientes 3 cartas de 50 y las consideré en combinación. Pero fíjate cómo los primeros condicionaron el mundo de manera permutacional: no es lo mismo recibir X en el hoyo e Y en el flop, que Y en el hoyo y X en el flop, por lo que solo se relacionan de manera permutacional en el sentido de que I no debe dividir por, digamos, 2!(lo que erróneamente pertenecería a barajar el flop y el hoyo).
  • Tomé la siguiente carta de 47.
  • Tomé la siguiente carta de 46.

Sin embargo, en un análisis estático en el río, sin contar el tiempo pero preguntando sobre el estado general de la tabla al final, solo tendrá que considerar dos espacios: 52c2 (hole) * 50c5 (community)porque esos espacios son:

  • Tomé las primeras 2 cartas de 52 y las consideré en combinación.
  • Tomé las siguientes 5 cartas de 50 y las consideré en combinación (ya no me importa su orden).

4. Conclusión

  • Tenga en cuenta el tipo de juego y la verdadera naturaleza del mundo que desea analizar. Ese mundo se dividirá en subespacios más tarde.
  • Haga la pregunta correcta y considere los espacios involucrados:
    • Si los palos o valores de espacios relacionados en la pregunta no son independientes, harás una permutación de ellos (si además el orden entre ellos no importa, harás una combinación en su lugar). Si son independientes, sus espacios se multiplicarán (ejemplos: cuando los palos se restringían entre sí calculé como 4c2, pero cuando los valores eran los que se restringían entre sí, consideré los palos como independientes y calculé como 4*4).
    • Cualquiera que sea su elección entre permutaciones, combinaciones e independencia, asegúrese de que sea consistente : el mismo tipo de cálculo que usa en los casos generales, lo usará para los casos esperados.
  • ¡Identifique correctamente escenarios disjuntos y superpuestos! Como hice en la pregunta del par.
  • Aprende Python, usa las funciones de Python que te dije. Recuerda que siempre debes validar R <= N. Recuerda que las probabilidades son un número entre 0 y 1. Debes multiplicar por 100 para tener un valor porcentual.
  • ¡Aprende documentos académicos sobre probabilidades condicionales, espacios de probabilidades discretas, eventos de probabilidad independientes y en general todo lo relacionado con ese tema frecuentemente subestimado!
No he leído todo esto, pero por las partes que he leído, ¡este es un trabajo increíble! Aunque es bastante largo, hay un montón de cosas buenas presentadas de manera clara y concisa que podrían responder muchas de las preguntas que se hacen aquí (o en otros lugares).
Espero que sea lo suficientemente claro para mst ppl

Estas son las manos de póquer de 5 cartas
Esto coincide con todos los recuentos de manos aquí Probabilidades de póquer de WIKI

Si va a escribir cualquier tipo de calculadora de equidad, juego o bot, aquí es donde le recomiendo que comience. Cualquier simulación debe poder identificar las manos.

A las 5 cartas es fácil con combinación.

Monte Carlo es popular para ejecutar sorteos aleatorios, pero esto solo ejecuta todas las manos. Las computadoras se están volviendo lo suficientemente rápidas como para que puedas ejecutar todas las manos. Esto ejecuta las 2,598,960 posibles combinaciones de 5 cartas en 1 segundo.

Esto es .NET C#

public void Deal5()
{
    Stopwatch sw = new Stopwatch();
    sw.Start();
    //int[,] deck = new int[4, 13];
    //for(int i = 0; i < 52; i ++)
    //    Debug.WriteLine("Suit = " + (i / 13)  + " Rank = " + i % 13);
    int counter = 0;
    int counterFlush = 0;
    int counterStraight = 0;
    int counterStraightFlush = 0;
    int counterQuad = 0;
    int counterBoat = 0;
    int counterTrips = 0;
    int counterPairTwo = 0;
    int counterPairOne = 0;
    int counterHigh = 0;
    //Random rand = new Random();
    //Dictionary<int, int> rankCount = new Dictionary<int, int>(5);
    int card1rank;
    int card1suit;
    int card2rank;
    int card2suit;
    int card3rank;
    int card3suit;
    int card4rank;
    int card4suit;
    int card5rank;
    int card5suit;
    bool haveStraight;
    bool haveFlush;
    int[] rankArray = new int[13];
    int rankArrayMax;
    int straightCount;
    bool quad;
    bool trips;
    int pairs;
    for (int i = 51; i >= 4; i--)
    {
        card1rank = i % 13;
        card1suit = i / 13;
        for (int j = i - 1; j >= 3; j--)
        {
            card2rank = j % 13;
            card2suit = j / 13;
            for (int k = j - 1; k >= 2; k--)
            {
                card3rank = k % 13;
                card3suit = k / 13;
                for (int l = k - 1; l >= 1; l--)
                {
                    card4rank = l % 13;
                    card4suit = l / 13;
                    for (int m = l - 1; m >= 0; m--)
                    {
                        counter++;
                        haveStraight = false;
                        haveFlush = false;
                        card5rank = m % 13;
                        card5suit = m / 13;

                        haveFlush = (card1suit == card2suit && card1suit == card3suit && card1suit == card4suit && card1suit == card5suit);

                        rankArray[0] = 0;
                        rankArray[1] = 0;
                        rankArray[2] = 0;
                        rankArray[3] = 0;
                        rankArray[4] = 0;
                        rankArray[5] = 0;
                        rankArray[6] = 0;
                        rankArray[7] = 0;
                        rankArray[8] = 0;
                        rankArray[9] = 0;
                        rankArray[10] = 0;
                        rankArray[11] = 0;
                        rankArray[12] = 0;

                        rankArray[card1rank]++;
                        rankArray[card2rank]++;
                        rankArray[card3rank]++;
                        rankArray[card4rank]++;
                        rankArray[card5rank]++;

                        rankArrayMax = 1;
                        straightCount = 0;
                        for (int q = 0; q < 13; q++)
                        {
                            if (rankArray[q] > rankArrayMax)
                                rankArrayMax = rankArray[q];
                            if (rankArrayMax > 1)
                                break;  // cannot make a straight if there are any pairs
                            if (rankArray[q] == 1)
                            {
                                straightCount++;
                                if (straightCount == 5)
                                    break;
                            }
                            else
                                straightCount = 0;
                        }
                        //                                     ace high straight
                        haveStraight = (straightCount == 5 || (straightCount == 4 && rankArray[0] == 1));

                        if (haveStraight && haveFlush)
                            counterStraightFlush++;
                        else if (haveFlush)
                            counterFlush++;
                        else if (haveStraight)
                            counterStraight++;
                        else if (rankArrayMax == 1)
                            counterHigh++;
                        else
                        {
                            //continue;
                            quad = false;
                            trips = false;
                            pairs = 0;
                            //foreach (int r in rankArray.OrderByDescending(x => x))  for some reason this was SLOW
                            for (int q = 0; q < 13; q++)
                            {
                                if (rankArray[q] <= 1)
                                    continue;
                                //Debug.WriteLine(r);
                                if (rankArray[q] == 2)
                                    pairs++;
                                else if (rankArray[q] == 3)
                                    trips = true;
                                else
                                    quad = true;
                            }

                            if (trips)
                            {
                                if (pairs > 0)
                                    counterBoat++;
                                else
                                    counterTrips++;
                            }
                            else if (pairs == 1)
                                counterPairOne++;
                            else if (pairs == 2)
                                counterPairTwo++;
                            else
                                counterQuad++;
                        }
                    }
                }
            }
        }
    }
    sw.Stop();
    Debug.WriteLine("hand count            " + counter.ToString("N0"));
    Debug.WriteLine("stopwatch millisec    " + sw.ElapsedMilliseconds.ToString("N0"));
    int sum = counterHigh + counterPairOne + counterPairTwo + counterTrips + counterStraight
            + counterFlush + counterBoat + counterQuad + counterStraightFlush;
    Debug.WriteLine("straightFlush counter " + counterStraightFlush.ToString("N0") + "        " + (100m * counterStraightFlush / sum).ToString("N4"));
    //Debug.WriteLine("supposed to be        " + ((int)40).ToString("N0"));
    Debug.WriteLine("quad count            " + counterQuad.ToString("N0") + "       " + (100m * counterQuad / sum).ToString("N4"));
    Debug.WriteLine("boat count            " + counterBoat.ToString("N0") + "     " + (100m * counterBoat / sum).ToString("N4")); // + " " + (100m * ((100m * counterBoat / sum) - 0.144057623049m) / 0.144057623049m).ToString("N4"));
    Debug.WriteLine("flush counter         " + counterFlush.ToString("N0") + "     " + (100m * counterFlush / sum).ToString("N4"));
    //Debug.WriteLine("supposed to be        " + ((int)5148).ToString("N0"));
    Debug.WriteLine("straight counter      " + counterStraight.ToString("N0") + "    " + (100m * counterStraight / sum).ToString("N4"));
    //Debug.WriteLine("supposed to be        " + ((int)10240).ToString("N0")); 
    //Debug.WriteLine("counterStraightTop    " + counterStraightTop.ToString("N0"));
    //Debug.WriteLine("counterStraightTopNot " + counterStraightTopNot.ToString("N0"));
    //Debug.WriteLine("diff striaght         " + (counterStraight - 10240).ToString("N0"));
    Debug.WriteLine("trips count           " + counterTrips.ToString("N0") + "    " + (100m * counterTrips / sum).ToString("N3"));
    Debug.WriteLine("two pair count        " + counterPairTwo.ToString("N0") + "   " + (100m * counterPairTwo / sum).ToString("N3"));
    Debug.WriteLine("one pair counter      " + counterPairOne.ToString("N0") + " " + (100m * counterPairOne / sum).ToString("N2"));
    Debug.WriteLine("high card counter     " + counterHigh.ToString("N0") + " " + (100m * counterHigh / sum).ToString("N2"));// + " " + (100m * ((100m * counterHigh / sum) - 50.11773940m) / 50.11773940m).ToString("N4"));
    Debug.WriteLine("sum                   " + sum.ToString("N0"));
    sw.Stop();
    Debug.WriteLine("stopwatch millisec    " + sw.ElapsedMilliseconds.ToString("N0"));
    Debug.WriteLine("");
}