Architecture d’un bot de poker avancé : équité et tests
Un bot de poker avancé transforme une boucle d’événements fiable en système de décision mesurable. L’amélioration ne consiste pas à « ajouter de l’IA », mais à introduire des instantanés de décision immuables, des caractéristiques de poker explicites, une équité tenant compte des ranges, des mains rejouables et une boucle expérimentale capable de prouver qu’une politique a changé. Conservez le garde-fou des actions légales du bot débutant. Toute l’intelligence se place derrière lui.
Série sur l’architecture des bots de poker : partie 2 sur 3. Commencez par Architecture d’un bot de poker débutant si votre runtime refuse encore des actions. Poursuivez avec Architecture d’un bot de poker professionnel. Comparez les options d’exploitation dans Coût d’un bot de poker en 2026.
Qu’est-ce qui change dans l’architecture d’un bot de poker avancé ?
Un bot avancé sépare les faits, les estimations, la politique et l’exécution. Les faits proviennent du dernier tour du serveur : pot, board, tapis, actions légales, identifiant de main et jeton. Les estimations comprennent l’équité et la range adverse. La politique utilise les deux pour produire une intention. L’exécution confronte une dernière fois cette intention aux faits.
Cette distinction est importante, car les estimations ont le droit d’être erronées. Un modèle adverse peut attribuer une range trop serrée. Une simulation Monte-Carlo peut comporter une erreur d’échantillonnage. Aucune de ces erreurs ne doit produire une relance invalide ni une réponse pour un tour expiré. L’enveloppe reste déterministe, même si la politique interne devient probabiliste.
| Classe de données | Exemple | Confiance | Responsable |
|---|---|---|---|
| Fait serveur | pot = 180, relance max. 1,640 | Fait autorité | Adaptateur de protocole |
| Fait dérivé | Cote du pot, tapis effectif, position | Exact si les entrées le sont | Couche de caractéristiques |
| Estimation | 43 % d’équité à l’abattage | Échantillonnée ou modélisée | Service d’équité |
| Croyance | L’adversaire ouvre 31 % au bouton | Incertaine | Modèle adverse |
| Intention | Suivre car l’équité dépasse le prix | Sortie de politique | Stratégie |
Ne les aplatissez jamais dans un dictionnaire non typé. Lorsque confiance et responsabilité disparaissent, une range supposée semble aussi fiable que la borne de relance du serveur.
Comment fonctionnent les instantanés de décision immuables ?
Un instantané de décision immuable est une entrée complète, en lecture seule, capturée à partir d’un your_turn. Il empêche des événements réseau tardifs de modifier les données pendant le calcul d’équité ou l’inférence du modèle. Il devient aussi l’unité rejouée dans les tests.
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")Construisez l’instantané de manière synchrone à l’arrivée du tour, puis transmettez-le à une tâche de décision asynchrone. Avant l’envoi du résultat, comparez à nouveau ses hand_id et turn_token avec le tour actif. Les jetons Open Poker sont consommés après une action, et chaque nouveau your_turn invalide le précédent. Un travail périmé doit donc être abandonné, pas relancé.
La référence des types de messages documente les champs réseau. Votre normaliseur doit également accepter table_state après une reconnexion, car sa section hero, propre au joueur, contient les cartes privatives et les actions légales actuelles.
Comment l’équité et la cote du pot deviennent-elles une décision ?
L’équité indique la fréquence à laquelle une main reçoit le pot à l’abattage face à une range supposée. La cote du pot indique la part minimale requise pour rentabiliser un call. Suivre présente une espérance positive en jetons lorsque l’équité estimée dépasse call / (pot + call), avant les ajustements liés aux mises futures, à l’erreur de range et aux objectifs du tournoi.
Si le pot vaut 180 et que suivre coûte 60, la cote est 60 / 240 = 25%. Une équité estimée à 38 % dépasse ce seuil brut de 13 points. Ne suivez pas chaque fois que l’avantage n’est que d’un point. La variance Monte-Carlo, une range adverse imprécise et l’action future peuvent effacer une marge mince. Nous utilisons une marge de sécurité explicite et la journalisons.
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
)Le calculateur d’équité Monte-Carlo présente une implémentation Python. Pour des primitives d’évaluation maintenues, la documentation de l’évaluateur PokerKit constitue un meilleur point de départ que l’écriture d’un évaluateur de mains au milieu d’un projet stratégique.
Comment un modèle adverse doit-il représenter l’incertitude ?
Un modèle adverse doit stocker des décomptes et des taux lissés, pas des étiquettes comme « agressif » ou « fish ». Les premières caractéristiques utiles comprennent la participation volontaire préflop, le taux de relance préflop, les occasions de 3-bet et les actions correspondantes, l’agressivité postflop, les occasions de fold face à une mise et les mains observées à l’abattage. Chaque taux exige son dénominateur.
Un joueur qui relance deux fois en quatre occasions affiche un taux observé de 50 %, mais presque aucune certitude. Le lissage bayésien empêche les petits échantillons de faire osciller la politique. Avec un a priori Beta, un taux s’estime par (successes + alpha) / (opportunities + alpha + beta). Un a priori neutre Beta(2, 2) transforme deux relances en quatre occasions en 4 / 8 = 50%, tandis que zéro relance en une occasion devient 2 / 5 = 40%, et non un zéro certain.
Segmentez les statistiques selon les situations qui modifient la stratégie. La position et la street comptent. Une « agressivité » globale mélange une ouverture UTG et un check-raise river. Commencez par quelques catégories suffisamment alimentées, pas cinquante cellules clairsemées. Notre guide de modélisation des adversaires approfondit la décroissance, les informations d’abattage et les plafonds d’exploitation.
Conservez une politique de référence qui ignore les caractéristiques adverses. Sans elle, impossible de savoir si l’adaptation aide ou si le bot a simplement connu une bonne semaine.
Que doit renvoyer l’interface d’une politique avancée ?
La politique avancée doit renvoyer l’intention d’action et de montant, des codes de motif, les valeurs des caractéristiques et les métadonnées du modèle. Une simple chaîne comme "call" est insuffisante pour l’analyse. Un texte libre est trop peu structuré pour le code. Utilisez un enregistrement typé.
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)Le garde-fou d’exécution reste responsable du bornage et du repli. Si la politique propose un call après le changement du tour actif, abandonnez-le. Si elle propose une relance absente de la liste légale, remplacez-la par check ou fold et incrémentez une métrique de violation. Une correction silencieuse masque les bugs; une correction assortie de télémétrie protège la table tout en rendant la défaillance visible.
Comment les replays de mains testent-ils tout le chemin de décision ?
Les replays injectent des événements serveur enregistrés dans le même normaliseur et la même politique que ceux utilisés en direct, sans ouvrir de socket. Ils détectent des bugs que des tests unitaires isolés manquent : état transmis entre deux mains, position déduite d’un siège vide, événement dupliqué ou montant null utilisé dans un calcul.
Stockez un message JSON par ligne, dans l’ordre d’arrivée. Un exécuteur de replay charge le fichier et appelle les vrais gestionnaires. Remplacez l’aléatoire par une graine fixe et les services externes par des réponses enregistrées. La sortie doit être une suite d’enregistrements de décision qu’un test peut comparer au comportement approuvé.
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"]Les tests fondés sur les propriétés sont utiles pour les garde-fous. Générez des ensembles aléatoires d’actions légales et de bornes de relance, puis vérifiez que la sortie est toujours proposée et respecte toujours les bornes. Hypothesis est conçu pour ce type de test. Toutes les opinions stratégiques n’en ont pas besoin, mais les invariants du protocole le méritent.
Comment évaluer une modification de stratégie ?
Évaluez-la avec des politiques appariées, des versions fixes, des métriques opérationnelles et assez de mains pour révéler l’incertitude. Ne déployez pas une nouvelle range pour comparer ses 200 mains suivantes au résultat de mardi dernier. Le groupe d’adversaires, les positions et la variance des cartes ont changé.
| Métrique | Pourquoi elle compte |
|---|---|
| Actions illégales pour 1 000 tours | Critère strict de correction |
| Latence de décision p50, p95, p99 | Détecte les longues traînes masquées par les moyennes |
| Taux de repli | Révèle l’instabilité de la politique ou d’une dépendance |
| bb/100 avec intervalle de confiance | Résultat stratégique normalisé par les blindes |
| Estimation ajustée sur les all-ins | Réduit une partie de la variance d’abattage |
| VPIP, PFR, taux de 3-bet | Explique l’évolution du comportement |
| Taux de fold par street | Détecte les fuites stratégiques évidentes |
Utilisez si possible les mêmes nombres aléatoires dans le simulateur : exécutez les politiques A et B avec les mêmes distributions et actions adverses. En direct, contrôlez la composition des tables et comparez des périodes plus longues. L’article OpenSpiel de Google DeepMind décrit un cadre d’évaluation et de recherche pour les jeux à information imparfaite. Il convient aux essais locaux, tandis que l’arène Open Poker teste le protocole et la diversité adverse.
Une modification n’est pas promue au seul motif que son bb/100 est positif. Elle doit maintenir les critères de correction à zéro, respecter le budget de latence et améliorer une cible déclarée sans régression inacceptable ailleurs.
Quelle place pour un LLM au niveau avancé ?
Un LLM s’intègre derrière la même interface de politique, comme conseiller sélectif, et non comme client réseau ou autorité de légalité. Fournissez-lui un instantané compact, les actions légales exactes, la cote calculée, une range estimée et un schéma JSON strict. Validez sa réponse et gardez un repli déterministe.
Contournez le modèle pour les décisions évidentes. Un check gratuit, un fold imposé par une range préflop stricte ou une taille de relance déjà choisie par une règle de value ne nécessitent pas d’appel distant. Le routage sélectif réduit les coûts et facilite la maîtrise de la latence. Le guide du bot de poker avec LLM montre la connexion élémentaire; un runtime avancé doit ajouter validation du schéma, prompts versionnés, annulation à l’échéance et fixtures de replay.
Nous restons sceptiques face aux justifications en langage naturel comme preuve d’évaluation. Un modèle peut expliquer avec éloquence une mauvaise action. Jugez l’action d’après les résultats, les tests contrefactuels et des métriques stables. Conservez le texte pour déboguer, mais fiez-vous aux caractéristiques structurées et au dossier expérimental.
FAQ
Qu’est-ce qui rend un bot de poker avancé ?
Il utilise des instantanés immuables, des caractéristiques dérivées explicites, une équité tenant compte des ranges, des statistiques adverses, des replays et des expériences versionnées. Ajouter du code stratégique ne suffit pas.
Combien d’essais Monte-Carlo faut-il exécuter ?
Commencez par 2 000 à 5 000 essais par décision et mesurez votre matériel. N’en utilisez davantage que si l’estimation modifie assez souvent les décisions pour justifier la latence. Consignez le nombre d’essais et la durée.
Combien de données faut-il pour modéliser un adversaire ?
Lissez dès la première observation, mais limitez l’adaptation tant que chaque statistique ne possède pas un dénominateur significatif. Il n’existe pas de nombre magique, car les occasions de 3-bet sont bien plus rares que celles de participation préflop.
Faut-il optimiser le taux de gain ou le profit en jetons ?
Utilisez les grosses blindes par 100 mains pour comparer les stratégies, et les jetons bruts pour l’impact sur la saison. Publiez toujours l’incertitude et les métriques opérationnelles. Une estimation ponctuelle sans nombre de mains ni intervalle induit une fausse confiance.
Les replays peuvent-ils prouver qu’une stratégie gagne ?
Non. Ils prouvent un comportement déterministe et détectent les régressions sur des situations connues. Les simulations et expériences en direct évaluent les performances face à des distributions de mains et d’adversaires.
Lorsque les versions de politique, les replays et les métriques rendent chaque modification vérifiable, la contrainte suivante devient opérationnelle. Architecture d’un bot de poker professionnel traite de la resynchronisation, des budgets d’échéance, de l’isolation des défaillances, de l’évaluation fantôme et des déploiements sûrs pour un bot autonome.