In [1]:
import pymongo
import json

db = pymongo.MongoClient('mongodb://data.sberbank.ai/holdem_games').get_database('holdem_games')
Число игр в базе данных

In [2]:
db.games.count()


Out[2]:
1295
Число игр с непрерывного турнира

In [3]:
db.games.find({'label': 'default'}).count()


Out[3]:
0
Первая попавшаяся игра от определенного игрока

In [4]:
game = db.games.find_one({
    'label': 'online', 
    'seats.name': 'aWrsILaeY0LdPPwlX2pZlx',
})

Структура реплея игры

{
  # название турнира, возможные значения
  #   - online:  сабмиты из он-лайн этапа
  #   - default: непрерывный турнир во время хакатона
  #   - final:   игры первого этапа финала
  "label": "online",  

  # время начала игры (unix timestamp)
  "timestamp": 1506150447.5848944,

  # время игры в секундах
  "duration": 111.707551,

  # параметры правил игры
  "rule": {
    "max_round": 50,
    "ante": 0,
    "blind_structure": {},
    "initial_stack": 1500,
    "small_blind_amount": 15
  },

  # информация о серии игр
  "series": {
    "id": "8eacd808a02d11e79d500242ac12000a" # уникальный идентификатор серии игр
    "start_time": 1506150318.5754483,        # время начала серии игр
    "game": 0,                               # номер игры в серии

  }

  # список участников игры в порядке их расположения за столом
  "seats": [
    {
      # уникальный идентификатор команды, чей бот играет
      "name": "The Team",

      "uuid": "jcaitizqrnclxcjlykmtee", # идентификатор бота внутри конкретной игры

      # число фишек 
      "stack": 1185,        # к концу игры
      "start_stack": 1500,  # в начале игры

      "bot": {
        "failed": false,          # true, если бот был упавшим во время игры
        "failed_at_start": false, # true, если бот был упавшим в начале игры 
                                  # (такое может произойти, если бот упал во время одной из игр )

        # кусок вывода stdout (может быть использован для определения ошибки)
        "log": "2017-09-23 07:05:46.655460: W tensorflow/core/platform/cpu_feature_guard.cc:45] The TensorFlow library wasn't compiled to use SSE4.1 instructions, but these are available on your machine and could speed up CPU computations.\n2017-09-23 07:05:46.655498: W tensorflow/core/platform/cpu_feature_guard.cc:45] The TensorFlow library wasn't compiled to use SSE4.2 instructions, but these are available on your machine and could speed up CPU computations."
      },

      # максимальный нормер раунда, в котором участник все еще был за столом
      "max_participating_round": 50,
    },
    {
      "name": "Another Team",

       "uuid": "snygzfpttfhvanlrqouuqw",

      "stack": 960,
      "start_stack": 1500,

      "bot": {
        "failed": true,
        "failed_at_start": false,
        "fail_reason": "invalid_action (invalid amount for action raise, allowed 30..1005, requested 16)"
        "log": "",
      },
      "max_participating_round": 50,      
    },
    ...
  ],

  # описание раундов
  "rounds": [
    "round_count": 0, # порядковый номер раунда

    # описание действий в раунде
    "round_state": {
      "small_blind_pos": 1,     # индекс игрока, у которого малый блайнд
      "big_blind_pos": 2,       # индекс игрока, у которого большой блайнд
      "small_blind_amount": 15, # размер малого блайнда

      "seats": [], # состояние участников на начало раунда

      # общие карты в раунде
      "community_card": ["ST", "D8", "DA", "SJ", "D3"],

      # последовательность действий на каждой улице
      "action_histories": {
        "preflop": [ ... ],
        "flop": [ ... ],
        "turn": [
          # описание хода
          {
            "uuid": "wgoxzmaarejoofxefygmth", # uuid игрока (по нему можно узнать имя команды в seats)
            "action": "CALL",         # действие: CALL, RAISE или FOLD
            "paid": 0,                # сколько фишел уже было поставлено до хода
            "amount": 0               # сколько фишек поставлено на текущем ходе
            "bot": {
              "failed": false,        # true, если действие сделал не бот, а симулятор (авто сброс)
              "valid_actions": {...}, # список доступных действий (как он подается в stdin)
              "time_bank": 300,       # секунд осталось в тайм-банке
              "line": "call\t0",      # строка, которую бот отправил в симулятор
              "time_elapsed": 0.0006890296936035156 # секунд потрачено на ход
            },
          },
        ],
      },      
    },

    # список победителей раунда
    "winners": [
      {
        "name": "uq8h3B2GrcoY2Ra~87aW63",
        "uuid": "xtatrrkuwyigoondrtaeia",
        "stack": 2550,
        "state": "participating"
      }
    ],
  ],
}

Построение таблицы результатов


In [5]:
import pandas

In [6]:
results = db.games.find(
    {'label': 'online'},
    projection=['seats', 'timestamp', 'duration', 'series'],
)

df_participant_results = pandas.DataFrame.from_records([
    {
        'timestamp': result['timestamp'],
        'duration': result['duration'],
        'series_id': result['series']['id'],
        'series_time': result['series']['start_time'],
        'series_game': result['series']['game'],
        
        'name': seat['name'],
        'stack': seat['stack'],
        'failed': seat['bot']['failed'],
    }
    for result in results
    for seat in result['seats']
])

In [7]:
df_participant_results.head()


Out[7]:
duration failed name series_game series_id series_time stack timestamp
0 111.707551 False So1yg6nEYSCUJ2HtQEACZb 0 8eacd808a02d11e79d500242ac12000a 1.506150e+09 1185 1.506150e+09
1 111.707551 False aWrsILaeY0LdPPwlX2pZlx 0 8eacd808a02d11e79d500242ac12000a 1.506150e+09 0 1.506150e+09
2 111.707551 True wyBKNCWdd1HkVxhmnNoeqQ 0 8eacd808a02d11e79d500242ac12000a 1.506150e+09 960 1.506150e+09
3 111.707551 False eftkdK5uRZgtu78T0o8fW9 0 8eacd808a02d11e79d500242ac12000a 1.506150e+09 0 1.506150e+09
4 111.707551 False o_mo4SbWWSXfMcmuQzpywV 0 8eacd808a02d11e79d500242ac12000a 1.506150e+09 2130 1.506150e+09

In [8]:
g = df_participant_results.groupby('name')
df_leaderboard = pandas.DataFrame({
    'games': g['series_game'].count(),
    'failed_percent': g['failed'].mean(),
    'avg_stack': g['stack'].mean(),
}).sort_values('avg_stack', ascending=False)

In [9]:
df_leaderboard.head()


Out[9]:
avg_stack failed_percent games
name
uq8h3B2GrcoY2Ra~87aW63 4604.211111 0.0 90
iti9mUPtzIB8OixZNMhUwM 4580.850000 0.0 40
wWc3yQaWLh7F9lqPH7xWgk 4492.327869 0.0 61
v_lfvjaCeJfpbPhayTvKow 3874.737500 0.0 80
bB3x~e3JCksmqNA1dHc8Aq 3843.037500 0.0 80
Таблицу можно сохранить в CSV или в Excel

In [10]:
df_leaderboard.to_csv('leaderboard.csv')
df_leaderboard.to_excel('leaderboard.xlsx')