Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import requests,random
- from operator import itemgetter
- from timeit import default_timer as timer
- from itertools import repeat as rep
- import multiprocessing
- import numpy as np
- from functools import total_ordering
- import copy
- @total_ordering
- class Team:
- def __init__(self, guid, name, abbrev,maps,wins,losses,mapwins,maplosses,division):
- self.guid=guid
- self.name=name
- self.abbrev=abbrev
- self.elo=1000
- self.maps = maps
- self.assaultdraws = 0
- self.assaultdrawable = 0
- self.hybriddraws = 0
- self.hybriddrawable = 0
- self.wins = wins
- self.losses = losses
- self.mapwins = mapwins
- self.maplosses = maplosses
- self.division = division
- self.teamrecords = {}
- def __eq__(self,other):
- return teamcmp(self,other)==0
- def __ne__(self,other):
- return teamcmp(self,other)!=0
- def __lt__(self,other):
- return teamcmp(self,other)<0
- def updaterecord(self,other,scores):
- if other.guid not in self.teamrecords.keys():
- self.teamrecords[other.guid] = HTH()
- if scores[0] > scores[1]:
- self.teamrecords[other.guid].wins += 1
- self.teamrecords[other.guid].mapwins += scores[0]
- self.teamrecords[other.guid].maplosses += scores[1]
- else:
- self.teamrecords[other.guid].losses += 1
- self.teamrecords[other.guid].mapwins += scores[0]
- self.teamrecords[other.guid].maplosses += scores[1]
- class HTH:
- def __init__(self):
- self.wins = 0
- self.losses = 0
- self.mapwins = 0
- self.maplosses = 0
- def __str__(self):
- return "{}-{} M {}-{}".format(self.wins,self.losses,self.mapwins,self.maplosses)
- def teamcmp(A,B):
- Adiff = A.mapwins - A.maplosses
- Bdiff = B.mapwins - B.maplosses
- if B.guid in A.teamrecords.keys():
- AHdiff = A.teamrecords[B.guid].mapwins - A.teamrecords[B.guid].maplosses
- BHdiff = B.teamrecords[A.guid].mapwins - B.teamrecords[A.guid].maplosses
- else:
- AHdiff = 0
- BHdiff = 0
- if (A.wins-A.losses) != (B.wins-B.losses):
- retvalue = 1 if (A.wins-A.losses) > (B.wins-B.losses) else -1
- return retvalue
- elif Adiff != Bdiff:
- retvalue = 1 if Adiff > Bdiff else -1
- return retvalue
- elif AHdiff != BHdiff:
- retvalue = 1 if AHdiff > BHdiff else -1
- return retvalue
- else:
- return 0 # god I don't know how to do this shit
- class Match:
- def __init__(self,A,B,gamemaps,expectations):
- self.A=A
- self.B=B
- self.gamemaps=gamemaps
- self.expecations=expectations
- def simulate(self):
- return scorekey[np.random.choice(range(len(scorekey)),p=expectations)]
- def expected(A, B):
- return 1 / (1 + 10 ** ((B - A) / 400))
- def elo(old, exp, score, k=24):
- return old + k * (score - exp)
- control = ["0x08000000000007E2","0x080000000000066D","0x08000000000004B7"]
- def tiebreakmap(mcmap):
- tiebreaks = []
- for cmap in control:
- if mcmap != cmap:
- tiebreaks.append(cmap)
- return random.choice(tiebreaks)
- trials = 500000
- ptrials = 20000
- def simulate(A, B, gamemaps):
- scorehist = {}
- expectations = []
- assaultdrawchance = (((float(A.assaultdraws)/A.assaultdrawable)+(float(B.assaultdraws)/B.assaultdrawable))/2)
- hybriddrawchance = (((float(A.hybriddraws)/A.hybriddrawable)+(float(B.hybriddraws)/B.hybriddrawable)/2))
- for map in gamemaps:
- expectations.append(expected(A.maps[map],B.maps[map]))
- for i in range(trials):
- score = (0,0)
- for i in range(len(gamemaps)):
- if gamemaps[i] in assault:
- if random.random() < assaultdrawchance:
- continue
- if gamemaps[i] in hybrid:
- if random.random() < hybriddrawchance:
- continue
- if random.random() < expectations[i]:
- score = (score[0]+1,score[1])
- else:
- score = (score[0],score[1]+1)
- if score[0] == score[1]: # just in case of a (1,1) draw
- tiebreak = tiebreakmap(gamemaps[0])
- if random.random() < expected(A.maps[tiebreak],B.maps[tiebreak]):
- score = (score[0]+1,score[1])
- else:
- score = (score[0],score[1]+1)
- if score in scorehist.keys():
- scorehist[score] += 1
- else:
- scorehist[score] = 1
- return scorehist
- scorekey = [(0,2),(0,3),(0,4),(1,2),(1,3),(2,0),(2,1),(2,3),(3,0),(3,1),(3,2),(4,0)]
- def addtrial(id,A,B,gamemaps,assault,assaultdrawchance,hybrid,hybriddrawchance,expectations):
- score = (0,0)
- for i in range(len(gamemaps)):
- if gamemaps[i] in assault:
- if random.random() < assaultdrawchance:
- continue
- if gamemaps[i] in hybrid:
- if random.random() < hybriddrawchance:
- continue
- if random.random() < expectations[i]:
- score = (score[0]+1,score[1])
- else:
- score = (score[0],score[1]+1)
- if score[0] == score[1]: # just in case of a (1,1) draw
- tiebreak = tiebreakmap(gamemaps[0])
- if random.random() < expected(A.maps[tiebreak],B.maps[tiebreak]):
- score = (score[0]+1,score[1])
- else:
- score = (score[0],score[1]+1)
- return score
- def createhist(results):
- scorehist = {}
- for res in results:
- if res not in scorehist.keys():
- scorehist[res] = 1
- else:
- scorehist[res] += 1
- return scorehist
- def simulate_multi(A, B, gamemaps):
- expectations = []
- assaultdrawchance = (((float(A.assaultdraws)/A.assaultdrawable)+(float(B.assaultdraws)/B.assaultdrawable))/2)
- hybriddrawchance = (((float(A.hybriddraws)/A.hybriddrawable)+(float(B.hybriddraws)/B.hybriddrawable)/2))
- for map in gamemaps:
- expectations.append(expected(A.maps[map],B.maps[map]))
- pool = multiprocessing.Pool(4)
- res = pool.starmap(addtrial,zip(range(trials),rep(A),rep(B),rep(gamemaps),rep(assault),rep(assaultdrawchance),rep(hybrid),rep(hybriddrawchance),rep(expectations)))
- scorehist = createhist(res)
- return scorehist
- def printhistogram(hist):
- for score in hist.keys():
- print("{0}-{1}: {2:.3f}".format(score[0],score[1],float(hist[score])/trials))
- def getplayoffs(teamlist):
- teamlist = sorted(teamlist,reverse=True)
- playoffs = []
- for div in (79,80): # find division winners
- for i in range(len(teamlist)):
- if teamlist[i].division == div:
- playoffs.append(teamlist[i])
- del teamlist[i]
- break
- playoffs += teamlist[:6]
- return sorted(playoffs,reverse=True)
- if __name__ == "__main__":
- teamresp = requests.get('https://api.overwatchleague.com/ranking')
- if teamresp.status_code != 200:
- raise ApiError('GET /ranking {}'.format(teamresp.status_code))
- mapresp = requests.get('https://api.overwatchleague.com/maps')
- if mapresp.status_code != 200:
- raise ApiError('GET /ranking {}'.format(mapresp.status_code))
- maps = {}
- assault = []
- hybrid = []
- for map in mapresp.json():
- maps[map['guid']]=map['name']['en_US']
- if map['type'] == "hybrid":
- hybrid.append(map['guid'])
- if map['type'] == "assault":
- assault.append(map['guid'])
- #print(hybrid,assault)
- #print(maps)
- #print(teamresp.json()['content'][0])
- teams = {}
- for team in teamresp.json()['content']:
- teammaps={}
- for map in maps.keys():
- teammaps[map] = 1000
- for division in team['competitor']['divisions']:
- division = division['division']['id']
- if division == 79 or division == 80:
- div = division
- records = team['records'][0]
- teams[team['competitor']['id']] = Team(team['competitor']['id'],team['competitor']['name'],team['competitor']['abbreviatedName'],teammaps,records['matchWin'],records['matchLoss'],records['gameWin'],records['gameLoss'],div)
- #for teamid in teams.keys():
- #div = "PAC" if teams[teamid].division == 80 else "ATL"
- #print(teamid,teams[teamid].name,div, "{}-{} {}".format(teams[teamid].wins,teams[teamid].losses,(teams[teamid].mapwins-teams[teamid].maplosses)))
- resp = requests.get('https://api.overwatchleague.com/schedule')
- if resp.status_code != 200:
- raise ApiError('GET /schedule {}'.format(resp.status_code))
- #print(resp.json()['data']['stages'][0]['matches'][0]['games'][0]['attributes']['mapGuid'])
- for match in resp.json()['data']['stages'][0]['matches']:
- if match['state'] != "CONCLUDED":
- break
- A = teams[match['competitors'][0]['id']]
- B = teams[match['competitors'][1]['id']]
- #print(A.name, "vs", B.name)
- scores = [score['value'] for score in match['scores']]
- A.updaterecord(B,scores)
- B.updaterecord(A,[scores[1],scores[0]])
- #print(str(A.teamrecords[B.guid]))
- #print(str(B.teamrecords[A.guid]))
- #print(A>B)
- for game in match['games']:
- exp = expected(A.elo,B.elo)
- gamemap = game['attributes']['mapGuid']
- mapexp = expected(A.maps[gamemap],B.maps[gamemap])
- #print("{0} vs {1} map {2} - {3} EV {4:.3f} map EV {5:.3f}".format(A.abbrev,B.abbrev,game['number'],maps[gamemap],exp,mapexp))
- assaultflag = False
- hybridflag = False
- if gamemap in assault:
- A.assaultdrawable += 1
- B.assaultdrawable += 1
- assaultflag = True
- if gamemap in hybrid:
- A.hybriddrawable += 1
- B.hybriddrawable += 1
- hybridflag = True
- points = game['points']
- if points[0] > points[1]:
- A.elo = elo(A.elo,exp,1)
- A.maps[gamemap] = elo(A.maps[gamemap],mapexp,1)
- B.elo = elo(B.elo,1-exp,0)
- B.maps[gamemap] = elo(B.maps[gamemap],1-mapexp,0)
- #print("{0} wins, ELOs {1:.1f} {2:.1f} {3:.1f} {4:.1f}".format(A.abbrev,A.elo,B.elo,A.maps[gamemap],B.maps[gamemap]))
- elif points[0] < points[1]:
- A.elo = elo(A.elo,exp,0)
- A.maps[gamemap] = elo(A.maps[gamemap],mapexp,0)
- B.elo = elo(B.elo,1-exp,1)
- B.maps[gamemap] = elo(B.maps[gamemap],1-mapexp,1)
- #print("{0} wins, ELOs {1:.1f} {2:.1f} {3:.1f} {4:.1f}".format(B.abbrev,A.elo,B.elo,A.maps[gamemap],B.maps[gamemap]))
- else:
- A.elo = elo(A.elo,exp,0.5)
- A.maps[gamemap] = elo(A.maps[gamemap],mapexp,0.5)
- B.elo = elo(B.elo,1-exp,0.5)
- B.maps[gamemap] = elo(B.maps[gamemap],1-mapexp,0.5)
- #print("draw, ELOs {0:.1f} {1:.1f} {2:.1f} {3:.1f}".format(A.elo,B.elo,A.maps[gamemap],B.maps[gamemap]))
- if assaultflag:
- A.assaultdraws += 1
- B.assaultdraws += 1
- if hybridflag:
- A.hybriddraws += 1
- B.hybriddraws += 1
- #print()
- i=1
- matches=[]
- start=timer()
- for match in resp.json()['data']['stages'][0]['matches']:
- if match['state'] == "CONCLUDED":
- continue
- A = teams[match['competitors'][0]['id']]
- B = teams[match['competitors'][1]['id']]
- #print(A.name, "vs", B.name," - prediction EV ","{0:.3f}".format(expected(A.elo,B.elo)))
- #print()
- gamemaps = []
- for game in match['games']:
- gamemap = game['attributes']['mapGuid']
- gamemaps.append(gamemap)
- mapexp = expected(A.maps[gamemap],B.maps[gamemap])
- #print("{0} vs {1} map {2} - {3} map EV {4:.3f}".format(A.abbrev,B.abbrev,game['number'],maps[gamemap],mapexp))
- #if gamemap in hybrid:
- #print("Hybrid draw chance: {0} {1:.3f} {2} {3:.3f}".format(A.abbrev,float(A.hybriddraws)/A.hybriddrawable,B.abbrev,float(B.hybriddraws)/B.hybriddrawable))
- #if gamemap in assault:
- #print("Assault draw chance: {0} {1:.3f} {2} {3:.3f}".format(A.abbrev,float(A.assaultdraws)/A.assaultdrawable,B.abbrev,float(B.assaultdraws)/B.assaultdrawable))
- #print()
- #start = timer()
- #histogram=simulate(A,B,gamemaps)
- #printhistogram(histogram)
- #end = timer()
- #print("{} iterations in {}s".format(trials,(end-start)))
- #print()
- #start = timer()
- histogram=simulate_multi(A,B,gamemaps)
- #printhistogram(histogram)
- #end = timer()
- #print("{} iterations in {}s".format(trials,(end-start)))
- expectations = [0.0]*len(scorekey)
- for score in scorekey:
- if score in histogram.keys():
- expectations[scorekey.index(score)] = float(histogram[score])/trials
- amatch = Match(A,B,gamemaps,expectations)
- matches.append(amatch)
- #print()
- #print()
- end=timer()
- print("{} matches simulated in {}s".format(len(matches),(end-start)))
- phistogram = {}
- start=timer()
- for i in range(ptrials):
- teams2 = copy.deepcopy(teams)
- for match in matches:
- A=teams2[match.A.guid]
- B=teams2[match.B.guid]
- scores = match.simulate()
- #print("simulating {} vs {} score {}-{}".format(A.abbrev,B.abbrev,scores[0],scores[1]))
- A.updaterecord(B,scores)
- B.updaterecord(A,[scores[1],scores[0]])
- if scores[0] > scores[1]:
- A.wins += 1
- B.losses += 1
- else:
- A.losses += 1
- B.wins += 1
- A.mapwins += scores[0]
- A.maplosses += scores[1]
- B.mapwins += scores[1]
- B.maplosses += scores[0]
- teamlist = [teams2[teamid] for teamid in teams2.keys()]
- simplayoff = getplayoffs(teamlist)
- simplayoff = [team.guid for team in simplayoff]
- simplayoff = tuple(simplayoff)
- #print(simplayoff)
- if simplayoff in phistogram.keys():
- phistogram[simplayoff] += 1
- else:
- phistogram[simplayoff] = 1
- end=timer()
- print("{} playoffs simulated in {}s".format(ptrials,(end-start)))
- for team in teams.keys():
- playoffcount = 0
- for playoffsim in phistogram.keys():
- if teams[team].guid in playoffsim:
- playoffcount += 1
- print("{0} {1:.3f}".format(teams[team].abbrev,float(playoffcount)/ptrials))
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement