currently 2700 games in- so that's 2200 games in about 20 minutes
At this rate, the whole ladder analysis should take ~1400 minutes- just about a whole day- on my system. There's at least a few ways to make things go faster, though.
import requests
import string
class APIError(Exception):
"""
Error class that should simply output errors
raised by the Warlight API itself
"""
pass
class ServerGameKeyNotFound(Exception):
"""
Error class for nonexistent games
"""
def getNextID(ID):
"""
Given an ID, returns the next ID
"""
lastChar = ID[-1]
mainID = ID[:(len(ID) - 1)]
if (lastChar == "Z"): newEnd = "AA"
else: newEnd = chr(ord(lastChar) + 1)
return (mainID + newEnd)
def canBeTeamless(teams, allowTeamless=True):
"""
Helper function to determine whether a game can be teamless
"""
return ((allowTeamless is True) and ([team for team in teams
if (isinstance(team, tuple))] == list()))
def makePlayers(teams, allowTeamless=False):
"""
Given teams, returns a list
containing player dictionaries
PARAMETERS:
teams: list of teams as tuples of player IDs
OPTIONAL:
teamless: bool (default False); if set to True,
a teamless result will be returned if possible
"""
teamless = canBeTeamless(teams, allowTeamless)
teamID = 0
players = list()
for team in teams:
if (teamless):
player = dict()
player['token'] = str(team)
player['team'] = str(None)
players.append(player)
elif (type(team) == list) or (type(team) == tuple):
for member in team:
player = dict()
player['token'] = str(member)
player['team'] = str(teamID)
players.append(player)
else:
player = dict()
player['token'] = str(team)
player['team'] = str(teamID)
players.append(player)
teamID += 1
return players
def overrideBonuses(bonuses):
"""
Given a list containing tuples
with bonus name and new values,
generates new list with said data
in dictionary form
"""
overridenBonuses = list()
for bonus in bonuses:
bonusData = dict()
bonusData['bonusName'] = bonus[0]
bonusData['value'] = bonus[1]
overridenBonuses.append(bonusData)
return overridenBonuses
def getAPIToken(email, password):
"""
Gets API token using email and password
"""
site = "https://www.warlight.net/API/GetAPIToken"
data = dict()
data['Email'] = email
data['Password'] = password
r = requests.post(url=site, params=data)
jsonOutput = r.json()
if 'error' in jsonOutput:
raise APIError(jsonOutput['error'])
return jsonOutput['APIToken']
def queryGame(email, token, gameID, getHistory=False):
"""
Queries a game given gameID
using credentials (email+token)
returns JSON output
"""
getHistory = str(getHistory).lower()
site = "https://www.warlight.net/API/GameFeed"
data = dict()
data['Email'] = email
data['APIToken'] = token
data['GameID'] = str(gameID)
data['GetHistory'] = getHistory
r = requests.post(url=site, params=data)
jsonOutput = r.json()
if 'error' in jsonOutput:
if ("ServerGameKeyNotFound" in jsonOutput['error']):
raise ServerGameKeyNotFound(jsonOutput['error'])
raise APIError(jsonOutput['error'])
return jsonOutput
def createGame(email, token, **settings):
"""
Creates a game given settings
using credentials (email+token)
returns game ID
"""
site = "https://www.warlight.net/API/CreateGame"
data = dict()
data['hostEmail'] = email
data['hostAPIToken'] = str(token)
data['templateID'] = settings.get('template')
data['gameName'] = settings.get('gameName')
data['personalMessage'] = settings.get('message', "")
teams = settings.get('teams')
data['players'] = makePlayers(teams)
if 'overriddenBonuses' in settings:
data['overridenBonuses'] = \
overrideBonuses(settings.get('overridenBonuses'))
r = requests.post(url=site, json=data)
jsonOutput = r.json()
if 'error' in jsonOutput:
raise APIError(jsonOutput['error'])
return jsonOutput['gameID']
def deleteGame(email, token, gameID):
"""
Deletes a game
using credentials (email+token)
does not return anything
"""
site = "https://www.warlight.net/API/DeleteLobbyGame"
data = dict()
data['Email'] = email
data['APIToken'] = str(token)
data['gameID'] = int(gameID)
r = requests.post(url=site, json=data)
jsonOutput = r.json()
if 'error' in jsonOutput:
raise APIError(jsonOutput['error'])
if 'success' not in jsonOutput:
raise APIError("Unknown error!")
def getGameIDs(email, token, *source):
"""
Gets a list of games for a ladder/tournament
using credentials (email+token)
returns list of games
"""
site = "https://www.warlight.net/API/GameIDFeed"
data = dict()
data['Email'] = email
data['APIToken'] = token
try:
assert(len(source) == 2)
except:
raise TypeError("Need both source type and ID!")
if ("ladder" in source) or ("Ladder" in source):
data['LadderID'] = int(source[-1])
elif ("tournament" in source) or ("Tournament" in source):
data['TournamentID'] = int(source[-1])
else:
raise IOError("Source type must be either ladder or tournament!")
r = requests.post(url=site, params=data)
jsonOutput = r.json()
if 'error' in jsonOutput:
raise APIError(jsonOutput['error'])
return jsonOutput['gameIDs']
def validateToken(email, token, player, *templates):
"""
Validtes an inviteToken
using credentials (email+token)
returns response
"""
site = "https://www.warlight.net/API/ValidateInviteToken"
data = dict()
data['Email'] = email
data['APIToken'] = token
data['Token'] = player
if templates is not tuple():
data['TemplateIDs'] = string.join(templates, ",")
r = requests.post(url=site, params=data)
jsonOutput = r.json()
if 'error' in jsonOutput:
raise APIError(jsonOutput['error'])
return jsonOutput
def setMapDetails(email, token, mapID, *commands):
"""
Sets map details
using credentials (email+token)
and command setup (commandtype, dict())
"""
site = "https://www.warlight.net/API/SetMapDetails"
data = dict()
data['email'] = email
data['APIToken'] = token
data['mapID'] = str(mapID)
commandData = list()
for command in commands:
order = dict()
order['command'] = command[0]
for item in command[1]:
order[item] = command[item]
commands.append(order)
data['commands'] = commandData
r = requests.post(url=site, json=data)
jsonOutput = r.json()
if 'error' in jsonOutput:
raise APIError(jsonOutput['error'])
^ Here's a (pretty insecure) wrapper library for the Warlight API in Python
from api import *
import getpass
from decimal import Decimal
requests.packages.urllib3.disable_warnings()
# if you're not using Python 2.7.9, this just silences the InsecurePlatformWarning
def getWinningColor(email, token, gameID):
queryData = queryGame(email, token, gameID)
for player in queryData['players']:
if player['state'] == 'Won':
return player['color']
if __name__ == "__main__":
# get credentials
email = raw_input("e-mail: ")
password = getpass.getpass()
token = getAPIToken(email, password)
# get 1v1 ladder games
ladder_1vs1 = getGameIDs(email, token, "ladder", 0)
# global variables for storing wins
totalWins = 0
colorWins = dict()
for game in ladder_1vs1:
winningColor = getWinningColor(email, token, game)
if winningColor is None: # no winner
continue
totalWins += 1
if winningColor not in colorWins:
colorWins[winningColor] = 0
colorWins[winningColor] += 1
colorWinsList = list()
for color in colorWins:
winPercent = round(Decimal(100) * Decimal(colorWins[color]) / Decimal(totalWins), 2)
colorWinsList.append((color, winPercent))
colorWinsList = sorted(colorWinsList, key=lambda x: x[1]) # sort by win percent
colorWinsList.reverse()
for dataPoint in colorWinsList:
print (str(dataPoint[0]) + ": " str(dataPoint[1]) + "% of total wins")
^ just save the top code as api.py, save the bottom code in the same folder, and run the bottom code
You can add a bunch of optimizations to make it run faster (like not running everything on a single thread), plus odds are your system + network connection are both faster than mine.
Edited 5/16/2016 18:41:58