Last active
September 30, 2017 17:20
-
-
Save gcampfield/be5b6e22744f6f1f34179e1ab233056e to your computer and use it in GitHub Desktop.
A script to generate Dota pick/ban tables
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import requests | |
# ---------- CONSTANTS ---------- | |
OPTIC_ID = 5026801 | |
RADIANT = 0 | |
DIRE = 1 | |
NONE = 2 | |
SEP = '\n***\n' | |
heroes_url = 'https://www.trackdota.com/static/names.json' | |
heroes = requests.get(heroes_url).json().get('heroes') | |
hashes = { | |
'OpTic Gaming': '#optic', | |
'Immortals': '#immortals', | |
} | |
# ---------- UTILITIES ---------- | |
def safe_get(l, i, default=None): | |
try: | |
return l[i] | |
except IndexError: | |
return default | |
def time_str(time): | |
if time is None: | |
return '' | |
if time < 0: | |
return '-' | |
minutes = time // 60 | |
seconds = time % 60 | |
return str(minutes) + ":" + str(seconds).zfill(2) | |
# ---------- GETTERS/SETTERS ---------- | |
# data | |
def get_core_data(game_id): | |
core_url = 'https://www.trackdota.com/data/game/%s/core.json' % game_id | |
return requests.get(core_url).json() | |
def get_live_data(game_id): | |
live_url = 'https://www.trackdota.com/data/game/%s/live.json' % game_id | |
return requests.get(live_url).json() | |
# heroes | |
def get_hero(player): | |
hero_id = player.get('hero_id', 0) | |
if type(hero_id) != int: | |
hero_id = 0 | |
player['hero_name'] = safe_get(heroes, hero_id, '<Unknown>') | |
def get_heroes(players): | |
for player in players: | |
get_hero(player) | |
return players | |
# pickbans | |
def get_pickbans(team, core_data): | |
side = team['side'] | |
team['picks'] = get_heroes(core_data.get(side + '_picks', [])) | |
team['bans'] = get_heroes(core_data.get(side + '_bans', [])) | |
# stats | |
def get_player_stats(player, player_stats): | |
if 'account_id' not in player: | |
return | |
player_id = player['account_id'] | |
for stats in player_stats: | |
if stats.get('account_id', 0) == player_id: | |
player['stats'] = stats | |
def get_stats(players, live_data): | |
get_heroes(players) | |
radiant_stats = live_data.get('radiant', {}).get('players', {}) | |
dire_stats = live_data.get('dire', {}).get('players', {}) | |
for player in players: | |
if 'team' not in player: | |
continue | |
if player['team'] == DIRE: | |
get_player_stats(player, dire_stats) | |
elif player['team'] == RADIANT: | |
get_player_stats(player, radiant_stats) | |
# events | |
def get_events(log): | |
barracks = {} | |
towers = {} | |
winner = None | |
for event in log: | |
if 'action' in event and 'delta' in event and 'timestamp' in event: | |
if event['action'] == 'barracks': | |
barracks[event['delta']] = event['timestamp'] | |
elif event['action'] == 'tower': | |
towers[event['delta']] = event['timestamp'] | |
elif event['action'] == 'win': | |
if event['delta'] == 0: | |
winner = ('radiant', event['timestamp']) | |
else: | |
winner = ('dire', event['timestamp']) | |
return barracks, towers, winner | |
RADIANT = 0 | |
DIRE = 1 | |
SIDE = 0 | |
TIME = 1 | |
def set_winner(optic, opp, winner): | |
if not winner: return | |
if winner[SIDE] == optic['side']: | |
optic['win_time'] = winner[TIME] | |
else: | |
opp['win_time'] = winner[TIME] | |
LANES = 3 | |
TIERS = 4 | |
def get_tower_index(side, lane, tier): | |
if tier == TIERS-1: | |
if lane == 1: return -1 # mid lane has no tier 4 | |
return 9 + (side == 'dire') * 11 + (lane == 2) | |
offset = lane * 3 + tier | |
if side == 'radiant': | |
offset += 11 | |
return offset | |
def get_barrack_index(side, lane, barrack): | |
offset = lane * 2 + barrack | |
if side == 'radiant': | |
offset += 6 | |
return offset | |
def get_towers(towers): | |
radiant_towers = [] | |
dire_towers = [] | |
for tier in range(TIERS): | |
radiant_tier = [] | |
dire_tier = [] | |
for lane in range(LANES): | |
index = get_tower_index('radiant', lane, tier) | |
if index < 0: radiant_tier.append(index) | |
else: radiant_tier.append(towers.get(index, None)) | |
index = get_tower_index('dire', lane, tier) | |
if index < 0: dire_tier.append(index) | |
else: dire_tier.append(towers.get(index, None)) | |
radiant_towers.append(radiant_tier) | |
dire_towers.append(dire_tier) | |
return radiant_towers, dire_towers | |
BARRACKS = 2 | |
def get_barracks(barracks): | |
radiant_barracks = [] | |
dire_barracks = [] | |
for barrack in range(BARRACKS): | |
radiant_tier = [] | |
dire_tier = [] | |
for lane in range(LANES): | |
index = get_barrack_index('radiant', lane, barrack) | |
radiant_tier.append(barracks.get(index, None)) | |
index = get_barrack_index('dire', lane, barrack) | |
dire_tier.append(barracks.get(index, None)) | |
radiant_barracks.append(radiant_tier) | |
dire_barracks.append(dire_tier) | |
return radiant_barracks, dire_barracks | |
# ---------- OUTPUT ---------- | |
def it(s): | |
return '*' + str(s) + '*' | |
def bold(s): | |
return '**' + str(s) + '**' | |
def strike(s): | |
return '~~' + str(s) + '~~' | |
# pickbans | |
def print_pickban_header(optic, opp): | |
dire, radiant = '[](#dire) Dire', '[](#radiant) Radiant' | |
if optic['side'] == 'radiant': | |
a, b = radiant, dire | |
else: | |
a, b = dire, radiant | |
top_line = "%s|[%s](%s)|vs|[%s](%s)|%s\n" % \ | |
(a, optic['team_name'], optic['hash'], opp['team_name'], opp['hash'], b) | |
print(top_line + \ | |
":--|:--|:-:|--:|--:\n" + \ | |
"**Bans**|**Picks**|**#**|**Picks**|**Bans**") | |
def print_pickban_line(row, p1, b1, p2, b2): | |
info = [] | |
info.append(strike(b1['hero_name'])) | |
info.append(p1['hero_name']) | |
info.append(bold(row)) | |
info.append(p2['hero_name']) | |
info.append(strike(b2['hero_name'])) | |
print('|'.join(info)) | |
def print_pickban_table(optic, opp): | |
print_pickban_header(optic, opp) | |
row = 1 | |
data = zip(optic['picks'], optic['bans'], opp['picks'], optic['bans']) | |
for og_p, og_b, opp_p, opp_b in data: | |
print_pickban_line(row, og_p, og_b, opp_p, opp_b) | |
row += 1 | |
# stats | |
def print_stats_header(): | |
print("Hero|Player|K/D/A|LH/D| # |LH/D|K/D/A|Player|Hero\n" + \ | |
":---|:-----|:---:|:--:|:-:|:--:|:---:|-----:|---:") | |
def kda(player): | |
stats = player['stats'] | |
return '%s/%s/%s' % (stats['kills'], stats['death'], stats['assists']) | |
def lhd(player): | |
stats = player['stats'] | |
return '%s/%s' % (stats['last_hits'], stats['denies']) | |
def print_stats_line(og_player, opp_player, row): | |
info = [] | |
info.append(og_player['hero_name']) | |
info.append(bold(og_player['name'])) | |
info.append(kda(og_player)) | |
info.append(lhd(og_player)) | |
info.append(bold(row)) | |
info.append(lhd(opp_player)) | |
info.append(kda(opp_player)) | |
info.append(bold(opp_player['name'])) | |
info.append(opp_player['hero_name']) | |
print('|'.join(info)) | |
def print_stats_table(optic, opp): | |
print_stats_header() | |
row = 1 | |
data = zip(optic['players'], opp['players']) | |
for og_player, opp_player in data: | |
print_stats_line(og_player, opp_player, row) | |
row += 1 | |
# events | |
def print_events_header(optic, opp): | |
top_line = "[%s](%s)|Top|Middle|Bottom||Bottom|Middle|Top|[%s](%s)\n" % \ | |
(optic['team_name'], optic['hash'], opp['team_name'], opp['hash']) | |
print(top_line + \ | |
":-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:") | |
buildings = ['T1', 'T2', 'T3', 'Melee', 'Ranged', 'T4'] | |
def print_event_line(og_buildings, opp_buildings, row): | |
info = [] | |
info.append(bold(buildings[row])) | |
for building in og_buildings: | |
info.append(time_str(building)) | |
info.append('') | |
for building in opp_buildings: | |
info.append(time_str(building)) | |
info.append(bold(buildings[row])) | |
print('|'.join(info)) | |
def print_winner_line(optic, opp): | |
info = [] | |
info.append(bold('Ancient')) | |
info.append('-') | |
info.append(time_str(optic.get('win_time', None))) | |
info.append('-') | |
info.append('') | |
info.append('-') | |
info.append(time_str(opp.get('win_time', None))) | |
info.append('-') | |
info.append(bold('Ancient')) | |
print('|'.join(info)) | |
def print_events_table(optic, opp): | |
print_events_header(optic, opp) | |
row = 0 | |
data = zip(optic['towers'][:-1], opp['towers'][:-1]) | |
for og_towers, opp_towers in data: | |
print_event_line(og_towers, reversed(opp_towers), row) | |
row += 1 | |
data = zip(optic['barracks'], opp['barracks']) | |
for og_barracks, opp_barracks in data: | |
print_event_line(og_barracks, reversed(opp_barracks), row) | |
row += 1 | |
print_event_line(optic['towers'][-1], opp['towers'][-1], row) | |
print_winner_line(optic, opp) | |
# ---------- MAIN ---------- | |
if __name__ == '__main__': | |
# game_id = int(input('dota game id: ')) | |
game_id = 3475184410 | |
core_data = get_core_data(game_id) | |
live_data = get_live_data(game_id) | |
radiant_team = core_data.get('radiant_team', {}) | |
dire_team = core_data.get('dire_team', {}) | |
if 'team_name' not in radiant_team: | |
radiant_team['team_name'] = 'Radiant' | |
if 'team_name' not in dire_team: | |
dire_team['team_name'] = 'Dire' | |
players = core_data.get('players', []) | |
radiant_players = filter(lambda p: p.get('team', NONE) == RADIANT, players) | |
dire_players = filter(lambda p: p.get('team', NONE) == DIRE, players) | |
get_stats(radiant_players, live_data) | |
get_stats(dire_players, live_data) | |
log = live_data.get('log', []) | |
barracks, towers, winner = get_events(log) | |
radiant_towers, dire_towers = get_towers(towers) | |
radiant_barracks, dire_barracks = get_barracks(barracks) | |
if radiant_team.get('team_id', 0):# == OPTIC_ID: | |
optic = radiant_team | |
opp = dire_team | |
opp['players'] = dire_players | |
opp['side'] = 'dire' | |
optic['players'] = radiant_players | |
optic['towers'] = dire_towers | |
optic['barracks'] = dire_barracks | |
opp['towers'] = radiant_towers | |
opp['barracks'] = radiant_barracks | |
optic['side'] = 'radiant' | |
elif dire_team.get('team_id', 0) == OPTIC_ID: | |
optic = dire_team | |
opp = radiant_team | |
opp['players'] = radiant_players | |
opp['side'] = 'radiant' | |
optic['players'] = dire_players | |
optic['towers'] = radiant_towers | |
optic['barracks'] = radiant_barracks | |
opp['towers'] = dire_towers | |
opp['barracks'] = dire_barracks | |
optic['side'] = 'dire' | |
else: | |
print('OpTic can\'t be detected in this match...') | |
exit(1) | |
optic['team_name'] = 'OpTic Gaming' | |
get_pickbans(optic, core_data) | |
get_pickbans(opp, core_data) | |
opp['hash'] = hashes.get(opp.get('team_name', ''), '#blank') | |
optic['hash'] = '#optic' | |
set_winner(optic, opp, winner) | |
print_pickban_table(optic, opp) | |
print(SEP) | |
print_stats_table(optic, opp) | |
print(SEP) | |
print_events_table(optic, opp) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment