def add_player(nickname, firstname="", lastname="", commit=False): """ Adds a player and the corresponding ranks to the database. If the player already exsits, this function does nothing. :param nickname: The nickname of the player to add :type nickname: string :param firstname: The first name of the player to add :type firstname: string :param lastname: The last name of the player to add :type lastname: string :param commit: True if the rows should be committed :type commit: bool :return: Tupel (the player model, False if player already existed) """ player = Player.query().get(nickname=nickname) created = False if player == None: created = True player = Player(firstname=firstname, lastname=lastname, nickname=nickname) player.save(commit) rank = Rank_Elo(player_id=player.player_id.value) rank.save(commit) rank = Rank_Glicko(player_id=player.player_id.value) rank.save(commit) return player, created
def get_rating(args, p1=None, p2=None): def rating_elo(player): if player is None: return None return Rank_Elo.query().get(player_id=player.player_id.value) def rating_glicko(player): if player is None: return None return Rank_Glicko.query().get(player_id=player.player_id.value) def rating_glicko2(): return None """ Queries the rating of a given player or two given players. Returns one rank table, if "args.player" is defined. Returns a tupel of two rank tables, if "args.player1" and "args.player2" is defined. :param args: A list with arguments from the argument parser :type args: namespace :param p1: The nickname of a player :param p2: The nickname of another player :return: The rank for the given player(s) (either in args or in p1/p2) """ rating_funcs = { 'elo': rating_elo, 'glicko': rating_glicko, 'glicko2': rating_glicko2} if p1 is not None and p2 is not None: player1 = Player.query().get(nickname=p1) player2 = Player.query().get(nickname=p2) return (rating_funcs[args.algorithm](player1), rating_funcs[args.algorithm](player2)) elif args.__dict__.get("player", None): player = Player.query().get(nickname=args.player) if player is None: return None return rating_funcs[args.algorithm](player) elif args.__dict__.get("player1", None) and args.__dict__.get("player2", None): player1 = Player.query().get(nickname=args.player1) player2 = Player.query().get(nickname=args.player2) return (rating_funcs[args.algorithm](player1), rating_funcs[args.algorithm](player2)) return None
def match(args): def match_elo(rating): ratings = Rank_Elo.query().all() best = None deviation = 99999999 for r in ratings: if (best is None or abs(r.value.value - rating.value.value) < deviation) and r.player_id.value != rating.player_id.value: best = r deviation = abs(r.value.value - rating.value.value) return best def match_glicko(rating): print "Not implemented yet" return None """ Finds the best opponent for a given player. :param args: A list with arguments from the argument parser :type args: namespace """ match_funcs = {'elo': match_elo, 'glicko': match_glicko} rating = utils.get_rating(args) if rating is None: print "Player %s is not known." % args.player return print "Looking for the best opponent for player %s..." % args.player opponent = match_funcs[args.algorithm](rating) if opponent is None: print "No opponent found." return print "Best opponent for player %s with rating %d is:" % ( args.player, rating.value.value) other = Player.query().get(player_id=opponent.player_id.value) print "\tPlayer %s with rating %d." % (other.nickname.value, opponent.value.value)
def best_worst_elo(): ranks = Rank_Elo.query().all() ranks = sorted(ranks, key=lambda x: x.value.value, reverse=best) # the table to print out table = [['Rank', 'Rating', 'Nick', 'Firstname', 'Lastname', 'ID']] #print "Rank\tRating\tNick\tForename\tSurname\tid" for i in range(min(args.amount, len(ranks))): player = Player().query().get(player_id=ranks[i].player_id.value) #print "%d\t%d\t%s\t%s,\t%s\t%s" % (i + 1, ranks[i].value.value, # player.nickname.value, player.firstname.value, # player.lastname.value, player.player_id.value) table.append([ i + 1, ranks[i].value.value, player.nickname.value, player.firstname.value, player.lastname.value, player.player_id.value ]) utils.print_table(table)
def match(args): def match_elo(rating): ratings = Rank_Elo.query().all() best = None deviation = 99999999 for r in ratings: if (best is None or abs(r.value.value - rating.value.value) < deviation) and r.player_id.value != rating.player_id.value: best = r deviation = abs(r.value.value - rating.value.value) return best def match_glicko(rating): print "Not implemented yet" return None """ Finds the best opponent for a given player. :param args: A list with arguments from the argument parser :type args: namespace """ match_funcs = {'elo': match_elo, 'glicko': match_glicko} rating = utils.get_rating(args) if rating is None: print "Player %s is not known." % args.player return print "Looking for the best opponent for player %s..." % args.player opponent = match_funcs[args.algorithm](rating) if opponent is None: print "No opponent found." return print "Best opponent for player %s with rating %d is:" % (args.player, rating.value.value) other = Player.query().get(player_id=opponent.player_id.value) print "\tPlayer %s with rating %d." % (other.nickname.value, opponent.value.value)
def history(args): if args.player1 == args.player2: print "Player1 and Player2 are equal. Use 'history <player>'." return # store all players in a dict (player_id --> player) and get player1/2 players = Player.query().all() pdict = {} for player in players: pdict[player.player_id.value] = player if player.nickname.value == args.player1: player1 = player if player.nickname.value == args.player2: player2 = player if args.player2 is None: print "Searching for the history of %s\n" % args.player1 # the table to print out table = [['Opponent', 'Outcome', 'Date']] # get all matches with player 1 matches = Match1on1.query().filter( player1=player1.player_id.value).filter( player2=player1.player_id.value).join_or().all() won = 0 lost = 0 draw = 0 # iterate over all matches for match in matches: # check who the opponent is and who actually won opponent = match.player1.value if match.outcome.value == 0.5: outcome = "Draw" draw += 1 if opponent == player1.player_id.value: opponent = match.player2.value if match.outcome.value == 1: outcome = "Won" won += 1 elif match.outcome.value == 0: lost += 1 outcome = "Lost" else: if match.outcome.value == 1: outcome = "Lost" lost += 1 elif match.outcome.value == 0: outcome = "Won" won += 1 table.append( [pdict[opponent].nickname.value, outcome, match.date.value]) # finally print the table utils.print_table(table) print "\nStatistics:" print "Won: %d\nLost: %d\nDraw: %d" % (won, lost, draw) else: #TODO modify this when IN (...) works print "Searching for the history of %s and %s\n" % (args.player1, args.player2) # the table to print out table = [['Winner', 'Date']] # get all matches with player 1 matches1 = Match1on1.query().filter( player1=player1.player_id.value).filter( player2=player1.player_id.value).join_or().all() # get all matches with player 2 matches2 = Match1on1.query().filter( player1=player2.player_id.value).filter( player2=player2.player_id.value).join_or().all() statistics = {args.player1: 0, args.player2: 0, 'Draw': 0} # Find the intersection of the two list. Other methods do not work # because the 'in' operator does not seem to work with instances matches = [ x for x in matches1 if [y for y in matches2 if y.match_id.value == x.match_id.value] ] for match in matches: if match.outcome.value == 0: nickname = pdict[match.player2.value].nickname.value table.append([nickname, match.date.value]) statistics[nickname] += 1 elif match.outcome.value == 1: nickname = pdict[match.player2.value].nickname.value table.append([nickname, match.date.value]) statistics[nickname] += 1 else: table.append(['Draw', match.date.value]) statistics['Draw'] += 1 # finally print the table utils.print_table(table) print "\nStatistics for %s:" % args.player1 print "Won: %d\nLost: %d\nDraw: %d" % ( statistics[args.player1], len(matches) - statistics[args.player1] - statistics["Draw"], statistics["Draw"]) print "\nStatistics for %s:" % args.player2 print "Won: %d\nLost: %d\nDraw: %d" % ( statistics[args.player2], len(matches) - statistics[args.player2] - statistics["Draw"], statistics["Draw"])
def predict(args): """ Reads match constellations from an input file and writes the results to a specified output file. :param args: A list with arguments from the argument parser :type args: namespace """ if os.path.abspath(args.ifile) == os.path.abspath(args.ofile): print "You tried to overwrite your input with your output file." print "Aborted." return if args.algorithm == "glicko": print "Not implemented yet" return try: modes = {True: "incremental", False: "non-incremental"} print "Predicting the matches in %s mode" % modes[args.incremental] print "Open %s and write into %s..." % (args.ifile, args.ofile) csvfile, reader, hasHeader = utils.get_csv(args.ifile) ofile = open(args.ofile, 'w') line = 0 if hasHeader: print "\tFirst line of csv file is ignored. It seems to be a " \ "header row.\n" # constants conf = utils.get_config(args) k = conf["elo.chess.k"] func = conf["elo.chess.function"] # Query all ratings and store it in a dictionary. This is done for # faster access and on-the-fly calculation of new elo values ratings = Rank_Elo.query().all() rdict = {} for r in ratings: player = Player.query().get(player_id=r.player_id.value) rdict[player.nickname.value] = r for row in reader: if line != 0 or (line == 0 and not hasHeader): ratings = (rdict.get(row[1], None), rdict.get(row[2], None)) if ratings[0] is None or ratings[1] is None: continue value1 = ratings[0].value.value value2 = ratings[1].value.value if (value1 > value2): outcome = 1 elif (value1 < value2): outcome = 0 else: outcome = 0.5 if args.incremental: result = elo.elo1on1(value1, value2, outcome, k, func) ratings[0].value = result[0] ratings[1].value = result[1] ofile.write("%s,%s,%s,%s\n" % (row[0], row[1], row[2], str(outcome))) elif line == 0 and hasHeader: ofile.write('"%s","%s","%s","Statistically most possible ' \ 'outcome"\n' % (row[0], row[1], row[2])) if line % 13 == 0: sys.stdout.write("\rWrote %d entries to the out file" % line) sys.stdout.flush() line = line + 1 print "\rWrote %d entries to the out file" % (line - (1 if hasHeader else 0)) csvfile.close() ofile.close() except csv.Error: print "Error importing %s in line %d" % (args.ifile, line) except IOError: print "One file is missing. Either %s or %s" % (args.ifile, args.ofile)
#!/usr/bin/env python # -*- coding: utf-8 -*- from pychallenge.models import Config, Match1on1, Player, Rank_Elo, Rank_Glicko if __name__ == "__main__": Config.create() Match1on1.create() Player.create() Rank_Elo.create() Rank_Glicko.create()
def history(args): if args.player1 == args.player2: print "Player1 and Player2 are equal. Use 'history <player>'." return # store all players in a dict (player_id --> player) and get player1/2 players = Player.query().all() pdict = {} for player in players: pdict[player.player_id.value] = player if player.nickname.value == args.player1: player1 = player if player.nickname.value == args.player2: player2 = player if args.player2 is None: print "Searching for the history of %s\n" % args.player1 # the table to print out table = [['Opponent', 'Outcome', 'Date']] # get all matches with player 1 matches = Match1on1.query().filter( player1=player1.player_id.value).filter( player2=player1.player_id.value).join_or().all() won = 0 lost = 0 draw = 0 # iterate over all matches for match in matches: # check who the opponent is and who actually won opponent = match.player1.value if match.outcome.value == 0.5: outcome = "Draw" draw += 1 if opponent == player1.player_id.value: opponent = match.player2.value if match.outcome.value == 1: outcome = "Won" won += 1 elif match.outcome.value == 0: lost += 1 outcome = "Lost" else: if match.outcome.value == 1: outcome = "Lost" lost += 1 elif match.outcome.value == 0: outcome = "Won" won += 1 table.append([pdict[opponent].nickname.value, outcome, match.date.value]) # finally print the table utils.print_table(table) print "\nStatistics:" print "Won: %d\nLost: %d\nDraw: %d" % (won, lost, draw) else: #TODO modify this when IN (...) works print "Searching for the history of %s and %s\n" % (args.player1, args.player2) # the table to print out table = [['Winner', 'Date']] # get all matches with player 1 matches1 = Match1on1.query().filter( player1=player1.player_id.value).filter( player2=player1.player_id.value).join_or().all() # get all matches with player 2 matches2 = Match1on1.query().filter( player1=player2.player_id.value).filter( player2=player2.player_id.value).join_or().all() statistics = {args.player1: 0, args.player2: 0, 'Draw': 0} # Find the intersection of the two list. Other methods do not work # because the 'in' operator does not seem to work with instances matches = [x for x in matches1 if [y for y in matches2 if y.match_id.value == x.match_id.value]] for match in matches: if match.outcome.value == 0: nickname = pdict[match.player2.value].nickname.value table.append([nickname, match.date.value]) statistics[nickname] += 1 elif match.outcome.value == 1: nickname = pdict[match.player2.value].nickname.value table.append([nickname, match.date.value]) statistics[nickname] += 1 else: table.append(['Draw', match.date.value]) statistics['Draw'] += 1 # finally print the table utils.print_table(table) print "\nStatistics for %s:" % args.player1 print "Won: %d\nLost: %d\nDraw: %d" % (statistics[args.player1], len(matches) - statistics[args.player1] - statistics["Draw"], statistics["Draw"]) print "\nStatistics for %s:" % args.player2 print "Won: %d\nLost: %d\nDraw: %d" % (statistics[args.player2], len(matches) - statistics[args.player2] - statistics["Draw"], statistics["Draw"])
def predict(args): """ Reads match constellations from an input file and writes the results to a specified output file. :param args: A list with arguments from the argument parser :type args: namespace """ if os.path.abspath(args.ifile) == os.path.abspath(args.ofile): print "You tried to overwrite your input with your output file." print "Aborted." return if args.algorithm == "glicko": print "Not implemented yet" return try: modes = {True: "incremental", False: "non-incremental"} print "Predicting the matches in %s mode" % modes[args.incremental] print "Open %s and write into %s..." % (args.ifile, args.ofile) csvfile, reader, hasHeader = utils.get_csv(args.ifile) ofile = open(args.ofile, 'w') line = 0 if hasHeader: print "\tFirst line of csv file is ignored. It seems to be a " \ "header row.\n" # constants conf = utils.get_config(args) k = conf["elo.chess.k"] func = conf["elo.chess.function"] # Query all ratings and store it in a dictionary. This is done for # faster access and on-the-fly calculation of new elo values ratings = Rank_Elo.query().all() rdict = {} for r in ratings: player = Player.query().get(player_id=r.player_id.value) rdict[player.nickname.value] = r for row in reader: if line != 0 or (line == 0 and not hasHeader): ratings = (rdict.get(row[1], None), rdict.get(row[2], None)) if ratings[0] is None or ratings[1] is None: continue value1 = ratings[0].value.value value2 = ratings[1].value.value if (value1 > value2): outcome = 1 elif (value1 < value2): outcome = 0 else: outcome = 0.5 if args.incremental: result = elo.elo1on1(value1, value2, outcome, k, func) ratings[0].value = result[0] ratings[1].value = result[1] ofile.write("%s,%s,%s,%s\n" % (row[0], row[1], row[2], str(outcome))) elif line == 0 and hasHeader: ofile.write('"%s","%s","%s","Statistically most possible ' \ 'outcome"\n' % (row[0], row[1], row[2])) if line % 13 == 0: sys.stdout.write("\rWrote %d entries to the out file" % line) sys.stdout.flush() line = line + 1 print "\rWrote %d entries to the out file" % ( line - (1 if hasHeader else 0)) csvfile.close() ofile.close() except csv.Error: print "Error importing %s in line %d" % (args.ifile, line) except IOError: print "One file is missing. Either %s or %s" % (args.ifile, args.ofile)