Jugador Virtual de Póker Texas Hold'em
Jugador Virtual de Póker Texas Hold'em
Pareja
El color lo forman cinco cartas no consecutivas del mismo palo. 3. OBJETIVO Y PRESENTACIÓN DEL
Gana el desempate entre dos colores aquel que tenga la carta más MODELO
alta.
3.1 Introducción
Escalera Primero, decir que un modelo que simule el comportamiento de
un humano jugando al póker, es casi inviable, por la cantidad de
factores que influyen, tanto dentro del juego como factores
externos.
El modelo que se presenta aquí, y la inmensa mayoría de modelos
existentes son modelos simplificados, que sólo tienen en cuenta
factores internos del juego y siempre será una máquina, luego
Para la escalera se precisan cinco cartas de valor consecutivo. siempre pensará “con la cabeza fría” y elegirá la mejor jugada en
Entre dos escaleras gana la que sea más alta. Por otra parte, el As cada momento.
puede usarse para formar la escalera A-K-Q-J-10, que sería una A corto plazo puede no resultar victorioso, pero este modelo sigue
Escalera Real, y también la escalera 5-4-3-2-A. un criterio de probabilidades, por el cual está comprobado que a
[Link]. xx medio/largo plazo se obtienen ganancias.
Trío
Nuestro modelo empezará siguiendo una determinada estrategia, y
podrá ir cambiando a lo largo de la partida, dependiendo del
comportamiento del rival.
3.4.7 Random
Para simular de mejor manera el jugador virtual, utilizaremos la
función de C++ Random y así poder hacer un jugador más
imprevisible. En todas las tomas de decisiones utilizaremos esta
función.
if (ciega_grande == true)
3.4.1 Probabilidad umbral Poner_ciega_grande();
La probabilidad umbral es la probabilidad mínima de ganar que
debe tener la mano para jugar. Está es diferente dependiendo la if (ciega_pequeña == true)
cantidad de jugadores en mesa. Por debajo se este umbral, se Poner_ciega_pequeña();
considera que la mano tiene muy pocas probabilidades de ganar y
se supone una pérdida innecesaria de fichas. A lo largo de la
partida, dependiendo del tipo de jugadores a los que nos Luego, se reparten dos cartas a cada jugador, y en ese momento
enfrentemos, esta probabilidad umbral variará a más o menos. calculamos la probabilidad que tiene nuestra mano de ganar
(fuerza de la mano), dependiendo del número de jugadores, de
nuestra posición en la mesa y de si hemos sido ciega (grande o
pequeña) o no.
Diagrama de las fases del juego:
else
probabilidad_total = Fuerza_mano(mano_incial) + Calcular FM Igualar
Random(0,0.2) - Random(0,0.2);
}
Subir
Mientras las apuestas no hayan sido igualadas, calcularemos el
ratio de ganancia y el ratio de devolución para realizar la jugada.
Teniendo en cuenta estos parámetros y los factores Random
jugaremos (función Jugar) de un modo u otro (Irse, Igualar o Flop
Subir). Irse
A lo largo de las manos, se analizará a los adversarios y teniendo
en cuenta la variables para este análisis jugaremos siguiendo una
estrategia u otra (definidas en el punto 3.2). Calcular FM Igualar
4.2 Flop
Con esto llegamos al Flop, donde se reparten tres cartas Subir
comunitarias. A partir de este momento nuestra mano pasará a
tener 5 cartas, y la probabilidad para calcular la fuerza de la mano
se calculará por un método señalado anteriormente. Hay que
señalar que este método no es del todo exacto, pero nos da una
muy buena aproximación de nuestras probabilidades de ganar la Turn
mano.
Irse
Como ya se hiciera en el Pre-Flop, calcularemos de nuevo los
parámetros básicos para la toma de decisiones y en función de
ellos jugaremos (función Jugar). Calcular FM Igualar
4.3 Turn
Igual que en las fases anteriores, realizaremos un tipo de jugada u
otra según los parámetros básicos. Subir
4.4 River
En esta última fase se decidirá quién gana finalmente esa mano
después de las apuestas. River
Irse
Como añadido, el jugador hará un All in (apostarlo todo) si sus
fichas actuales son diez veces menos que sus fichas iniciales para
intentar salvar la partida (o perder inmediatamente). Calcular FM Igualar
Subir
if (ratio_devolucion < 1)
Si
{ Irse (95%)
if (aleatoriedad > 0.15)
Irse();
if (aleatoriedad <= 0.15 && 0.05 < aleatoriedad) RD < 0.8 Igualar (0%)
Subir(ratio_subida);
Subir (5%)
if (aleatoriedad <= 0.05)
Igualar();
}
Si
Irse (80%)
5.3 Ratio de devolución inferior a 1.3
En este punto nuestra mano ya se considerará buena y tendremos
opciones reales de hacernos con el boto final. Así que en este caso RD < 1 Igualar (5%)
igualaremos la apuesta con un 60% de probabilidad y subiremos
con un 40%. En ningún caso nos iremos.
Subir (15%)
if (ratio_devolicion < 1.3)
{
if (aleatoriedad > 0.4)
Igualar();
if (aleatoriedad <= 0.4)
7. BIBLIOGRAFÍA
Si
Irse (0%) 8. ANEXO. PSEUDO CÓDIGO EN C++
// Variables
RD > 1.3 Igualar (30%)
int numero_jugadores,
probabilidad_umbral, probabilidad_total,
Subir (70%) aletoriedad;
int fichas_iniciales,
fichas_disponibles, bote, apuesta,
ratio_devolucion, ratio_subida;
*RR: Ratio de devolución bool ciega_grande, ciega_pequeña,
apuesta_igualada, hablo, perder;
char mano_inicial [2],
6. CONCLUSIONES cartas_comunitarias [5];
El juego está basado en la minimización del factor suerte, luego // Funciones (sólo se define Jugar())
sólo sería rentable tras un número bastante grande de manos. Y void Poner_ciega_grande(void);
todo esto teniendo en cuenta sólo factores del juego, aunque no se void Poner_ciega_pequeña(void);
hayan contemplado todos (sería demasiado trabajoso y casi
void Igualar(void);
inviable).
void Irse(void);
Si la máquina se enfrentara a un jugador principiante, lo más void Subir(int);
probable es que gane, puesto que todas las probabilidades usadas, void All_in(void);
fórmulas y estrategias son reales. Está comprobado que si se juega int Fuerza_mano(char);
de esa forma se obtienen beneficios a largo plazo. Esto, sumado a
que una máquina siempre piensa fríamente y que siempre va a
int Ratio_ganancia(int, int);
elegir la que cree que es su mejor opción, la hace un rival muy bool Jugar(int, int, int, int);
difícil de batir. bool Resolucion_jugada(void);
Por otro lado, si tenemos el juego muy estudiado y sabemos cuál
es la mejor opción, podríamos predecir el comportamiento del
void main(void)
jugador virtual. {
// Cálculo de probabilidad umbral
Cabe mencionar, en cuanto al tema de poker y la inteligencia
suponiendo un máximo de cuatro jugadores
artificial, el ordenador Polaris, que se usó como experimento,
switch (numero_jugadores)
contra Phil Laak y Ali Eslami, dos jugadores de póquer de Los
Ángeles clasificados entre los mejores del mundo. Aunqué ganó y {
empató las 2 primeras partidas (de 500 manos cada una), al final case 2:
el resultado se decantó para el lado humano. probabilidad_umbral = 0.58;
case 3:
Todo esto demuestra que a pesar de los años de estudio de la
inteligencia artificial, todavía estamos en una constante evolución probabilidad_umbral = 0.42;
y nos queda mucho camino por recorrer. case 4:
probabilidad_umbral = 0.32;
}
// Inicio de la partida Fuerza_mano, ratio_devolucion,
while (1) aletoriedad);
{ }
// Se ponen las ciegas }
if (ciega_grande == true)
Poner_ciega_grande(); // Turn (cuatro cartas comunitarias)
if (ciega_pequeña == true) probabilidad_total =
Poner_ciega_pequeña(); Fuerza_mano(mano_inicial,
cartas_comunitarias)
// Se reparte la mano (dos cartas + Random(0,0.2) -
privadas) Random(0,0.2);
if (ciega_grande == true || if (probabilidad_total >=
ciega_pequeña == true) probabilidad_umbral)
{ {
probabilidad_total = while (apuesta_igualada == false
Fuerza_mano(mano_inicial) + || perder == false)
Random(0,0.2) - Random(0,0.2) + 0.05; {
else Ratio_ganancia(bote,
probabilidad_total = apuesta);
Fuerza_mano(mano_incial) + Random(0,0.2) ratio_devolucion =
- Random(0,0.2); Fuerza_mano / Ratio_ganancia;
} aleatoriedad = Random(0,1);
Jugar(Ratio_ganancia,
// Pre-Flop Fuerza_mano, ratio_devolucion,
if (probabilidad_total >= aletoriedad);
probabilidad_umbral) }
{ }
while (apuesta_igualada == false)
{ // River (cinco cartas comunitarias)
Ratio_ganancia(bote, probabilidad_total =
apuesta); Fuerza_mano(mano_inicial,
ratio_devolucion = cartas_comunitarias)
Fuerza_mano / Ratio_ganancia; + Random(0,0.2) -
aleatoriedad = Random(0,1); Random(0,0.2);
if (probabilidad_total >=
Jugar(Ratio_ganancia, Fuerza_mano, probabilidad_umbral)
ratio_devolucion, aletoriedad); {
} while (apuesta_igualada == false
} || perder == false)
{
// Flop (tres cartas comunitarias) Ratio_ganancia(bote,
probabilidad_total = apuesta);
Fuerza_mano(mano_inicial, ratio_devolucion =
cartas_comunitarias) Fuerza_mano / Ratio_ganancia;
+ Random(0,0.2) - aleatoriedad = Random(0,1);
Random(0,0.2); Jugar(Ratio_ganancia,
if (probabilidad_total >= Fuerza_mano, ratio_devolucion,
probabilidad_umbral) aletoriedad);
{ }
while (apuesta_igualada == false }
|| perder == false)
{ bool Jugar(void){
Ratio_ganancia(bote, if (hablo == true)
apuesta); {
ratio_devolucion = if (fichas_disponibles <
Fuerza_mano / Ratio_ganancia; fichas_iniciales / 10)
aleatoriedad = Random(0,1); All_in();
Jugar(Ratio_ganancia, else
if (ratio_devolucion < 0.8) mano
//Muy mala mano {
{ if (aletoriedad
if (aleatoriedad > > 0.4)
0.05) Igualar();
Irse(); if (aletoriedad
if (aleatoriedad <= <= 0.4)
0.05)
// Farol ratio_subida = (10*Ratio_ganancia)
* fichas_disponibles /
ratio_subida = (10*Ratio_ganancia) (100*Fuerza_mano);
* fichas_disponibles /
(100*Fuerza_mano); Subir(ratio_subida);
}
Subir(ratio_subida); else
} // Muy
else if buena mano
(ratio_devolucion < 1) // Mala {
mano if (aletoriedad
{ > 0.3)
if (aletoriedad
> 0.15) ratio_subida = (10*Ratio_ganancia)
Irse(); * fichas_disponibles /
if (aletoriedad (100*Fuerza_mano);
<= 0.15 && 0.05 < Aletoriedad)
// Farol Subir(ratio_subida);
if (aletoriedad
ratio_subida = (10*Ratio_ganancia) <= 0.3)
* fichas_disponibles / Igualar();
(100*Fuerza_mano); }
}
Subir(ratio_subida); else
if (aletoriedad Esperar_turno();
<= 0.05)
Igualar(); perder =
} Resolucion_jugada();
else if }
(ratio_devolicion < 1.3) // Buena