def generate_ranking(dao, now=datetime.now()): player_date_map = {} player_id_to_player_map = {} tournaments = dao.get_all_tournaments(regions=[dao.region_id]) for tournament in tournaments: print 'Processing:', tournament.name for player_id in tournament.players: player_date_map[player_id] = tournament.date # TODO add a default rating entry when we add it to the map for match in tournament.matches: if not match.winner in player_id_to_player_map: db_player = dao.get_player_by_id(match.winner) db_player.ratings[dao.region_id] = DEFAULT_RATING player_id_to_player_map[match.winner] = db_player if not match.loser in player_id_to_player_map: db_player = dao.get_player_by_id(match.loser) db_player.ratings[dao.region_id] = DEFAULT_RATING player_id_to_player_map[match.loser] = db_player winner = player_id_to_player_map[match.winner] loser = player_id_to_player_map[match.loser] rating_calculators.update_trueskill_ratings(dao.region_id, winner=winner, loser=loser) print 'Checking for player inactivity...' i = 1 players = player_id_to_player_map.values() sorted_players = sorted( players, key=lambda player: trueskill.expose(player.ratings[dao.region_id].trueskill_rating), reverse=True) ranking = [] for player in sorted_players: player_last_active_date = player_date_map.get(player.id) if player_last_active_date == None or dao.is_inactive(player, now) or not dao.region_id in player.regions: pass # do nothing, skip this player else: ranking.append(RankingEntry(i, player.id, trueskill.expose(player.ratings[dao.region_id].trueskill_rating))) i += 1 print 'Updating players...' for i, p in enumerate(players, start=1): dao.update_player(p) print 'Updated player %d of %d' % (i, len(players)) print 'Inserting new ranking...' dao.insert_ranking(Ranking(dao.region_id, now, [t.id for t in tournaments], ranking)) print 'Done!'
def quality_and_probability(players, names): p0, p1 = players[names[0]], players[names[1]] quality = trueskill.quality_1vs1(p0, p1) probability = arduino_map((1-quality)*100, 0, 100, 50, 100)/100 ex0, ex1 = trueskill.expose(p0), trueskill.expose(p1) if ex0 == ex1: favor = None elif ex0>ex1: favor = names[0] else: favor = names[1] return quality, probability, favor
def display(request): #this is the main view #it's going to get all of our awesome players from the database #and create a leaderboard time thing from them based on their #ratings...it sounds stupid simple but it will probably be harder than anything else here all_players = player.objects.all() player_list = {} final_list = [] player_skills = [] player_rounded_skills = [] for each in all_players: if each.wins + each.losses > 5: player_mu = each.mu player_sigma = each.sigma player_rating = Decimal(expose(Rating(float(player_mu), float(player_sigma)))) #if player_rating in player_list: # player_rating += Decimal(.000000000000000000000000001) player_list[player_rating] = each sorted_player_list = sorted(player_list, reverse=True) for each in sorted_player_list: final_list.append(player_list[each]) player_skills.append(each) index_list = range(1, len(all_players)+1) for each in player_skills: player_rounded_skills.append(round(each, 1)) zipped_list = zip(final_list, player_rounded_skills, index_list) return render(request, 'display.html', {'player_list': final_list, 'skill_list': player_skills, 'zipped_list':zipped_list, 'index_list': index_list, })
def calculate_score(self, comparison_pairs): """ Calculate scores for a set of comparisons :param comparisons: array of :return: dictionary key -> ScoredObject """ self.storage = {} self.opponents = {} self.ratings = {} trueskill.setup() keys = self.get_keys_from_comparison_pairs(comparison_pairs) # create default ratings for every available key for key in keys: rating = trueskill.Rating() self.ratings[key] = rating self.opponents[key] = set() self.storage[key] = ScoredObject( key=key, score=trueskill.expose(rating), variable1=rating.mu, variable2=rating.sigma, rounds=0, opponents=0, wins=0, loses=0, ) # calculate rating by for every match for comparison_pair in comparison_pairs: key1 = comparison_pair.key1 key2 = comparison_pair.key2 winning_key = comparison_pair.winning_key # skip incomplete comparisosns if winning_key is None: self._update_rounds_only(key1) self._update_rounds_only(key2) continue r1 = self.ratings[key1] r2 = self.ratings[key2] if winning_key == comparison_pair.key1: r1, r2 = trueskill.rate_1vs1(r1, r2) elif winning_key == comparison_pair.key2: r2, r1 = trueskill.rate_1vs1(r2, r1) else: raise InvalidWinningKeyException self._update_rating(key1, r1, key2, winning_key) self._update_rating(key2, r2, key1, winning_key) # return comparison results return self.storage
def generate_ranking(dao): dao.reset_all_player_ratings() player_date_map = {} now = datetime.now() player_id_to_player_map = dict((p.id, p) for p in dao.get_all_players()) tournaments = dao.get_all_tournaments() for tournament in tournaments: print 'Processing:', tournament.name for player_id in tournament.players: player_date_map[player_id] = tournament.date for match in tournament.matches: winner = player_id_to_player_map[match.winner] loser = player_id_to_player_map[match.loser] rating_calculators.update_trueskill_ratings(winner=winner, loser=loser) excluded_players = set([p.id for p in dao.get_excluded_players()]) i = 1 players = player_id_to_player_map.values() sorted_players = sorted(players, key=lambda player: trueskill.expose(player.rating.trueskill_rating), reverse=True) ranking = [] for player in sorted_players: player_last_active_date = player_date_map.get(player.id) if player_last_active_date == None or dao.is_inactive(player, now) or player.id in excluded_players: pass # do nothing, skip this player else: ranking.append(RankingEntry(i, player.id, trueskill.expose(player.rating.trueskill_rating))) i += 1 print 'Updating players...' for p in players: dao.update_player(p) print 'Inserting new ranking...' dao.insert_ranking(Ranking(now, [t.id for t in tournaments], ranking)) print 'Done!'
def quality_json(rating): """ Convert a Rating into something more JSON serializeable, includes 'exposure' data :type rating: Rating :param rating: the rating to convert :param result: the result sent in initial payload :rtype: dict :return: dict """ return {'mu':rating.mu, 'sigma':rating.sigma, 'exposure':trueskill.expose(rating)}
def forwards(self, orm): ids = orm['auth.User'].objects.values_list('id', flat=True) users = {i: trueskill.Rating() for i in ids} for game in orm.Game.objects.filter(confirmed=True).order_by('date_created'): wid = game.winner.id lid = game.loser.id users[wid], users[lid] = trueskill.rate_1vs1(users[wid], users[lid]) for id, rating in users.iteritems(): u = orm.Rating.objects.get(user__id=id) u.ts_rating = rating u.exposure = trueskill.expose(u.ts_rating) u.save()
def _update_rating(self, key, new_rating, opponent_key, winning_key): self.ratings[key] = new_rating self.opponents[key].add(opponent_key) wins = self.storage[key].wins loses = self.storage[key].loses # winning_key == None should not increase total wins or loses self.storage[key] = ScoredObject( key=key, score=trueskill.expose(new_rating), variable1=new_rating.mu, variable2=new_rating.sigma, rounds=self.storage[key].rounds + 1, opponents=len(self.opponents[key]), wins=wins + 1 if winning_key == key else wins, loses=loses + 1 if winning_key == opponent_key else loses, )
def signup(): db = get_db() try: rating = ts.Rating() db.execute(''' INSERT INTO player (alias, nick, mu, sigma, exposure, won, lost, active) VALUES (?, ?, ?, ?, ?, 0, 0, 1);''', (request.form['alias'], request.form['nick'], rating.mu, rating.sigma, ts.expose(rating))) db.commit() except sqlite3.IntegrityError as e: flash(str(e)) return redirect(url_for('index'))
def save(self, *args, **kwargs): self.exposure = trueskill.expose(self.ts_rating) super(Rating, self).save(*args, **kwargs)
def record(): db = get_db() p1 = request.form['p1'] s1 = int(request.form['s1']) p2 = request.form['p2'] s2 = int(request.form['s2']) hi, lo = max(s1, s2), min(s1, s2) if (not ((hi == 2 and lo == 0) or (hi == 2 and lo == 1) or (hi == 3 and lo == 0) or (hi == 3 and lo == 1) or (hi == 3 and lo == 2))): flash('Ladder is based on 3 or 5 game matches only') return redirect(url_for('index')) if p1 == p2: flash('Match players must be different.') return redirect(url_for('index')) # check if this was a scheduled match scheduledrow = db.execute(''' SELECT (s.id) FROM schedule s JOIN player p1 ON s.p1 = p1.id JOIN player p2 ON s.p2 = p2.id WHERE p1.alias=? AND p2.alias=? OR p1.alias=? AND p2.alias=?;''', (p1, p2, p2, p1)).fetchone() scheduled = scheduledrow is not None if scheduled: db.execute('DELETE FROM schedule WHERE id=?;', (scheduledrow[0],)) if s1 > s2: win_alias, win_score, lose_alias, lose_score = p1, s1, p2, s2 else: win_alias, win_score, lose_alias, lose_score = p2, s2, p1, s1 date_string = request.form['date'] + ' ' if ':' in request.form['time']: date_string += request.form['time'] + ' ' else: date_string += request.form['time'] + ':00 ' date_string += 'PM' if 'ampm' in request.form else 'AM' try: date = datetime.strptime(date_string, "%m/%d/%Y %I:%M %p") except: flash('Invalid time format') return redirect(url_for('index')) db.execute(''' INSERT INTO match (winner, loser, winscore, losescore, date, scheduled) SELECT w.id, l.id, ?, ?, ?, ? FROM player w JOIN player l WHERE w.alias = ? AND l.alias = ?;''', (win_score, lose_score, date, scheduled, win_alias, lose_alias)) def get_rating(alias): sql = 'SELECT mu, sigma FROM player WHERE alias=?;' row = db.execute(sql, (alias,)).fetchone() if row is None: flash('Alias ' + alias + ' does not exist.') return None return ts.Rating(mu=row['mu'], sigma=row['sigma']) win_rating = get_rating(win_alias) lose_rating = get_rating(lose_alias) if win_rating is None or lose_rating is None: return redirect(url_for('index')) win_rating, lose_rating = ts.rate_1vs1(win_rating, lose_rating) win_exposure = ts.expose(win_rating); lose_exposure = ts.expose(lose_rating); db.execute(''' UPDATE player SET exposure=?, mu=?, sigma=?, won=won+1 WHERE alias=?;''', (win_exposure, win_rating.mu, win_rating.sigma, win_alias)); db.execute(''' UPDATE player SET exposure=?, mu=?, sigma=?, lost=lost+1 WHERE alias=?;''', (lose_exposure, lose_rating.mu, lose_rating.sigma, lose_alias)); db.commit() return redirect(url_for('index'))
def generate_ranking(dao, now=datetime.now(), day_limit=60, num_tourneys=2, tournament_qualified_day_limit=999): player_date_map = {} player_id_to_player_map = {} tournament_qualified_date = (now - timedelta(days=tournament_qualified_day_limit)) print('Qualified Date: ' + str(tournament_qualified_date)) tournaments = dao.get_all_tournaments(regions=[dao.region_id]) for tournament in tournaments: if tournament.excluded is True: print 'Tournament Excluded:' print 'Excluded - ' + str(tournament.name) continue if tournament_qualified_date <= tournament.date: print 'Processing:', tournament.name.encode('utf-8'), str(tournament.date) for player_id in tournament.players: player_date_map[player_id] = tournament.date # TODO add a default rating entry when we add it to the map for match in tournament.matches: if match.excluded is True: print('match excluded:') print('Tournament: ' + str(tournament.name)) print(str(match)) continue # don't count matches where either player is OOR winner = dao.get_player_by_id(match.winner) if dao.region_id not in winner.regions: continue loser = dao.get_player_by_id(match.loser) if dao.region_id not in loser.regions: continue if match.winner not in player_id_to_player_map: db_player = dao.get_player_by_id(match.winner) db_player.ratings[dao.region_id] = model.Rating() player_id_to_player_map[match.winner] = db_player if match.loser not in player_id_to_player_map: db_player = dao.get_player_by_id(match.loser) db_player.ratings[dao.region_id] = model.Rating() player_id_to_player_map[match.loser] = db_player winner = player_id_to_player_map[match.winner] loser = player_id_to_player_map[match.loser] rating_calculators.update_trueskill_ratings( dao.region_id, winner=winner, loser=loser) print 'Checking for player inactivity...' rank = 1 players = player_id_to_player_map.values() sorted_players = sorted( players, key=lambda player: trueskill.expose(player.ratings[dao.region_id].trueskill_rating()), reverse=True) ranking = [] for player in sorted_players: player_last_active_date = player_date_map.get(player.id) if player_last_active_date is None or \ dao.is_inactive(player, now, day_limit, num_tourneys) or \ dao.region_id not in player.regions: pass # do nothing, skip this player else: ranking.append(model.RankingEntry( rank=rank, player=player.id, rating=trueskill.expose(player.ratings[dao.region_id].trueskill_rating()))) rank += 1 print 'Updating players...' for i, p in enumerate(players, start=1): dao.update_player(p) # TODO: log somewhere later # print 'Updated player %d of %d' % (i, len(players)) print 'Inserting new ranking...' dao.insert_ranking(model.Ranking( id=ObjectId(), region=dao.region_id, time=now, tournaments=[t.id for t in tournaments], ranking=ranking)) print 'Done!'
def _create_ranking_from_tournament_list( dao, tournaments, now, day_limit, num_tourneys, tournament_qualified_day_limit, ranking_to_diff_against): player_date_map = {} player_id_to_player_map = {} tournament_qualified_date = (now - timedelta(days=tournament_qualified_day_limit)) print('Qualified Date: ' + str(tournament_qualified_date)) for tournament in tournaments: if tournament_qualified_date <= tournament.date: print 'Processing:', tournament.name.encode('utf-8'), str(tournament.date) for player_id in tournament.players: player_date_map[player_id] = tournament.date # TODO add a default rating entry when we add it to the map for match in tournament.matches: if match.excluded is True: print('match excluded:') print('Tournament: ' + str(tournament.name)) print(str(match)) continue if match.winner not in player_id_to_player_map: db_player = dao.get_player_by_id(match.winner) db_player.ratings[dao.region_id] = model.Rating() player_id_to_player_map[match.winner] = db_player if match.loser not in player_id_to_player_map: db_player = dao.get_player_by_id(match.loser) db_player.ratings[dao.region_id] = model.Rating() player_id_to_player_map[match.loser] = db_player winner = player_id_to_player_map[match.winner] loser = player_id_to_player_map[match.loser] rating_calculators.update_trueskill_ratings( dao.region_id, winner=winner, loser=loser) print 'Checking for player inactivity...' rank = 1 players = player_id_to_player_map.values() sorted_players = sorted( players, key=lambda player: (trueskill.expose(player.ratings[dao.region_id].trueskill_rating()), player.name), reverse=True) ranking = [] for player in sorted_players: player_last_active_date = player_date_map.get(player.id) if _is_player_inactive(dao, player, tournaments, player_last_active_date, now, day_limit, num_tourneys): pass # do nothing, skip this player else: ranking.append(model.RankingEntry( rank=rank, player=player.id, rating=trueskill.expose(player.ratings[dao.region_id].trueskill_rating()), previous_rank=ranking_to_diff_against.get_ranking_for_player_id(player.id) if ranking_to_diff_against else None)) rank += 1 print 'Updating players...' for i, p in enumerate(players, start=1): dao.update_player(p) # TODO: log somewhere later # print 'Updated player %d of %d' % (i, len(players)) print 'Returning new ranking...' return model.Ranking( id=ObjectId(), region=dao.region_id, time=now, tournaments=[t.id for t in tournaments], ranking=ranking)
def display_player(request, given_player): player_name = player.objects.get(name=given_player) matches = match.objects.filter(players__name=player_name.name) player_rating = expose(Rating(float(player_name.mu), float(player_name.sigma))) return render(request,'player_display.html',{'matches':matches, 'player':player_name, 'rating': player_rating})
def get_score(self): """ :rtype : float """ return (trueskill.expose(self.rating) + trueskill.global_env().mu) * 3
def elo(self, rating=None): if rating is None: rating = self.rating return trueskill.expose(rating)
def calculate_score_1vs1(self, key1_scored_object, key2_scored_object, winning_key, other_comparison_pairs): """ Calcualtes the scores for a new 1vs1 comparison without re-calculating all previous scores :param key1_scored_object: Contains score parameters for key1 :param key2_scored_object: Contains score parameters for key2 :param winning_key: indicates with key is the winning key :param other_comparison_pairs: Contains all previous comparison_pairs that the 2 keys took part in. This is a subset of all comparison pairs and is used to calculate round, wins, loses, and opponent counts :return: tuple of ScoredObject (key1, key2) """ self.storage = {} self.opponents = {} self.ratings = {} trueskill.setup() key1 = key1_scored_object.key key2 = key2_scored_object.key # Note: if value are None, trueskill.Rating will use default mu 25 and sigma 8.333 r1 = trueskill.Rating(mu=key1_scored_object.variable1, sigma=key1_scored_object.variable2) r2 = trueskill.Rating(mu=key2_scored_object.variable1, sigma=key2_scored_object.variable2) if winning_key == key1: r1, r2 = trueskill.rate_1vs1(r1, r2) elif winning_key == key2: r2, r1 = trueskill.rate_1vs1(r2, r1) else: raise InvalidWinningKeyException self.ratings[key1] = r1 self.ratings[key2] = r2 for key in [key1, key2]: self.opponents[key] = set() self.storage[key] = ScoredObject( key=key, score=trueskill.expose(self.ratings[key]), variable1=self.ratings[key].mu, variable2=self.ratings[key].sigma, rounds=0, opponents=0, wins=0, loses=0, ) # calculate opponents, wins, loses, rounds for every match for key1 and key2 for comparison_pair in other_comparison_pairs + [ComparisonPair(key1, key2, winning_key)]: cp_key1 = comparison_pair.key1 cp_key2 = comparison_pair.key2 cp_winning_key = comparison_pair.winning_key if cp_key1 == key1 or cp_key1 == key2: if cp_winning_key is None: self._update_rounds_only(cp_key1) else: self._update_result_stats(cp_key1, cp_key2, cp_winning_key) if cp_key2 == key1 or cp_key2 == key2: if cp_winning_key is None: self._update_rounds_only(cp_key2) else: self._update_result_stats(cp_key2, cp_key1, cp_winning_key) return (self.storage[key1], self.storage[key2])