forked from Alosapien/Alosapien
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
3 changed files
with
147 additions
and
64 deletions.
There are no files selected for viewing
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
credentials.json | ||
token.pickle |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
# Install dependencies | ||
|
||
``` | ||
pip install google-api-python-client google-auth-httplib2 google-auth-oauthlib | ||
``` | ||
|
||
# Set up credentials | ||
|
||
First acquire the credentials.json file for the Wilkinz gmail account. | ||
|
||
Copy the file into this directory. | ||
|
||
# Indicate who's playing | ||
|
||
Update the "Team" rows of the google spreadsheet, putting "?" for each player | ||
|
||
# Run the script | ||
|
||
``` | ||
python teamMaker2.py | ||
``` |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,66 +1,126 @@ | ||
import itertools | ||
import pickle | ||
import os.path | ||
from googleapiclient.discovery import build | ||
from google_auth_oauthlib.flow import InstalledAppFlow | ||
from google.auth.transport.requests import Request | ||
|
||
# If modifying these scopes, delete the file token.pickle. | ||
SCOPES = ['https://www.googleapis.com/auth/spreadsheets.readonly'] | ||
|
||
SPREADSHEET_ID = '1c2Kvc3y1GrF9EFqAKvPoRU8NmFV_exCrAeCTrmDct2Y' | ||
ELOS_RANGE = 'TEST!A2:ZZ12' | ||
TEAMS_RANGE = 'TEST!A16:ZZ26' | ||
|
||
class Sheets(object): | ||
def __init__(self): | ||
self._creds = self.get_credentials() | ||
service = build('sheets', 'v4', credentials=self._creds) | ||
self._sheets = service.spreadsheets() | ||
|
||
def get_credentials(self): | ||
"""Sets up credentials to be able to access the google sheet. | ||
The first time this is called, this method will open a | ||
web page for the user to sign in. After signing in, a | ||
token.pickle file will be created to remember the sign-in, so | ||
that future runs of the program no longer require signing in. | ||
""" | ||
creds = None | ||
if os.path.exists('token.pickle'): | ||
with open('token.pickle', 'rb') as token: | ||
creds = pickle.load(token) | ||
# If there are no (valid) credentials available, let the user log in. | ||
if not creds or not creds.valid: | ||
if creds and creds.expired and creds.refresh_token: | ||
creds.refresh(Request()) | ||
else: | ||
flow = InstalledAppFlow.from_client_secrets_file( | ||
'credentials.json', SCOPES) | ||
creds = flow.run_local_server(port=0) | ||
# Save the credentials for the next run | ||
with open('token.pickle', 'wb') as token: | ||
pickle.dump(creds, token) | ||
return creds | ||
|
||
def get_elos(self): | ||
"""Reads the latest ELO values from the spreadsheet. | ||
ELO values are return as a {name: ELO} dictionary. | ||
""" | ||
result = self._sheets.values().get(spreadsheetId=SPREADSHEET_ID, | ||
range=ELOS_RANGE).execute() | ||
values = result.get('values', []) | ||
if not values: | ||
raise RuntimeError('No elo data found.') | ||
|
||
elos = {} | ||
for row in values: | ||
name = row[0] | ||
elos[name] = int(row[-1]) | ||
return elos | ||
|
||
def get_players(self): | ||
"""Returns the list of players to calculate teams for. | ||
This is determined by looking at the "Team" rows of the | ||
spreadsheet, and choosing all players with a "?" in the | ||
last column. | ||
""" | ||
result = self._sheets.values().get(spreadsheetId=SPREADSHEET_ID, | ||
range=TEAMS_RANGE).execute() | ||
values = result.get('values', []) | ||
if not values: | ||
raise RuntimeError('No team data found.') | ||
|
||
players = [] | ||
last_column = max(len(row) for row in values) - 1 | ||
for row in values: | ||
if last_column < len(row) and row[last_column] == '?': | ||
players.append(row[0]) | ||
return players | ||
|
||
|
||
class TeamChooser(object): | ||
def __init__(self, elos): | ||
self._elos = elos | ||
|
||
def team_score(self, players): | ||
return sum(self._elos[p] for p in players) | ||
|
||
def print_team(self, team_index, team): | ||
print(" Team {} ({}):".format(team_index, self.team_score(team))) | ||
for p in team: | ||
print(" {} ({})".format(p, self._elos[p])) | ||
|
||
def show_best_teams(self, players, num_teams=2, results_to_show=3): | ||
results = set() # (team_score_difference, team_1, team_2) | ||
for order in itertools.permutations(players): | ||
# Choose teams by deciding positions at which to split the permutation | ||
for inds in itertools.combinations(range(len(players)), num_teams-1): | ||
inds = (0,) + inds + (len(players),) | ||
teams = [ order[inds[i]:inds[i+1]] for i in range(num_teams) ] | ||
scores = [ self.team_score(team) for team in teams ] | ||
mean = sum(scores) / len(scores) | ||
unfairness = sum(abs(score-mean) for score in scores) | ||
# Use a set to deduplicate equivalent teams. | ||
# Using frozenset instead of set because frozenset, unlike set, is hashable | ||
results.add((unfairness, frozenset(frozenset(team) for team in teams))) | ||
for diff, teams in sorted(results)[:results_to_show]: | ||
print("----- Result with unfairness {} -----".format(diff)) | ||
for i, team in enumerate(teams): | ||
self.print_team(i+1, team) | ||
|
||
num_teams = 2 | ||
gaming_players = ['Arno', 'Will', 'Wang', 'JZ', 'Jind', 'Drew', "Mike"] | ||
|
||
sheets = Sheets() | ||
elos = sheets.get_elos() | ||
players = sheets.get_players() | ||
print(elos) | ||
print(players) | ||
|
||
chooser = TeamChooser(elos) | ||
chooser.show_best_teams(players, num_teams) | ||
|
||
|
||
ELOS = {'Drew':1450, 'JZ':900, 'Mike':950, 'Alo':650, 'Arno':800, 'Will':750, 'Jind':550, 'Wang':400} # scores of players | ||
|
||
def team_score(players): | ||
return sum(ELOS[p] for p in players) | ||
|
||
def print_team(team_index, team): | ||
print(" Team {} ({}):".format(team_index, team_score(team))) | ||
for p in team: | ||
print(" {} ({})".format(p, ELOS[p])) | ||
|
||
def show_best_teams(players, num_teams=2, results_to_show=3): | ||
results = set() # (team_score_difference, team_1, team_2) | ||
for order in itertools.permutations(players): | ||
# Choose teams by deciding positions at which to split the permutation | ||
for inds in itertools.combinations(range(len(players)), num_teams-1): | ||
inds = (0,) + inds + (len(players),) | ||
teams = [ order[inds[i]:inds[i+1]] for i in range(num_teams) ] | ||
scores = [ team_score(team) for team in teams ] | ||
mean = sum(scores) / len(scores) | ||
unfairness = sum(abs(score-mean) for score in scores) | ||
# Use a set to deduplicate equivalent teams. | ||
# Using frozenset instead of set because frozenset, unlike set, is hashable | ||
results.add((unfairness, frozenset(frozenset(team) for team in teams))) | ||
for diff, teams in sorted(results)[:results_to_show]: | ||
returns=Returns(teams,gamble=50) #calculates the loss and gain for a team | ||
print("----- Result with unfairness {} -----".format(diff)) | ||
for i, team in enumerate(teams): | ||
print_team(i+1, team) | ||
print(' loss:',returns[i][0],' gain:',returns[i][1]) # prints the loss and gain | ||
return sorted(results)[:results_to_show] | ||
##### | ||
def Returns(teams,gamble=50): #calculates the losses and gain of each team | ||
teamTotals=[] | ||
for team in teams: | ||
teamTotals+=[team_score(team)] | ||
#print(teamTotals) | ||
returns=[] | ||
ind=0 | ||
for team in teams: | ||
returns+=[[round(-1*gamble),round(gamble*((sum(teamTotals)-teamTotals[ind])/teamTotals[ind]))]] | ||
#print(((sum(teamTotals)-teamTotals[ind])/teamTotals[ind])) | ||
ind+=1 | ||
#print(returns) | ||
return returns | ||
|
||
def score_update(teams,winnerInd,gamble=50): #updates ELOS depending on the victors of a given match | ||
returns=Returns(teams,gamble) | ||
for player in ELOS: | ||
for ind in range(len(teams)): | ||
team=teams[ind] | ||
if player in team: | ||
if ind==winnerInd: | ||
ELOS[player]+=returns[ind][1] | ||
if ind!=winnerInd: | ||
ELOS[player]=max(20,ELOS[player]+returns[ind][0]) | ||
print(ELOS) | ||
### | ||
|
||
num_teams = 3 | ||
gaming_players = ['Alo', 'Will', 'Wang', 'JZ', 'Mike', 'Drew'] | ||
matches=show_best_teams(gaming_players, num_teams=num_teams) | ||
#print(matches) | ||
print('if the first match is played and Team 2 wins, the ELOS is updated as below') | ||
score_update(list(matches[0][1]),1) |