Last active
August 29, 2015 14:22
-
-
Save andrewpatt24/e41a2b345405ced27280 to your computer and use it in GitHub Desktop.
"Dota 2 Game Prediction" submission to Hackerrank - 2nd in UK! (Code posted to Hackerrank is only bottom portion)
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
########################################################################################################## | |
## All below code is just calculation for each player type in game and there ELO from the training data ## | |
########################################################################################################## | |
################################################################ | |
## General ELO rating functions ################################ | |
################################################################ | |
def expected_score(own_rating,opp_rating): | |
return 1.0/(1.0+10.0**((float(opp_rating)-float(own_rating))/400.0)) | |
def adjustment(expected,actual,k=10.0): | |
return k*(actual-expected) | |
def actual_score(own_result,opp_result): | |
if own_result == opp_result: | |
return 0.5 | |
else: | |
return own_result | |
################################################################ | |
## function to calcualte newelo of a given player in array ##### | |
################################################################ | |
def new_player_elo(i,elos,results,k=10.0): | |
expected_array = [expected_score(elos[i],x) for x in elos] | |
actual_array = [actual_score(results[i],j) for j in results] | |
adjustment_array = [adjustment(e,a,k) for e,a in zip(expected_array,actual_array)] | |
return float(elos[i]) + sum(adjustment_array) | |
############################################################ | |
## function to loop over above and get array of new ELOs ### | |
############################################################ | |
def new_elos(elos,results,k=10): | |
return [new_player_elo(i,elos,results,k) for i in range(0,len(results))] | |
######################################################################## | |
## Function to create results array from single value in data ########## | |
######################################################################## | |
def get_results(result): | |
if result == 1: | |
return [1.0,1.0,1.0,1.0,1.0,0.0,0.0,0.0,0.0,0.0] | |
else: | |
return [0.0,0.0,0.0,0.0,0.0,1.0,1.0,1.0,1.0,1.0] | |
##################################################################################### | |
## Gets ELOS from player dictionary and adds new players to dictionary if needed #### | |
##################################################################################### | |
def get_elos(new_players,player_dict): | |
output = [] | |
for player in new_players: | |
try: | |
output.append(player_dict['elo'][player_dict['players'].index(player)]) | |
except ValueError: | |
player_dict['players'].append(player) | |
player_dict['elo'].append(4000) | |
output.append(4000) | |
return (output,player_dict) | |
def update_elos(player_dict,player_array,new_player_elos): | |
for i in range(len(player_array)): | |
player_dict['elo'][player_dict['players'].index(player_array[i])] = new_player_elos[i] | |
return player_dict | |
def parse_match_data(): | |
raw_data = f.readline().strip().split(',') | |
players = raw_data[0:10] | |
results = int(raw_data[10]) | |
return players, results | |
############################### | |
## Run through one match ###### | |
############################### | |
def rate_one_match(player_dict,k=10.0): | |
player_array, result = parse_match_data() | |
player_elos, player_dict = get_elos(player_array,player_dict) | |
result_array = get_results(result) | |
new_player_elos = new_elos(player_elos,result_array,k) | |
player_dict = update_elos(player_dict,player_array,new_player_elos) | |
print player_dict | |
return player_dict | |
## Start with a blank player_dict | |
player_dict = { | |
'players':[], | |
'elo':[] | |
} | |
print player_dict | |
loop_results = [] | |
##Need a range function that take floats | |
## Taken from : http://stackoverflow.com/questions/7267226/range-for-floats | |
def frange(x, y, jump): | |
while x < y: | |
yield x | |
x += jump | |
k_array = [x for x in frange(1.0,3.0,0.1)] | |
print k_array | |
for k in k_array: | |
results_of_test = 0.0 | |
with open('trainingdata.txt') as f: | |
for i in range(1000): | |
player_dict = rate_one_match(player_dict,k) | |
for i in range(500): | |
players, results = parse_match_data() | |
player_elos, player_dict = get_elos(players,player_dict) | |
if sum(player_elos[0:5]) > sum(player_elos[5:10]): | |
expected_result = 1 | |
else: | |
expected_result = 2 | |
if results == expected_result: | |
results_of_test += 1.0 | |
loop_results.append(results_of_test/500.0) | |
print zip(k_array,loop_results) | |
## Seems k = 2 is best | |
##build final_dict from all dataset | |
player_dict = { | |
'players':[], | |
'elo':[] | |
} | |
with open('trainingdata.txt') as f: | |
for i in range(1500): | |
player_dict = rate_one_match(player_dict,2.0) | |
print player_dict | |
############# | |
## Code to be put in Hackerrank | |
############# | |
final_player_dict = {'players': ['Sven', 'Lone Druid', 'Venomancer', 'Clockwerk', 'Shadow Shaman', 'Invoker', 'Gyrocopter', 'Anti-Mage', 'Alchemist', 'Slark', 'Riki', 'Tinker', 'Puck', 'Leshrac', 'Nyx Assassin', 'Slardar', 'Sand King', 'Spectre', 'Necrolyte', 'Warlock', 'Mirana', 'Pudge', 'Magnus', 'Keeper of the Light', 'Rubick', 'Tidehunter', 'Queen of Pain', 'Faceless Void', 'Sniper', 'Centaur Warrunner', 'Treant Protector', 'Broodmother', 'Weaver', 'Troll Warlord', 'Drow Ranger', 'Razor', 'Kunkka', 'Zeus', 'Bane', 'Visage', 'Timbersaw', 'Silencer', 'Meepo', 'Morphling', 'Omniknight', 'Crystal Maiden', 'Lina', 'Dark Seer', 'Brewmaster', 'Ogre Magi', 'Disruptor', 'Juggernaut', 'Tiny', 'Enigma', 'Bounty Hunter', 'Earthshaker', 'Doom', 'Huskar', 'Dazzle', 'Naga Siren', "Nature's Prophet", 'Chen', 'Ursa', 'Wisp', 'Lion', 'Batrider', 'Chaos Knight', 'Beastmaster', 'Windrunner', 'Luna', 'Phantom Lancer', 'Witch Doctor', 'Storm Spirit', 'Jakiro', 'Clinkz', 'Phantom Assassin', 'Shadow Fiend', 'Ancient Apparition', 'Viper', 'Templar Assassin', 'Dragon Knight', 'Skeleton King', 'Lifestealer', 'Undying', 'Death Prophet', 'Enchantress', 'Lich', 'Outworld Devourer', 'Bloodseeker', 'Spirit Breaker', 'Axe', 'Pugna', 'Vengeful Spirit', 'Lycanthrope', 'Medusa', 'Shadow Demon', 'Night Stalker'], 'elo': [3994.1631613177406, 3980.9980456540366, 3983.817796799303, 4007.3983513952376, 3987.9011164109133, 3983.9927612704514, 4044.623605438212, 3979.0912748530395, 3974.206350247612, 3990.678756840047, 3973.2907564878, 4002.0670271028566, 3989.2588098288393, 3998.817766883756, 4071.4912134580104, 3997.7825542921814, 4019.1843498210924, 3998.8105926231538, 4020.6579499341874, 4071.215459557408, 4057.9849476317554, 3971.2330692043834, 4038.6612245908686, 4057.0014792231455, 3961.021783998894, 4019.089120919476, 4002.444113269398, 3955.985904679837, 4032.10176172715, 4015.6224536253703, 3964.9419514334472, 3979.8664689487564, 4005.766970263955, 4022.169228823354, 4053.84476860488, 4029.236405163548, 4014.878355740683, 4050.2559304327074, 4002.304498522973, 4012.9537922024215, 3934.3179404974903, 4022.0071727416434, 3944.7645484796344, 3999.7210288874135, 4038.3157375644914, 4019.7879438084656, 3973.523198919531, 4006.536646491849, 3996.8696884250585, 4026.8479684733, 3987.689902950351, 3981.9865978169664, 3987.11244029581, 4015.343690713302, 3976.2676375079154, 3987.1504456024004, 3994.6579655251326, 3987.5173244678263, 3997.8255744545845, 3990.6915826151417, 3981.2703586425714, 4009.403979361409, 3989.2169111789676, 3986.8418742532335, 3978.4427998515775, 3970.8141801136035, 3996.0834452168638, 4011.8954160874146, 4003.096422301421, 4003.761392908484, 4036.0923247627557, 3983.6464437271275, 4006.1928361237597, 4020.1079988317015, 3974.935849456535, 3982.0270210855138, 4040.7894659960934, 3959.9997326708835, 3996.241976692838, 3987.3946771626565, 3996.206439934385, 3988.5337350853238, 3990.9999587548996, 3966.7525873675017, 4003.6764388523507, 3953.364011969913, 4044.5426148002975, 3980.4996553778656, 3949.636143328877, 4027.949573030075, 3971.5581250899763, 3986.055345363048, 4047.2192715769793, 3999.2061709991654, 3947.9604365226355, 4019.8883647068105, 4021.949055353319]} | |
def parse_test_data(): | |
raw_data = raw_input().strip().split(",") | |
players = raw_data[0:10] | |
return players | |
def get_elos(new_players,player_dict): | |
output = [] | |
for player in new_players: | |
try: | |
output.append(player_dict['elo'][player_dict['players'].index(player)]) | |
except ValueError: | |
player_dict['players'].append(player) | |
player_dict['elo'].append(4000) | |
output.append(4000) | |
return (output,player_dict) | |
n_go = int(raw_input()) | |
for i in range(n_go): | |
players = parse_test_data() | |
player_elos, player_dict = get_elos(players,final_player_dict) | |
if sum(player_elos[0:5]) > sum(player_elos[5:10]): | |
print 1 | |
else: | |
print 2 | |
## Score of 9.13 - 2nd in UK! (first attempt with k=10 and training ratings on first 1000 rows) | |
## Updated Score of 14.2 (second attempt with k=2 and training ratings on first 1500 rows) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment