Skip to content

Instantly share code, notes, and snippets.

@szarroug3
Last active August 21, 2020 01:23
Show Gist options
  • Save szarroug3/1ed00854f363a719c52c00725926bc11 to your computer and use it in GitHub Desktop.
Save szarroug3/1ed00854f363a719c52c00725926bc11 to your computer and use it in GitHub Desktop.
analyze_dota_matches.py
import json
import os
import requests
from argparse import ArgumentParser
from collections import defaultdict
from time import sleep
OPENDOTA_BASE_URL = 'https://api.opendota.com/api/{func_name}/{params}'
def opendota_api_call(func_name, *params):
for retry in range(1, 6):
resp = requests.get(OPENDOTA_BASE_URL.format(func_name=func_name, params='/'.join(params)))
if resp.ok:
break
sleep(20)
print('Retry #{}'.format(retry))
if not resp.ok:
raise Exception('Something went wrong: GET {}: {} {}'.format(func_name, resp.status_code, resp.reason))
return resp.json()
def parse_match(match, data={}):
for player in match['players']:
name = '{} ({})'.format(player['personaname'], player['account_id'])
player_data = data.get(name, defaultdict(list))
building_damage = 0
for building, damage in player['damage'].items():
if 'npc_dota_goodguys' not in building:
continue
if 'tower' not in building and 'rax' not in building:
continue
building_damage += damage
player_data['heroes'] += [player['hero_id']]
player_data['kills'] += [player['kills']]
player_data['deaths'] += [player['deaths']]
player_data['assists'] += [player['assists']]
player_data['gpm'] += [player['gold_per_min']]
player_data['kda'] += [player['kda']]
player_data['cs'] += [player['last_hits']]
player_data['building_damage'] += [building_damage]
player_data['deaths_to_techies'] += [player['killed_by'].get('npc_dota_hero_techies', 0)]
player_data['win'] += [player['win']]
player_data['games_played'] = player_data['games_played'] + 1 if player_data['games_played'] else 1
data[name] = player_data
return data
def parse_matches(matches):
unparsed = []
parsed = {}
not_found = []
for match in matches:
try:
fname = os.path.join('match_cache', '{}.json'.format(match))
if not os.path.exists('match_cache'):
os.makedirs('match_cache')
if os.path.exists(fname):
with open(fname) as f:
data = json.load(f)
else:
data = opendota_api_call('matches', match)
with open(fname, 'w') as f:
json.dump(data, f)
except:
not_found.append(match)
continue
if not data.get('picks_bans'):
unparsed.append(match)
continue
parsed = parse_match(data, data=parsed)
return unparsed, parsed, not_found
def get_midas_touch(data):
winner = None
value = -1
for player, player_data in data.items():
if player_data['games_played'] < 5:
continue
player_value = float(sum(player_data['gpm'])) / player_data['games_played']
if player_value > value:
value = player_value
winner = player
elif player_value == value:
winner = '{}, {}'.format(winner, player)
return '{} - {}'.format(winner, int(value))
def get_scorched_earth(data):
winner = None
value = -1
for player, player_data in data.items():
if player_data['games_played'] < 5:
continue
player_value = float(sum(player_data['kda'])) / player_data['games_played']
if player_value > value:
value = player_value
winner = player
elif player_value == value:
winner = '{}, {}'.format(winner, player)
return '{} - {}'.format(winner, int(value))
def get_hero_puddler(data):
winner = None
value = 500
for player, player_data in data.items():
if player_data['games_played'] < 5:
continue
player_value = len(set(player_data['heroes']))
if player_value < value:
value = player_value
winner = player
elif player_value == value:
winner = '{}, {}'.format(winner, player)
return '{} - {}'.format(winner, value)
def get_ocean(data):
winner = None
value = -1
for player, player_data in data.items():
player_value = len(set(player_data['heroes']))
if player_value > value:
value = player_value
winner = player
elif player_value == value:
winner = '{}, {}'.format(winner, player)
return '{} - {}'.format(winner, value)
def get_no_thoughts_head_empty(data):
winner = None
value = -1
for player, player_data in data.items():
player_value = float(sum(player_data['cs'])) / player_data['games_played']
if player_value > value:
value = player_value
winner = player
elif player_value == value:
winner = '{}, {}'.format(winner, player)
return '{} - {}'.format(winner, int(value))
def get_carty_b_award(data):
winner = None
value = -1
for player, player_data in data.items():
player_value = float(sum(player_data['building_damage'])) / player_data['games_played']
if player_value > value:
value = player_value
winner = player
elif player_value == value:
winner = '{}, {}'.format(winner, player)
return '{} - {}'.format(winner, int(value))
def get_minesweeper(data):
winner = None
value = -1
for player, player_data in data.items():
player_value = float(sum(player_data['deaths_to_techies'])) / player_data['games_played']
if player_value > value:
value = player_value
winner = player
elif player_value == value:
winner = '{}, {}'.format(winner, player)
return '{} - {}'.format(winner, int(value))
def get_space_creator(data):
winner = None
value = -1
for player, player_data in data.items():
player_value = max([d for d in player_data['deaths'] if player_data['win']])
if player_value > value:
value = player_value
winner = player
elif player_value == value:
winner = '{}, {}'.format(winner, player)
return '{} - {}'.format(winner, value)
def get_i_like_the_cha_ching_sound(data):
winner = None
value = -1
for player, player_data in data.items():
player_value = max(player_data['gpm'])
if player_value > value:
value = player_value
winner = player
elif player_value == value:
winner = '{}, {}'.format(winner, player)
return '{} - {}'.format(winner, value)
def get_kills_secured(data):
winner = None
value = -1
for player, player_data in data.items():
player_value = max(player_data['kills'])
if player_value > value:
value = player_value
winner = player
elif player_value == value:
winner = '{}, {}'.format(winner, player)
return '{} - {}'.format(winner, value)
def get_its_okay_take_the_kills(data):
winner = None
value = -1
for player, player_data in data.items():
player_value = max(player_data['assists'])
if player_value > value:
value = player_value
winner = player
elif player_value == value:
winner = '{}, {}'.format(winner, player)
return '{} - {}'.format(winner, value)
def get_me_hit_creep(data):
winner = None
value = -1
for player, player_data in data.items():
player_value = max(player_data['cs'])
if player_value > value:
value = player_value
winner = player
elif player_value == value:
winner = '{}, {}'.format(winner, player)
return '{} - {}'.format(winner, value)
def get_objective_gamer(data):
winner = None
value = -1
for player, player_data in data.items():
player_value = max(player_data['building_damage'])
if player_value > value:
value = player_value
winner = player
elif player_value == value:
winner = '{}, {}'.format(winner, player)
return '{} - {}'.format(winner, value)
def get_args():
parser = ArgumentParser()
parser.add_argument('-m', '--match', action='append')
return parser.parse_args()
def process(match):
unparsed, parsed, not_found = parse_matches(match)
if unparsed:
print('The following matches were not parsed by opendota: {}\n'.format(', '.join(unparsed)))
if not_found:
print('The following matches were not found by opendota: {}\n'.format(', '.join(not_found)))
print('Midas Touch - Highest GPM over season (5 game minimum): {}'.format(get_midas_touch(parsed)))
print('Scorched Earth - Best KDA during season (5 game minimum): {}'.format(get_scorched_earth(parsed)))
print('Hero Puddler - Least diverse (5 games minimum): {}'.format(get_hero_puddler(parsed)))
print('Ocean this probably doesnt need a minimum : {}'.format(get_ocean(parsed)))
print('No thoughts head empty (most cs in the season): {}'.format(get_no_thoughts_head_empty(parsed)))
print('Carty B Award (Most building damage): {}'.format(get_carty_b_award(parsed)))
print('Minesweeper (player most killed by techies): {}'.format(get_minesweeper(parsed)))
print('Space Creator - Most Deaths in a win: {}'.format(get_space_creator(parsed)))
print('I like the Cha-Ching sound - Highest GPM in a Single Game: {}'.format(get_i_like_the_cha_ching_sound(parsed)))
print('Kill Secured - Most Kills in a Single Game: {}'.format(get_kills_secured(parsed)))
print('It\'s Okay, Take The Kills :) - Most Assists in a Single Game: {}'.format(get_its_okay_take_the_kills(parsed)))
print('ME HIT CREEP - Most Last Hits in a Single Game: {}'.format(get_me_hit_creep(parsed)))
print('Objective Gamer - Most Building Damage in a Single Game: {}'.format(get_objective_gamer(parsed)))
if __name__ == '__main__':
process(**vars(get_args()))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment