Created
March 20, 2013 07:07
-
-
Save jordanbs/5202847 to your computer and use it in GitHub Desktop.
usage: bracketgen.py [-h] [--go-blue] [--dfs] Download this file, and run with the following command:
$ python ~/Downloads/bracketgen.py
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
#!/usr/bin/env python | |
# | |
# Copyright (C) 2013 jordanbs | |
# | |
# Permission is hereby granted, free of charge, to any person obtaining | |
# a copy of this software and associated documentation files (the | |
# "Software"), to deal in the Software without restriction, including | |
# without limitation the rights to use, copy, modify, merge, publish, | |
# distribute, sublicense, and/or sell copies of the Software, and to | |
# permit persons to whom the Software is furnished to do so, subject to | |
# the following conditions: | |
# | |
# ^^ That excludes the --go-blue parts. NO MODIFYING THAT WHATSOEVER. | |
# | |
# The above copyright notice and this permission notice shall be | |
# included in all copies or substantial portions of the Software. | |
# | |
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | |
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | |
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | |
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | |
# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | |
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | |
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |
# SOFTWARE. | |
# | |
import random | |
import argparse | |
gProbabilityTable = { (1, 1): 0.5, | |
(1, 2): 0.538, | |
(1, 3): 0.594, | |
(1, 4): 0.689, | |
(1, 5): 0.826, | |
(1, 6): 0.667, | |
(1, 7): 1., | |
(1, 8): 0.806, | |
(1, 9): 0.906, | |
(1, 10): 1., | |
(1, 11): 0.4, | |
(1, 12): 1., | |
(1, 13): 1., | |
(1, 16): 1., | |
(2, 2): 0.5, | |
(2, 3): 0.614, | |
(2, 4): 0.444, | |
(2, 5): 0.2, | |
(2, 6): 0.697, | |
(2, 7): 0.738, | |
(2, 8): 0.571, | |
(2, 9): 1., | |
(2, 10): 0.588, | |
(2, 11): 0.917, | |
(2, 12): 1., | |
(2, 15): 0.946, | |
(3, 3): 0.5, | |
(3, 4): 0.833, | |
(3, 5): 0.5, | |
(3, 6): 0.532, | |
(3, 7): 0.667, | |
(3, 8): 1., | |
(3, 9): 1., | |
(3, 10): 0.692, | |
(3, 11): 0.714, | |
(3, 14): 0.857, | |
(4, 4): 0.5, | |
(4, 5): 0.549, | |
(4, 6): 0.333, | |
(4, 7): 0.667, | |
(4, 8): 0.25, | |
(4, 9): 0.667, | |
(4, 10): 1., | |
(4, 12): 0.645, | |
(4, 13): 0.786, | |
(5, 5): 0.5, | |
(5, 6): 1., | |
(5, 8): 0.25, | |
(5, 9): 0.333, | |
(5, 10): 1., | |
(5, 12): 0.689, | |
(5, 13): 0.786, | |
(6, 6): 0.5, | |
(6, 7): 0.571, | |
(6, 8): 0.25, | |
(6, 10): 0.6, | |
(6, 11): 0.667, | |
(6, 14): 0.846, | |
(7, 7): 0.5, | |
(7, 10): 0.596, | |
(7, 14): 1., | |
(7, 15): 1., | |
(8, 8): 0.5, | |
(8, 9): 0.515, | |
(8, 11): 1., | |
(8, 13): 1., | |
(9, 9): 0.5, | |
(9, 10): 1., | |
(10, 10): 0.5, | |
(10, 11): 0., | |
(10, 14): 1., | |
(10, 15): 1., | |
(11, 11): 0.5, | |
(11, 14): 1., | |
(12, 12): 0.5, | |
(12, 13): 0.8, | |
} | |
rand = random.SystemRandom().random | |
#random.seed(2) | |
#rand = random.random | |
class Team(object): | |
fmt = '%s (%s)' | |
fmt_len = len(fmt) - 2 * fmt.count('%') | |
def __init__(self, name, seed): | |
self.name = name | |
self.seed = seed | |
def __repr__(self): | |
return '<Team: %s, Seed: %s>' % (self.name, self.seed) | |
def __str__(self): | |
return self.fmt % (self.name, self.seed) | |
# must be in order | |
gTeams = [ Team('Louisville', 1), | |
Team('North Carolina A&T', 16), | |
Team('Colorado State', 8), | |
Team('Missouri', 9), | |
Team('Okalhoma State', 5), | |
Team('Oregon', 12), | |
Team('Saint Louis', 4), | |
Team('New Mexico State', 13), | |
Team('Memphis', 6), | |
Team('St. Mary\'s', 11), | |
Team('Michigan State', 3), | |
Team('Valparaiso', 14), | |
Team('Creighton', 7), | |
Team('Cincinnati', 10), | |
Team('Duke', 2), | |
Team('Albany', 15), | |
Team('Gonzaga', 1), | |
Team('Southern University', 16), | |
Team('Pittsburgh', 8), | |
Team('Wichita State', 9), | |
Team('Wisconsin', 5), | |
Team('Ole Miss', 12), | |
Team('Kansas State', 4), | |
Team('Boise St/La Salle', 13), | |
Team('Arizona', 6), | |
Team('Belmont', 11), | |
Team('New Mexico', 3), | |
Team('Harvard', 14), | |
Team('Notre Dame', 7), | |
Team('Iowa State', 10), | |
Team('Ohio State', 2), | |
Team('Iona', 15), | |
Team('Kansas', 1), | |
Team('Western Kentucky', 16), | |
Team('North Carolina', 8), | |
Team('Vilanova', 9), | |
Team('Virginia Commonwealth', 5), | |
Team('Akron', 12), | |
Team('Michigan', 4), | |
Team('South Dakota State', 13), | |
Team('UCLA', 6), | |
Team('Minnesota', 11), | |
Team('Florida', 3), | |
Team('Northwestern State', 14), | |
Team('San Diego State', 7), | |
Team('Oklahoma', 10), | |
Team('Georgetown', 2), | |
Team('Florida Gulf Coast', 15), | |
Team('Indiana', 1), | |
Team('LIU/JMU', 16), | |
Team('NC State', 8), | |
Team('Temple', 9), | |
Team('UNLV', 5), | |
Team('California', 12), | |
Team('Syracuse', 4), | |
Team('Montana', 13), | |
Team('Butler', 6), | |
Team('Bucknell', 11), | |
Team('Marquette', 3), | |
Team('Davidson', 14), | |
Team('Illinois', 7), | |
Team('Colorado', 10), | |
Team('Miami', 2), | |
Team('Pacific', 15) | |
] | |
class Bracket(object): | |
def __init__(self, dfs=False): | |
self.dfs = dfs | |
if dfs: | |
self._generate_bracket_tree() | |
else: | |
self._generate_bracket_queue() | |
def eval_tourney(self, go_blue=False): | |
# Depth first tournament | |
# only play a game when you need the victor for the next one | |
if self.dfs: | |
return self._eval_tourney_tree(self.champ_node, go_blue=go_blue) | |
# Breadth first tournament | |
# ya know, like how tournaments are normally played | |
return self._eval_tourney_queue(self.game_queue, go_blue=go_blue) | |
def _eval_tourney_tree(self, root_node, go_blue=False): | |
return root_node.eval_node(go_blue=go_blue) | |
def _eval_tourney_queue(self, game_queue, go_blue=False): | |
while len(game_queue) > 1: | |
team1 = game_queue.pop(0) | |
assert(len(game_queue) > 0) | |
team2 = game_queue.pop(0) | |
assert(isinstance(team1, Team) and isinstance(team2, Team)) | |
winner = decide_game(team1, team2, go_blue=go_blue, auto=False) | |
game_queue.append(winner) | |
return winner | |
def _generate_top_nodes(self): | |
self.top_nodes = list() | |
game = None | |
for i, team in enumerate(gTeams): | |
if i % 2 == 0: | |
game = BracketNode() | |
self.top_nodes.append(game) | |
game.input1 = team | |
else: | |
game.input2 = team | |
def _generate_bracket_tree(self): | |
self._generate_top_nodes() | |
self.champ_node = BracketNode() | |
self._generate_bracket_helper(self.champ_node, 5) | |
def _generate_bracket_helper(self, node, rounds): | |
if rounds == 1: | |
node.input1 = self.top_nodes[0] | |
node.input2 = self.top_nodes[1] | |
del self.top_nodes[0], self.top_nodes[0] | |
return | |
node.input1 = BracketNode() | |
self._generate_bracket_helper(node.input1, rounds - 1) | |
node.input2 = BracketNode() | |
self._generate_bracket_helper(node.input2, rounds - 1) | |
def _generate_bracket_queue(self): | |
self.game_queue = list() | |
for team in gTeams: | |
self.game_queue.append(team) | |
class BracketNode(object): | |
def eval_node(self, go_blue=False): | |
assert(self.input1 and self.input2) | |
team1 = None | |
team2 = None | |
if isinstance(self.input1, Team): | |
team1 = self.input1 | |
if isinstance(self.input2, Team): | |
team2 = self.input2 | |
if team1 is None: | |
team1 = self.input1.eval_node(go_blue=go_blue) | |
if team2 is None: | |
team2 = self.input2.eval_node(go_blue=go_blue) | |
winner = decide_game(team1, team2, go_blue=go_blue) | |
return winner | |
def pred(team): | |
return team.name.startswith('Mich') and not team.name.endswith('ate') | |
def decide_game(team1, team2, go_blue=False, auto=False): | |
winner = None | |
odds = None | |
#ipdb.set_trace() | |
try: | |
odds = gProbabilityTable[(team1.seed, team2.seed)] | |
random_chance = rand() | |
#print('dice: %.2f, odds: %.2f' % (random_chance, odds)) | |
if ((random_chance < odds or (go_blue and pred(team1))) and | |
not (go_blue and pred(team2))): | |
winner = team1 | |
else: | |
odds = 1. - odds | |
winner = team2 | |
except KeyError: | |
user_in = '' | |
print('') | |
print_game(team1, team2) | |
print('This matchup has never happened before!') | |
while not winner: | |
if auto: | |
if team1.seed < team2.seed: | |
winner = team1 | |
else: | |
winner = team2 | |
break | |
user_in = raw_input('Choose the victor: ') | |
if team1.name.lower().startswith(user_in.lower()): | |
winner = team1 | |
if team2.name.lower().startswith(user_in.lower()): | |
if not winner: | |
winner = team2 | |
else: | |
winner = None | |
print('') | |
assert(winner != None) | |
print_game(team1, team2, winner, odds) | |
return winner | |
gLongestNameLen = max([len(team.name) + len(str(team.seed)) + Team.fmt_len for team in gTeams]) | |
def print_game(team1, team2, winner=None, odds=None): | |
team1_display = str(team1).rjust(gLongestNameLen) | |
team2_display = str(team2).ljust(gLongestNameLen) | |
display = '%s vs %s' % (team1_display, team2_display) | |
if winner: | |
winner_fmt = ' %s wins!' | |
winner_fmt_len = len(winner_fmt) - 2 * winner_fmt.count('%') | |
winner_display = (winner_fmt % winner).ljust(gLongestNameLen + winner_fmt_len) | |
display += winner_display | |
if odds: | |
display += ' %.0f%%' % (odds * 100) | |
else: | |
display += ' ...' | |
print(display) | |
def append_reflected_table(table): | |
reflected_table = dict() | |
for tup, prob in table.iteritems(): | |
reflected_table[(tup[1], tup[0])] = 1. - prob | |
for key, value in reflected_table.iteritems(): | |
table[key] = value | |
def main(): | |
parser = argparse.ArgumentParser() | |
parser.add_argument('--go-blue', action='store_false') | |
parser.add_argument('--dfs', action='store_true', help='Perform depth first tourney') | |
args = parser.parse_args() | |
append_reflected_table(gProbabilityTable) | |
bracket = Bracket(dfs=args.dfs) | |
return bracket.eval_tourney(go_blue=args.go_blue) | |
if __name__ == '__main__': | |
main() | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment