Skip to content
[OPEN_POKER]

Arquitectura avanzada de un bot de póquer: equity y pruebas

JJoão Carvalho||13 min read

Un bot de póquer avanzado convierte un bucle de eventos fiable en un sistema de decisiones medible. La mejora no consiste en «añadir IA». Consiste en usar instantáneas de decisión inmutables, características de póquer explícitas, equity basada en rangos, manos reproducibles y un ciclo de experimentación que pueda demostrar que una política ha cambiado. Conserva el control de acciones legales del bot básico. Todo lo más inteligente se sitúa detrás.

Serie sobre arquitectura de bots de póquer: Parte 2 de 3. Empieza por Arquitectura básica de un bot de póquer si tu entorno de ejecución todavía rechaza acciones. Continúa con Arquitectura profesional de un bot de póquer. Compara las opciones operativas en Coste de un bot de póquer en 2026.

¿Qué cambia en la arquitectura de un bot de póquer avanzado?

Un bot de póquer avanzado separa hechos, estimaciones, política y ejecución. Los hechos proceden del turno más reciente del servidor: bote, mesa, stacks, acciones legales, identificador de mano y token. Las estimaciones incluyen la equity y el rango del rival. La política usa ambas cosas para devolver una intención. La ejecución contrasta esa intención con los hechos una última vez.

Esta distinción importa porque las estimaciones pueden equivocarse. Un modelo de rival puede asignar un rango demasiado tight. Una simulación Monte Carlo puede tener error de muestreo. Ninguno de esos errores debe producir una subida no válida ni una respuesta para un turno caducado. La capa exterior sigue siendo determinista aunque la política interior se vuelva probabilística.

Clase de datosEjemploConfianzaResponsable
Hecho del servidorpot = 180, máximo de subida 1,640AutoritativoAdaptador del protocolo
Hecho derivadoPot odds, stack efectivo, posiciónExacto si las entradas son correctasCapa de características
Estimación43% de equity al showdownMuestreada o modeladaServicio de equity
CreenciaEl rival abre el 31% desde el botónInciertaModelo de rivales
IntenciónCall porque la equity supera el precioSalida de la políticaEstrategia

Nunca aplanes todo eso en un único diccionario sin tipos. Cuando desaparecen la confianza y la responsabilidad, un rango estimado empieza a parecer tan fiable como el límite de subida del servidor.

¿Cómo deben funcionar las instantáneas de decisión inmutables?

Una instantánea de decisión inmutable es una entrada completa y de solo lectura capturada a partir de un your_turn. Impide que eventos tardíos de la red cambien los datos mientras se calcula la equity o trabaja el modelo. También se convierte en la unidad que reproduces en las pruebas.

from dataclasses import dataclass
from typing import Literal
 
Action = Literal["fold", "check", "call", "raise", "all_in"]
 
 
@dataclass(frozen=True)
class DecisionSnapshot:
    hand_id: str
    turn_token: str
    street: str
    hole: tuple[str, str]
    board: tuple[str, ...]
    pot: float
    stack: float
    to_call: float
    opponents: int
    position: str
    legal: tuple[Action, ...]
    min_raise: float | None
    max_raise: float | None
 
    @property
    def pot_odds(self) -> float:
        return self.to_call / (self.pot + self.to_call) if self.to_call else 0.0
 
    @property
    def stack_to_pot(self) -> float:
        return self.stack / self.pot if self.pot else float("inf")

Crea la instantánea de forma síncrona cuando llegue el turno. Después, pásala a una tarea de decisión asíncrona. Antes de enviar el resultado, vuelve a comparar su hand_id y turn_token con el turno activo. Los tokens de Open Poker se consumen después de una acción y cada nuevo your_turn invalida el anterior, por lo que el trabajo obsoleto debe descartarse, no reintentarse.

La referencia de tipos de mensajes documenta los campos del protocolo. Tu normalizador también debe aceptar table_state después de una reconexión, porque su sección hero, específica del jugador, contiene las cartas propias y las acciones legales actuales.

¿Cómo se convierten la equity y las pot odds en una decisión?

La equity responde a la frecuencia con la que una mano recibe el bote en el showdown frente a un rango supuesto; las pot odds responden a la proporción de equilibrio necesaria para un call. Pagar tiene una expectativa positiva en fichas cuando la equity estimada supera call / (pot + call), antes de realizar ajustes por apuestas futuras, errores de rango y objetivos del torneo.

Si el bote es de 180 y pagar cuesta 60, las pot odds son 60 / 240 = 25%. Una equity estimada del 38% supera ese umbral bruto en 13 puntos porcentuales. No pagues todas las situaciones con una ventaja de un punto. La varianza de Monte Carlo, un rango rival impreciso y las acciones futuras pueden borrar un margen pequeño. Nosotros usamos un margen de seguridad explícito y lo registramos.

from dataclasses import dataclass
 
 
@dataclass(frozen=True)
class EquityResult:
    equity: float
    trials: int
    range_name: str
 
 
def call_has_margin(snapshot: DecisionSnapshot, result: EquityResult,
                    margin: float = 0.03) -> bool:
    return (
        "call" in snapshot.legal
        and result.equity >= snapshot.pot_odds + margin
    )

La calculadora de equity Monte Carlo muestra una implementación en Python. Si buscas primitivas de evaluación mantenidas, la documentación del evaluador de PokerKit es un punto de partida más sólido que escribir un evaluador de manos durante un proyecto de estrategia.

¿Cómo debe representar la incertidumbre un modelo de rivales?

Un modelo de rivales debe almacenar recuentos y tasas suavizadas, no etiquetas como «agresivo» o «fish». Entre las primeras características útiles están la participación voluntaria preflop, la tasa de subida preflop, las oportunidades de three-bet y las acciones realizadas, la agresividad postflop, las oportunidades de foldear ante una apuesta y las manos observadas en el showdown. Cada tasa necesita su denominador.

Un jugador que ha subido dos veces en cuatro oportunidades tiene una tasa observada del 50% y casi ninguna certeza. El suavizado bayesiano evita que muestras diminutas alteren bruscamente la política. Con una distribución previa Beta, una tasa puede estimarse como (successes + alpha) / (opportunities + alpha + beta). Una distribución previa neutral Beta(2, 2) convierte dos subidas en cuatro oportunidades en 4 / 8 = 50%, mientras que cero subidas en una oportunidad se convierte en 2 / 5 = 40%, no en un cero con alta confianza.

Segmenta las estadísticas según las situaciones que cambian la estrategia. La posición y la calle importan. Una «agresividad» global de la mesa mezcla una apertura desde under the gun con un check-raise en el river. Empieza con unos pocos grupos que puedas llenar, no con cincuenta celdas dispersas. Nuestra guía sobre modelado de rivales profundiza en el decaimiento, la evidencia del showdown y los límites a la explotación.

Mantén una política de referencia que ignore las características de los rivales. Sin ella, no puedes saber si la adaptación ayuda o si sencillamente todo el bot tuvo una buena semana.

¿Qué debe devolver la interfaz de una política avanzada?

La política avanzada debe devolver la intención de acción, la intención de importe, códigos de motivo, valores de las características y metadatos del modelo. Una cadena simple como "call" es demasiado escasa para el análisis. Un ensayo de formato libre es demasiado impreciso para el código. Usa un registro con tipos.

from dataclasses import dataclass, field
 
 
@dataclass(frozen=True)
class DecisionIntent:
    action: Action
    amount: float | None
    reason_code: str
    confidence: float
    features: dict[str, float] = field(default_factory=dict)
    policy_version: str = "range-equity-v3"
 
 
def decide(snapshot: DecisionSnapshot, eq: EquityResult) -> DecisionIntent:
    features = {
        "equity": eq.equity,
        "pot_odds": snapshot.pot_odds,
        "spr": snapshot.stack_to_pot,
    }
    if snapshot.to_call == 0 and "check" in snapshot.legal:
        return DecisionIntent("check", None, "free_action", 1.0, features)
    if call_has_margin(snapshot, eq):
        confidence = min(1.0, (eq.equity - snapshot.pot_odds) * 4)
        return DecisionIntent("call", None, "equity_clears_price", confidence, features)
    return DecisionIntent("fold", None, "equity_below_price", 0.8, features)

El control de ejecución sigue siendo responsable de aplicar límites y alternativas. Si esta política propone un call después de que cambie el turno activo, descártalo. Si propone una subida que no está en la lista legal, sustitúyela por check o fold e incrementa una métrica de infracciones de la política. Una corrección silenciosa oculta errores; la corrección acompañada de telemetría mantiene la mesa segura y hace visible el fallo.

¿Cómo prueban las repeticiones de manos toda la ruta de decisión?

Las repeticiones de manos introducen eventos registrados del servidor en el mismo normalizador y la misma política que se usan en vivo, sin abrir un socket. Detectan errores que las pruebas unitarias aisladas no encuentran: estado que se filtra entre manos, una posición derivada de un asiento vacío, un evento duplicado o un importe null que llega a una operación aritmética.

Almacena un mensaje JSON por línea y conserva el orden de llegada. Un ejecutor de repeticiones puede cargar el archivo y llamar a los manejadores reales. Sustituye el azar por una semilla fija y los servicios externos por respuestas registradas. La salida debe ser una secuencia de registros de decisión que una prueba pueda comparar con el comportamiento aprobado.

import json
import random
from pathlib import Path
 
 
def replay(path: str, engine) -> list[dict]:
    random.seed(20260812)
    decisions = []
    for line in Path(path).read_text(encoding="utf-8").splitlines():
        event = json.loads(line)
        result = engine.apply(event)
        if result is not None:
            decisions.append(result)
    return decisions
 
 
def test_replay_never_emits_illegal_action(engine):
    for item in replay("fixtures/three_hands.jsonl", engine):
        assert item["action"] in item["legal"]

Las pruebas basadas en propiedades son útiles para los controles de acciones. Genera conjuntos aleatorios de acciones legales y límites de subida, y después verifica que la salida siempre se ofrece y siempre queda dentro de los límites. Hypothesis está diseñado para este tipo de pruebas. No necesitas pruebas de propiedades para cada opinión sobre póquer, pero los invariantes del protocolo sí las merecen.

¿Cómo debes evaluar un cambio de estrategia?

Evalúa un cambio de estrategia con políticas emparejadas, etiquetas de versión fijas, métricas operativas y suficientes manos para hacer visible la incertidumbre. No despliegues un rango nuevo y compares sus siguientes 200 manos con el resultado del martes pasado. La mezcla de rivales, las posiciones y la varianza de las cartas han cambiado.

Registra al menos estas métricas:

MétricaPor qué importa
Acciones ilegales por cada 1.000 turnosCriterio estricto de corrección
Latencia de decisión p50, p95 y p99Detecta fallos en la cola que ocultan los promedios
Tasa de alternativasMuestra inestabilidad en la política o las dependencias
bb/100 con intervalo de confianzaResultado de la estrategia normalizado por ciegas
Estimación ajustada para all-insReduce parte de la varianza del showdown
VPIP, PFR y tasa de three-betExplica cómo cambió el comportamiento
Tasa de folds por calleDetecta fugas estratégicas evidentes

Usa números aleatorios comunes en un simulador cuando sea posible: ejecuta las políticas A y B con los mismos repartos y acciones de los rivales. El juego en vivo no permite controlar por completo el entorno, así que registra la composición de la mesa y compara ventanas más largas. El artículo de OpenSpiel de Google DeepMind describe un marco de evaluación e investigación para juegos, incluidos los de información imperfecta. Resulta útil en local, mientras que el entorno en vivo de Open Poker pone a prueba el protocolo y la diversidad de rivales.

Un cambio no se promociona solo porque el bb/100 sea positivo. Debe mantener en cero los criterios de corrección, mantener la latencia dentro del presupuesto y mejorar un objetivo declarado sin provocar una regresión inaceptable en otro aspecto.

¿Dónde encaja un LLM en el nivel avanzado?

Un LLM encaja detrás de la misma interfaz de política como asesor selectivo, no como cliente de red ni como autoridad sobre la legalidad. Dale una instantánea compacta, las acciones legales exactas, las pot odds calculadas, un rango estimado y un esquema JSON estricto. Valida su respuesta y conserva una alternativa determinista.

Evita enviar al modelo las decisiones obvias. Un check gratuito, un fold forzoso según una tabla preflop estricta o un tamaño de subida ya elegido por una regla determinista de valor no necesitan una llamada remota. El enrutamiento selectivo reduce el coste y facilita el control de la latencia. La guía sobre bots de póquer con LLM muestra el patrón básico de conexión, pero un entorno de ejecución avanzado debe añadir validación de esquemas, prompts versionados, cancelación por plazo y casos de repetición.

Somos escépticos respecto a los motivos en lenguaje natural como evidencia de evaluación. Un modelo puede producir una explicación convincente de una acción mala. Evalúa la acción según los resultados, las pruebas contrafactuales y las métricas estables. Conserva el texto para depurar, pero confía en las características estructuradas y en el registro del experimento.

Preguntas frecuentes

¿Qué hace que un bot de póquer sea avanzado?

Un bot avanzado usa instantáneas inmutables de los turnos, características derivadas explícitas, equity basada en rangos, estadísticas de los rivales, pruebas de repetición y experimentos versionados. Tener más código de estrategia no basta para que la arquitectura sea avanzada.

¿Cuántas iteraciones Monte Carlo debe ejecutar un bot de póquer?

Empieza con entre 2.000 y 5.000 iteraciones por decisión y mide el rendimiento en tu hardware. Usa más solo cuando la estimación cambie decisiones lo suficiente como para justificar la latencia. Registra tanto el número de iteraciones como el tiempo de ejecución.

¿Cuántos datos necesito para modelar rivales?

Aplica el suavizado desde la primera observación, pero mantén una adaptación pequeña hasta que cada estadística tenga un denominador significativo. No existe un número mágico de manos porque las oportunidades de three-bet aparecen con mucha menos frecuencia que las oportunidades de participación preflop.

¿Debo optimizar la tasa de ganancias o el beneficio en fichas?

Usa ciegas grandes por cada 100 manos para informar sobre estrategias comparables, además de las fichas brutas para medir el efecto en la temporada. Publica siempre la incertidumbre y las métricas operativas. Una estimación puntual sin número de manos ni intervalo invita a una falsa confianza.

¿Pueden las pruebas de repetición demostrar que una estrategia de póquer gana?

No. Las repeticiones demuestran un comportamiento determinista y detectan regresiones en situaciones conocidas. Las simulaciones y los experimentos en vivo prueban el rendimiento ante distribuciones de manos y rivales.

Cuando las versiones de las políticas, las repeticiones de manos y las métricas hagan auditable cada cambio, la siguiente limitación será operativa. Arquitectura profesional de un bot de póquer aborda la resincronización, los presupuestos de plazos, el aislamiento de fallos, la evaluación en modo sombra y los lanzamientos seguros para un bot que funciona sin supervisión.

Seguir Leyendo