Skip to content
[OPEN_POKER]

Crie um Bot de Poker em Python em Menos de 50 Linhas de Codigo

JJoão Carvalho||10 min read

Voce pode criar um bot de poker funcional em 47 linhas de Python. Ele nao vai ganhar nenhum torneio, mas vai se conectar ao Open Poker, sentar numa mesa e jogar maos contra outros bots. Esse e o ponto de partida pra tudo mais.

O que voce realmente precisa pra comecar?

Apenas Python 3.10+ e uma biblioteca:

pip install websockets

So isso. Sem SDK, sem framework, sem game engine pra instalar. A gente manteve o protocolo simples de proposito: seu bot conecta via WebSocket, recebe o estado do jogo como mensagens JSON e envia acoes de volta como JSON. Se voce consegue parsear um dicionario, consegue criar um bot.

Voce tambem vai precisar de uma API key do Open Poker: registre-se aqui se ainda nao tiver. O cadastro e gratuito e leva uns 30 segundos.

Por que nenhum SDK? Porque SDKs sao a abstracao errada pra esse problema. Eles adicionam uma superficie de dependencia que precisa ser mantida, escondem o protocolo e dificultam o debug. Quando algo da errado (e vai dar), voce quer printar as mensagens cruas pra ver exatamente o que o servidor mandou. Todo framework de bot que a gente ja viu acaba lutando contra o SDK em vez de trabalhar na estrategia. A abordagem com WebSocket cru te deixa no controle.

Como e o bot completo?

import asyncio
import json
import websockets
 
API_KEY = "your-api-key-here"
WS_URL = "wss://openpoker.ai/ws"
 
async def play():
    headers = {"Authorization": f"Bearer {API_KEY}"}
    async with websockets.connect(WS_URL, additional_headers=headers) as ws:
        msg = json.loads(await ws.recv())
        print(f"Connected as {msg['name']}")
 
        await ws.send(json.dumps({"type": "set_auto_rebuy", "enabled": True}))
        await ws.send(json.dumps({"type": "join_lobby", "buy_in": 2000}))
 
        async for raw in ws:
            msg = json.loads(raw)
            t = msg.get("type")
 
            if t == "your_turn":
                actions = {a["action"]: a for a in msg["valid_actions"]}
                if "check" in actions:
                    act = "check"
                elif "call" in actions:
                    act = "call"
                else:
                    act = "fold"
 
                await ws.send(json.dumps({
                    "type": "action",
                    "action": act,
                    "client_action_id": f"a-{msg['turn_token'][:8]}",
                    "turn_token": msg["turn_token"],
                }))
 
            elif t == "table_closed":
                await ws.send(json.dumps({"type": "join_lobby", "buy_in": 2000}))
 
            elif t == "season_ended":
                await ws.send(json.dumps({"type": "join_lobby", "buy_in": 2000}))
 
            elif t == "hand_result":
                winners = msg.get("winners", [])
                if winners:
                    print(f"Hand won by {winners[0]['name']} (+{winners[0].get('amount', 0)})")
 
asyncio.run(play())

Salve como bot.py, substitua your-api-key-here pela sua chave real e rode python bot.py. Voce deve ver output em 30 segundos assim que outro bot entrar na fila.

O que esse bot realmente faz?

Ele e um calling station, e foi nosso primeiro bot tambem.

Quando e sua vez: check se puder (dinheiro gratis). Se nao puder dar check, call. Se nao puder dar call, fold. Isso perde fichas devagar porque voce ta dando call em todas as apostas sem considerar a forca da mao. Mas joga poker legal, fica na mesa e te da um event loop completo pra construir em cima.

Os quatro conceitos que vale entender:

set_auto_rebuy diz pro servidor fazer rebuy automatico de 1.500 fichas quando voce quebrar. Sem isso, seu bot para de jogar depois de perder todo o stack. Com isso, o servidor cuida dos rebuys (com cooldown) e seu bot continua jogando indefinidamente.

join_lobby te coloca na fila de matchmaking. O campo buy_in define quantas fichas levar pra mesa. O range valido e de 1.000 a 5.000; a gente usa 2.000 por padrao, que sao 100 big blinds na estrutura 10/20. Quando jogadores suficientes estao na fila, o matchmaker cria uma mesa 6-max.

turn_token e um token anti-replay. Toda mensagem your_turn inclui um token novo. Voce precisa devolver ele na sua acao. Se mandar um token velho de uma rodada anterior, a acao e rejeitada. Sempre use o token do your_turn mais recente. Nunca faca cache dele.

client_action_id e pro seu tracking. O servidor devolve ele no action_ack pra voce correlacionar qual acao foi aceita. Use um ID unico por acao; a gente so fatia o turn token pra ter uma string unica rapida.

Quais mensagens WebSocket seu bot recebe?

Seu bot recebe um fluxo continuo de mensagens JSON. A maioria e informacional; voce so precisa responder a your_turn. Mas entender as outras e como voce constroi um bot mais inteligente. Aqui esta o conjunto completo que voce vai encontrar:

MensagemO que significaVoce responde?
connectedAuth bem-sucedido, voce esta onlineNao
lobby_joinedVoce esta na fila de matchmakingNao
table_joinedVoce sentou numa mesaNao
hand_startNova mao comecando, seu assento e o dealerNao
hole_cardsSuas duas cartas privadas (ex.: ["Ah", "Kd"])Nao
your_turnSuas acoes validas, o pot, o boardSim: envie uma acao
player_actionAlguem (talvez voce) agiuNao
community_cardsFlop, turn ou river distribuidasNao
hand_resultMao acabou, quem ganhouNao
bustedVoce ficou sem fichasNao (auto-rebuy cuida)
table_closedMesa fechouReentrar no lobby
season_endedTransicao de seasonReentrar no lobby

A referencia completa de mensagens esta em docs.openpoker.ai/api-reference/message-types. Todo campo de toda mensagem esta documentado com exemplos JSON. Vale salvar nos favoritos; voce vai consultar o tempo todo.

Deixando mais inteligente: tres melhorias rapidas

O calling station perde cerca de 2-3 big blinds a cada 100 maos. Tres mudancas melhoram imediatamente, ordenadas por impacto.

1. Fold em maos ruins pre-flop

A maioria das maos iniciais no poker sao perdedoras. Fold nos 60% piores antes do flop e voce ja esta na frente de todo calling station da plataforma. Selecao de maos iniciais e a maior melhoria que voce pode fazer.

def should_play(cards):
    """Return True for top ~40% of starting hands."""
    ranks = "23456789TJQKA"
    r1 = ranks.index(cards[0][0])
    r2 = ranks.index(cards[1][0])
    high, low = max(r1, r2), min(r1, r2)
    pair = r1 == r2
    suited = cards[0][1] == cards[1][1]
 
    if pair: return True                    # All pairs
    if high >= 10: return True              # Any two broadway
    if high >= 9 and suited: return True    # Suited connectors 9+
    if high == 12 and low >= 7: return True # A7+
    return False

Guarde suas hole cards quando receber hole_cards, depois verifique should_play() no seu handler de your_turn. Fold em todo o resto pre-flop.

2. Raise nas maos fortes

O calling station nunca da raise. Isso significa que os oponentes veem flops baratos contra voce em toda mao. Correcao: raise com seus 15% mais fortes de maos pre-flop.

if "raise" in actions and should_raise(my_cards):
    await ws.send(json.dumps({
        "type": "action",
        "action": "raise",
        "amount": actions["raise"]["min"],  # minimum raise
        "client_action_id": next_id(),
        "turn_token": msg["turn_token"],
    }))

A entrada raise em valid_actions te diz os valores exatos de min e max. O campo amount e um valor de raise-to (tamanho total da aposta), nao um incremento. Se o big blind e 20 e voce quer dar raise pra 60, mande "amount": 60.

3. Use pot odds pos-flop

Depois do flop, voce tem informacao real. Pot odds dizem se dar call e matematicamente correto: se o preco que voce ta pagando e menor que sua probabilidade de ganhar, call. Senao, fold. Pra a matematica completa, a entrada do glossario de pot odds tem exemplos resolvidos e armadilhas que pegam bots iniciantes.

def pot_odds_say_call(pot, call_amount, estimated_win_pct=0.3):
    if call_amount == 0:
        return True
    odds = call_amount / (pot + call_amount)
    return estimated_win_pct > odds

Ate uma estimativa grosseira da sua probabilidade de vitoria (30% como padrao, maior com top pair, menor sem nada) combinada com pot odds ganha do calling station puro por uma margem grande. A mensagem your_turn inclui o tamanho atual do pot, entao voce tem tudo que precisa.

O que aprendemos rodando esse bot

Eu rodei o calling station por mais de 1.200 maos pra ter um baseline real. Ele perdeu 2,4 big blinds a cada 100 maos — nao catastrofico, mas um dreno constante. O maior vazamento nao era dar call em apostas demais. Era dar call em apostas do river sem nada. O calling station nao tem o conceito de "eu nao acertei nada e essa aposta e grande em relacao ao pot"; ele so da call, toda vez, e sangra.

A segunda coisa que me surpreendeu: cooldowns de auto-rebuy importam mais do que voce imagina. Depois de quebrar, tem um cooldown de 5 minutos no plano gratuito (2 minutos no Pro) antes do proximo rebuy. Um bot que quebra frequentemente passa muito tempo parado. Acertar o gerenciamento de stack (nao quebrar de primeira) tem retornos compostos alem de so conservar fichas.

Adicionar should_play() da secao acima derrubou a taxa de perda pra cerca de 0,8 bb/100 nos nossos testes — uma melhoria de 3x com uma funcao. O bot ainda perde, mas agora perde como um jogador mediocre em vez de um quebrado. Esse e o ponto de partida pra trabalho real de estrategia.

Nao estamos alegando que esses sao tamanhos de amostra rigorosos. A variancia em 6-max e alta, e 1.200 maos e uma janela pequena. Mas direcionalmente, o padrao e consistente: selecao pre-flop e a primeira alavanca, agressividade pos-flop e a segunda.

O que esperar no leaderboard

Com o calling station base, voce vai terminar la embaixo no leaderboard. Adicione as tres melhorias acima e voce fica no meio. Pra chegar ao topo, voce vai precisar de avaliacao de maos, modelagem de oponentes, gerenciamento de stack e consciencia de posicao. O caminho completo esta documentado no plano de 7 dias pro leaderboard.

Seu bot precisa de pelo menos 10 maos pra aparecer no leaderboard. Com jogo continuo e auto-rebuy ligado, voce chega la em poucos minutos.

A documentacao completa da plataforma esta em docs.openpoker.ai. O guia de acoes e estrategia cobre semantica de raise, turn tokens e comportamento de timeout em detalhe. A documentacao da biblioteca websockets vale a leitura se voce quiser tratamento de conexao async alem do basico mostrado aqui.

FAQ

Meu bot conecta mas nunca senta numa mesa. O matchmaker precisa de 2+ jogadores na fila. Se ninguem mais ta jogando, seu bot espera. Rode dois bots com API keys diferentes, ou confira o leaderboard pra ver se tem outros ativos.

Estou recebendo erros action_rejected. Verifique se voce ta incluindo turn_token da mensagem your_turn mais recente. Tokens velhos sao a causa #1 de rejeicoes. Nao faca cache do token entre as rodadas.

Meu bot desconectou e perdeu o assento. Voce tem 120 segundos pra reconectar. Se reconectar a tempo, seu assento e preservado. Depois de 120 segundos, seu stack volta pro seu saldo e voce precisa reentrar no lobby.

Posso rodar esse bot 24/7? Sim. Ative auto-rebuy e trate table_closed + season_ended reentrando no lobby. O bot desse post faz as duas coisas. A gente rodou ele por periodos de varios dias sem nenhuma intervencao.

Quanto devo comprar de buy-in? O range valido e de 1.000 a 5.000 fichas. Usamos 2.000 nos exemplos (100 big blinds com blinds 10/20), que e um valor padrao de deep-stack. Comprar menos (1.000) reduz variancia mas tambem limita quanto voce pode ganhar numa unica mao. Comprar mais (5.000) e ok quando seu bot tem uma estrategia basica de fold/raise; nao faca isso com um calling station puro.


Pronto pra rodar seu primeiro bot? Registre-se pra uma API key e voce vai jogar maos em cinco minutos. O calling station e um bom ponto de partida; todo bot competitivo no leaderboard comecou de um jeito parecido.

Continue Lendo