Last active
May 7, 2016 09:00
-
-
Save ryannow/72811664be09e14fa8baa0b3ee3bddad to your computer and use it in GitHub Desktop.
Script to calculate NBA lottery odds. Includes all pick swaps and transfers relevant to the top 14 picks.
This file contains hidden or 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 collections | |
import csv | |
chances = { | |
'PHI': 250, | |
'LAL': 199, | |
'BOS': 156, | |
'PHX': 119, | |
'MIN': 88, | |
'NOP': 63, | |
'TOR': 43, | |
'SAC': 19, | |
'DEN': 19, | |
'MIL': 18, | |
'ORL': 8, | |
'UTA': 7, | |
'WAS': 6, | |
'CHI': 5, | |
} | |
# Dict above does not maintain order so use this instead to fill picks 4-14 | |
order = ['PHI', 'LAL', 'BOS', 'PHX', 'MIN', 'NOP', 'TOR', | |
'SAC', 'DEN', 'MIL', 'ORL', 'UTA', 'WAS', 'CHI'] | |
def chancesLeft(used): | |
total = 1000 | |
for team in used: | |
total -= chances[team] | |
return total | |
# A node contains a list of teams that won the first n spots and the probability we got to that point. | |
# Its child nodes are nodes representing each sequence of n+1 teams starting with the teams we already have. | |
class Node: | |
def __init__(self, prob, winners): | |
self.prob = prob | |
self.winners = winners | |
self.children = [] | |
def addChildren(self): | |
for key, value in chances.items(): | |
if value > 0: | |
if key not in self.winners: | |
nextProb = value / float(chancesLeft(self.winners)) | |
newProb = self.prob * nextProb | |
newWinners = self.winners + [key] | |
self.children.append(Node(self.prob * nextProb, self.winners + [key])) | |
def addDescendants(self, depth): | |
if depth > 0: | |
self.addChildren() | |
for child in self.children: | |
child.addDescendants(depth-1) | |
# Returns all leaf nodes at bottom of tree; does not return internal descendants. | |
def getAllDescendants(self): | |
fullList = [] | |
if len(self.children) == 0: | |
return [self] | |
for child in self.children: | |
fullList.extend(child.getAllDescendants()) | |
return fullList | |
""" | |
Print a CSV with each team's odds of each pick. | |
Since Philly has many likely scenarios in which they got multiple picks, | |
and the likelihood of getting the Lakers pick depends on their own result to some degree, | |
break their results out separately to find likelihood of each outcome. | |
""" | |
def main(): | |
root = Node(1, []) | |
root.addDescendants(3) | |
probs = {} | |
phiOutcomes = collections.defaultdict(int) | |
for team in order: | |
probs[team] = [0]*14 | |
for desc in root.getAllDescendants(): | |
phiPicks = "" | |
for idx, val in enumerate(doTransfers(fullList(desc.winners))): | |
probs[val][idx] += desc.prob | |
if val == "PHI": | |
phiPicks += str(idx + 1) | |
phiOutcomes[phiPicks] += desc.prob | |
print phiOutcomes | |
printCSV(probs) | |
def fullList(winners): | |
output = winners | |
for team in order: | |
if team not in winners: | |
output.append(team) | |
return output | |
def doTransfers(results): | |
afterswap = results | |
# In all cases, find pick in pre-swap results array, swap location in afterswap. | |
SACindex = results.index('SAC') | |
PHIindex = results.index('PHI') | |
if SACindex < PHIindex: | |
afterswap[SACindex] = 'PHI' | |
afterswap[PHIindex] = 'SAC' | |
TORindex = results.index('TOR') | |
DENindex = results.index('DEN') | |
if TORindex < DENindex: | |
afterswap[TORindex] = 'DEN' | |
afterswap[DENindex] = 'TOR' | |
LALindex = results.index('LAL') | |
if LALindex >= 3: | |
afterswap[LALindex] = 'PHI' | |
if SACindex >= 10: | |
afterswap[SACindex] = 'CHI' | |
WASindex = results.index('WAS') | |
if WASindex >= 3: | |
afterswap[WASindex] = 'PHX' | |
return afterswap | |
def printCSV(probs): | |
with open('lotto_odds.csv', 'wb') as csvfile: | |
oddswriter = csv.writer(csvfile, delimiter=',') | |
for team in order: | |
oddswriter.writerow([team] + probs[team]) | |
if __name__ == '__main__': | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment