Sample Code 2

This example Python script is a bit more complete than the previous one but is not standalone. It also shows how to make calls to a C library.

import argparse
import ctypes
import os
import re
import sys
import threading

import requests

from .constants import *
from .util import card_string_to_code, pb_to_lib_format



# If |bet| is None, we just read the current hand state. It is useful at
# the hand's start, as GTO King might play first (and we want to know his move).
# Note that we need to pass |initial_stack| everytime because a same bot can
# play in different formats.
def play(token, initial_stack, bet):
    data = {
        'token': token,
        'initialStacks': [initial_stack, initial_stack],
    if bet is not None:
        data['bet'] = bet
    response =, headers={}, json=data)
    success = getattr(response, 'status_code') == 200
    if not success:
        print('Status code: %s' % repr(response.status_code))
            print('Error response: %s' % repr(response.json()))
        except ValueError:
        r = response.json()
    except ValueError:
        print('Could not get JSON from response')
    if 'error' in r:
        print('Error: %s' % r['error'])
    return r

# This utility can be used to replay the whole history as well. We would have to
# transmit |initial_stack|, |position| and |hole_cards| to do so.
# It is be useful if the bot is very fast and we want the playing robust to
# interruptions.
def replay_history(ai, history):
    sub_histos = history.split('/')
    for i, sub_histo in enumerate(sub_histos):
        # Sequence of bets or board cards.
        if i % 2 == 0:
            bets = re.findall(r'b(\d+)', sub_histo)
            for bet in bets:
                bet = int(bet)
                ai.ReceiveAction(CLIENT_ID, bet)
            assert len(sub_histo) % 2 == 0
            cards = [
                sub_histo[i:i + CARD_LEN]
                for i in range(0, len(sub_histo), CARD_LEN)
            cards = pb_to_lib_format(cards)
            assert len(cards) in [1, 3]
            ai.ReceiveNewPublicCards(CLIENT_ID, cards, len(cards))

def play_hand(ai, token, initial_stack):
    r = play(token, initial_stack, None)
    #  print(r)
    position = r.get('position')
    hole_cards = r.get('hole_cards')
    # Unlike Slumbot, our convention is 0 = SB, 1 = BB.
    is_bb = position == 1
    ai.InitHand(CLIENT_ID, initial_stack, card_string_to_code(hole_cards[0]),
                card_string_to_code(hole_cards[1]), is_bb)
    # A previous duel was interrupted. Giving up the last hand by check/folding
    # (if replaying the whole history is not supported).
    if r.get('history').count('b') > 1:
        print("Check/folding until hand's end..")
        # GTO King should not return an outcome if we didn't send an action
        # (except if it was SB and immediately folded, but in such a case there
        # is no more than one 'b' in |history|).
        assert 'oucome' not in r
        while True:
            if 'outcome' in r:
                return r['outcome'], r['avg_outcome']
            last_street_bets = r.get('history').split('/')[-1]
            last_bets = re.findall(r'b(\d+)', last_street_bets)
            our_last_bet = 0 if len(last_bets) < 2 else last_bets[-2]
            r = play(token, initial_stack, our_last_bet)
        # Not reached.
    prev_history = ''
    while True:
        history = r.get('history')
        if 'outcome' in r:
            return r['outcome'], r['avg_outcome']
        new_history = history[len(prev_history):]
        replay_history(ai, new_history)
        bet = ai.PlayAction(CLIENT_ID)
        #  print('Hero betted', bet)
        r = play(token, initial_stack, bet)
        prev_history = history + 'b' + str(bet)
    # Not reached.

def main():
    parser = argparse.ArgumentParser(description='Play versus GTO King')
    parser.add_argument('--token', type=str, required=True)
    args = parser.parse_args()
    token = args.token

    lib_path = os.path.join(os.getcwd(), 'build', 'lib',
    ai = ctypes.cdll.LoadLibrary(lib_path)
    t = threading.Thread(target=ai.Init,
                         args=((True, LIVE_SEARCH)),
    while t.is_alive():

    initial_stack = 50
    num_hands = 10
    session_result = 0
    for hand in range(num_hands):
        print('\n----------------- HAND %i -----------------' % (hand + 1))
        hand_result, lifetime_result = play_hand(ai, token, initial_stack)
        session_result += hand_result
    print('Total session:', session_result)
    print('Total lifetime:', lifetime_result)

if __name__ == '__main__':