Пример #1
0
def rank_players(ratings):
    ordered = sorted(ratings.items(),
                     key=lambda x: ts.expose(x[1]),
                     reverse=True)
    result = []
    for rank in ordered:
        player, rating = rank
        result.append((player, rating, ts.expose(rating)))
    return result
Пример #2
0
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!'
Пример #3
0
def generate_ranking(dao, now=datetime.now(), day_limit=60, num_tourneys=2):
    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.encode('utf-8')

        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...'
    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 == None or dao.is_inactive(player, now, day_limit, num_tourneys) or not dao.region_id in player.regions:
            pass # do nothing, skip this player
        else:
            ranking.append(RankingEntry(rank, player.id, 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)
        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!'
Пример #4
0
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
Пример #5
0
 def clout(self) -> int:
     """
     Return a public-facing estimation of the skill rating.
     This is the (conservative) min-rating clout
     or 2 sigmas below current actual
     """
     return int(expose(self.rating) * SCALAR)
Пример #6
0
 def __init__(self, pid, name, skill, updated):
     self.pid = pid
     self.name = name
     self._ts_mu = skill.mu
     self._ts_sigma = skill.sigma
     self.rating = trueskill.expose(skill)
     self.updated = updated
Пример #7
0
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, })
Пример #8
0
def GetSortedRanking_(players):
    rankings = {}
    for p in players:
        rankings[p] = (ts.expose(players[p]), players[p])
    return sorted(rankings.items(),
                  key=lambda kv: (kv[1][0], kv[0]),
                  reverse=True)
Пример #9
0
    def calculate_score(self, comparison_pairs):
        """
        Calculate scores for a set of comparison_pairs
        :param comparison_pairs: array of comparison_pairs
        :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
            winner = comparison_pair.winner

            # skip incomplete comparisosns
            if winner is None:
                self._update_rounds_only(key1)
                self._update_rounds_only(key2)
                continue

            r1 = self.ratings[key1]
            r2 = self.ratings[key2]

            key1_winner = winner == ComparisonWinner.key1
            key2_winner = winner == ComparisonWinner.key2

            if key1_winner:
                r1, r2 = trueskill.rate_1vs1(r1, r2)
            elif key2_winner:
                r2, r1 = trueskill.rate_1vs1(r2, r1)
            elif winner == ComparisonWinner.draw:
                r1, r2 = trueskill.rate_1vs1(r1, r2, drawn=True)
            else:
                raise InvalidWinnerException

            self._update_rating(key1, r1, key2, key1_winner, key2_winner)
            self._update_rating(key2, r2, key1, key2_winner, key1_winner)

        # return comparison results
        return self.storage
Пример #10
0
def compute_ratings(matches):
    ratings = {}
    histories = {}
    new_player_history = []
    stats = {}
    new_player_stats = []

    for _, match in matches.iterrows():
        for name in set(itertools.chain(stats.keys(), match['player_stats'])):
            stats.setdefault(name, new_player_stats[:])
            if name in match['player_stats']:
                stats[name].append(match['player_stats'][name])
            else:
                stats[name].append(None)
        new_player_stats.append(None)

        new_ratings = trueskill.rate((
            {
                name: ratings.get(name, trueskill.Rating())
                for name in match["win"]
            },
            {
                name: ratings.get(name, trueskill.Rating())
                for name in match["loss"]
            },
        ))
        for new_rating in new_ratings:
            ratings.update(new_rating)

        new_player_history.append(trueskill.Rating())
        for name in ratings:
            histories.setdefault(name, new_player_history[:])
            histories[name].append(ratings[name])

    rows = [(name, rating, stats[name], histories[name])
            for name, rating in ratings.items()]
    ratings = pd.DataFrame.from_records(
        rows,
        columns=["Name", "trueskill.Rating", "stats", "history"],
        index="Name")
    ratings.index.name = None

    boundaries = compute_division_boundaries()
    ratings["μ"] = ratings["trueskill.Rating"].apply(lambda rating: rating.mu)
    ratings["σ"] = ratings["trueskill.Rating"].apply(
        lambda rating: rating.sigma)
    ratings["Rating"] = ratings["trueskill.Rating"].apply(
        lambda rating: trueskill.expose(rating))
    ratings["Rank"] = ratings["Rating"].apply(
        lambda rating: find_division(boundaries, rating))
    ratings["Record"] = ratings["stats"].apply(
        lambda stats: compute_record(stats))
    ratings["Streak"] = ratings["stats"].apply(
        lambda stats: compute_streak(stats))
    ratings["Champs"] = ratings["stats"].apply(
        lambda stats: tuple(game["champ"] for game in stats if game))
    ratings.sort_values("Rating", ascending=False, inplace=True)

    return ratings
Пример #11
0
    def elo(self):
        rating = trueskill.expose(self.rating)

        # Set elo floor to 0
        if rating < 0.05:
            return 0
        else:
            return int(rating)
Пример #12
0
    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
Пример #13
0
 def skill(self, new_skill):
     try:
         mu, sigma = new_skill.mu, new_skill.sigma
         rating = trueskill.expose(new_skill)
     except AttributeError:
         # swallow the exception but don't modify values
         pass
     else:
         self._ts_mu, self._ts_sigma = mu, sigma
         self.rating = rating
Пример #14
0
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!'
Пример #15
0
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)}
Пример #16
0
    def new_trueskill_rating(self, player_id, game_id, rating) -> None:
        """

        :param player_id: The id of the player to update
        :param game_id: The id of the game that cause the update
        :param Rating rating: The new player rating
        :return:
        """
        trueskill_update = (player_id, game_id, rating.mu, rating.sigma, expose(rating))
        sql = ''' INSERT INTO trueskills(discord_id, game_id, mu, sigma, trueskill) VALUES(?, ?, ?, ?, ?) '''
        cur = self.conn.cursor()
        cur.execute(sql, trueskill_update)
        self.conn.commit()
Пример #17
0
    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()
Пример #18
0
def main():
    parser = argparse.ArgumentParser(description='MadCars Bot Competition')
    parser.add_argument('-n',
                        '--num-games',
                        type=int,
                        help='Total number of games',
                        required=True)
    parser.add_argument('-d',
                        '--model-dir',
                        type=str,
                        help='NN model root directory',
                        required=True)
    parser.add_argument('-l',
                        '--log-interval',
                        type=int,
                        help='Rating print interval',
                        default=50)
    parser.add_argument('-c',
                        '--cache-path',
                        type=str,
                        default='competition_cache.json',
                        help='Ragings JSON cache')
    args = parser.parse_args()

    model_dir: str = args.model_dir
    num_games: int = args.num_games
    cache_path: str = args.cache_path
    log_interval: int = args.log_interval

    ts.setup(draw_probability=0.0001)
    loop = events.new_event_loop()
    events.set_event_loop(loop)

    clients = get_simple_bots() + get_nn_bots(model_dir)
    clients = load_ratings(cache_path, clients)

    games_played = 0

    while games_played < num_games:
        games_played += log_interval
        ratings = run_competition(clients, log_interval)
        ratings = sorted(ratings, key=lambda t: -ts.expose(t[1]))
        save_ratings(cache_path, clients)
        print(f'-- RATINGS {games_played} --')
        for name, rating in ratings:
            print(
                f'{ts.expose(rating):4.1f} ({rating.mu:4.1f} +- {rating.sigma * 3:4.1f}): {name:<32}'
            )
Пример #19
0
    def _update_rating(self, key, new_rating, opponent_key, did_win, did_lose):
        self.ratings[key] = new_rating
        self.opponents[key].add(opponent_key)
        wins = self.storage[key].wins
        loses = self.storage[key].loses

        # winner == 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 did_win else wins,
            loses=loses + 1 if did_lose else loses,
        )
Пример #20
0
    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,
        )
Пример #21
0
def plot_historical_rankings(historical_ratings):
    fig = plt.figure(figsize=(10, 5))
    ax = plt.subplot(111)
    for player, history in historical_ratings.items():
        rating_values = [ts.expose(x) for x in history]
        ax.plot(range(len(rating_values)),
                rating_values,
                label=player,
                marker='x')
    ax.grid()
    ax.set_xlabel("# Games")
    ax.set_ylabel("Rank")
    ax.set_title("Ranking over time")
    # Some fancy stuff to put the legend outside the plot
    box = ax.get_position()
    ax.set_position([box.x0, box.y0, box.width * 0.8, box.height])
    ax.legend(loc='center left', bbox_to_anchor=(1, 0.5))
Пример #22
0
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'))
Пример #23
0
 def to_series(self) -> pd.Series:
     return pd.Series({
         'name':
         self.name,
         'rating':
         trueskill.expose(self.rating),
         'wins':
         self.wins,
         'losses':
         self.losses,
         'kills':
         self.kills,
         'deaths':
         self.deaths,
         'assists':
         self.assists,
         'kda': (self.kills + self.assists) / (self.deaths or 1),
         'champs':
         self.unique_champs,
     })
Пример #24
0
def update(match_id, season_id, r_ids, b_ids, r_score, b_score):
    def get_rates(ids):
        # Get musigma user / create it if none
        res = []
        for user_id in ids:
            pl = orm.to_json(
                orm.get_user_musigma_team.first(user_id, season_id))
            rating = Rating(float(pl['mu']), float(
                pl['sigma'])) if pl is not None else Rating()
            res.append(rating)

        return res

    env_name = 'global' if not season_id else 'season'
    set_trueskill_env(env_name)
    env = get_trueskill_env(env_name)

    r_ids = [user_id for user_id in r_ids if user_id is not None]
    b_ids = [user_id for user_id in b_ids if user_id is not None]

    r_rates = get_rates(r_ids)
    b_rates = get_rates(b_ids)
    new_r_rates, new_b_rates = rate([r_rates, b_rates],
                                    ranks=[b_score,
                                           r_score])  # Lower is better

    new_rates = new_r_rates + new_b_rates
    new_expositions = [expose(r) for r in new_rates]

    with orm.transaction():
        for idx, user_id in enumerate(r_ids + b_ids):
            # Init user to default stats if not already in base
            user_musigma_team = orm.to_json(
                orm.get_user_musigma_team(user_id, season_id))
            if len(user_musigma_team) == 0:
                init_user(user_id, season_id)

            orm.create_user_musigma_team(user_id, match_id, season_id,
                                         new_expositions[idx],
                                         new_rates[idx].mu,
                                         new_rates[idx].sigma)
Пример #25
0
 def get_score(self):
     """
     :rtype : float
     """
     return (trueskill.expose(self.rating) + trueskill.global_env().mu) * 3
Пример #26
0
 def get_score(self):
     """
     :rtype : float
     """
     return (trueskill.expose(self.rating) + trueskill.global_env().mu) * 3
Пример #27
0
 def exposure(self):
     return trueskill.expose(self._rating)
Пример #28
0
    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])
Пример #29
0
    def calculate_score_1vs1(self, key1_scored_object, key2_scored_object,
                             winner, other_comparison_pairs):
        """
        Calculates 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 winner: indicates comparison winner
        :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 winner == ComparisonWinner.key1:
            r1, r2 = trueskill.rate_1vs1(r1, r2)
        elif winner == ComparisonWinner.key2:
            r2, r1 = trueskill.rate_1vs1(r2, r1)
        elif winner == ComparisonWinner.draw:
            r1, r2 = trueskill.rate_1vs1(r1, r2, drawn=True)
        else:
            raise InvalidWinnerException

        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, winner)]):
            cp_key1 = comparison_pair.key1
            cp_key2 = comparison_pair.key2
            cp_winner = comparison_pair.winner
            cp_key1_winner = cp_winner == ComparisonWinner.key1
            cp_key2_winner = cp_winner == ComparisonWinner.key2

            if cp_key1 == key1 or cp_key1 == key2:
                if cp_winner is None:
                    self._update_rounds_only(cp_key1)
                else:
                    self._update_result_stats(cp_key1, cp_key2, cp_key1_winner,
                                              cp_key2_winner)

            if cp_key2 == key1 or cp_key2 == key2:
                if cp_winner is None:
                    self._update_rounds_only(cp_key2)
                else:
                    self._update_result_stats(cp_key2, cp_key1, cp_key2_winner,
                                              cp_key1_winner)

        return (self.storage[key1], self.storage[key2])
Пример #30
0
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})
Пример #31
0
def update_ratings_log(tm_rtngs, event, cnt):
    d = {tm: trueskill.expose(rtng) for (tm, rtng) in tm_rtngs.items()}
    d['event'] = event
    d['cnt'] = cnt
    return d
Пример #32
0
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'))
Пример #33
0
                continue  # duel
            if len(set(thisRating)) != len(thisRating):
                print('Players are not unique')
                continue  # same players
            print('Game is ok')

            thisRates = []
            for player in thisRating:
                if player not in players:
                    rating[player] = trueskill.Rating()
                    players.add(player)
                thisRates.append((rating[player], ))
            thisRates = trueskill.rate(thisRates)
            for (player, rate) in zip(thisRating, thisRates):
                rating[player] = rate[0]

    return rating


rating = getRating()
sortedRating = sorted(rating.items(),
                      key=lambda kv: trueskill.expose(kv[1]),
                      reverse=True)

result = ""
for (num, rate) in enumerate(sortedRating):
    result += '{}) [{}](https://aicups.ru{}) ({})\n'.format(
        num + 1, rate[0][0], rate[0][1], str(rate[1]))
with open('rating.txt', 'w', encoding='utf8') as f:
    f.write(result)
Пример #34
0
def generate_ranking(dao,
                     now=datetime.now(),
                     day_limit=60,
                     num_tourneys=2,
                     tournament_qualified_day_limit=999):
    try:
        logger.info('Beginning ranking calculation for ' + str(dao.region_id))

        player_date_map = {}
        player_id_to_player_map = {}
        ranking_tournaments = []

        tournament_qualified_date = (
            now - timedelta(days=tournament_qualified_day_limit))
        print('Qualified Date: ' + str(tournament_qualified_date))
        logger.info('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)
                logger.warning('Tournament Excluded: ' + str(tournament.name))
                continue

            if tournament_qualified_date <= tournament.date:
                ranking_tournaments.append(tournament)

                print 'Processing:', tournament.name.encode('utf-8'), str(
                    tournament.date)
                logger.info('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))
                        logger.debug('Match excluded: ' + str(match) +
                                     ' Tournament: ' + str(tournament.name))
                        continue

                    logger.debug('Getting winner and loser')

                    # don't count matches where either player is OOR
                    winner = dao.get_player_by_id(match.winner)
                    logger.debug('Winner: ' + str(winner))
                    if winner is None:
                        logger.warning(
                            'Player found as NoneType. Skipping match')
                        continue
                    elif dao.region_id not in winner.regions:
                        continue

                    loser = dao.get_player_by_id(match.loser)
                    logger.debug('Loser: ' + str(loser))
                    if loser is None:
                        logger.warning(
                            'Player found as NoneType. Skipping match')
                        continue
                    elif 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)
            else:
                logger.debug('Tournament ' + str(tournament.name) +
                             ' outside qualified date. Skipping.')

        print 'Checking for player inactivity...'
        logger.info('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:
            if player is None:
                logger.warning(
                    'NoneType player found while checking inactivity. Skipping.'
                )
                continue

            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:
                logger.debug('Player ' + player.name +
                             ' outside of ranking criteria. Skipping.')
                pass  # do nothing, skip this player
            else:
                logger.debug('Player ' + player.name + ' updating.')
                ranking.append(
                    model.RankingEntry(
                        rank=rank,
                        player=player.id,
                        rating=trueskill.expose(
                            player.ratings[dao.region_id].trueskill_rating())))
                rank += 1

        print 'Updating players...'
        logger.info('Updating players...')
        for i, p in enumerate(players, start=1):
            if p is None:
                logger.warning(
                    'NoneType player found while updating. Skipping.')
                continue
            logger.debug('Updating player ' + p.name)
            dao.update_player(p)
            # TODO: log somewhere later
            # print 'Updated player %d of %d' % (i, len(players))

        print 'Inserting new ranking...'
        logger.info('Inserting new ranking...')
        dao.insert_ranking(
            model.Ranking(id=ObjectId(),
                          region=dao.region_id,
                          time=now,
                          tournaments=[t.id for t in ranking_tournaments],
                          ranking=ranking))

        print 'Done!'
        logger.info('Done!')
    except Exception as e:
        print str(e)
        logger.error(str(e))
        tb = traceback.format_exc()
        logging.error(tb)
Пример #35
0
def calc_leaderboard(state):
    return [(p, ts.expose(r)) for p, r in state.items()]
Пример #36
0
 def public_rating(self):
     # trueskill mu-3*sigma ratings are usually from 0-50,
     # so we double them to 0-100
     return 2*trueskill.expose(self.rating)
Пример #37
0
 def elo(self, rating=None):
     if rating is None:
         rating = self.rating
     return trueskill.expose(rating)
Пример #38
0
def ComputeRatingsAndRecords(conn, singles, doubles, verbose):
    temp_players = GetAllPlayers(conn)

    playerNames = GetIdPlayerNameDict(conn)

    players = {}
    playerRecords = {}
    playerProgress = {}

    for p in temp_players:
        pid = p['id']
        players[pid] = ts.Rating()
        playerRecords[pid] = (0, 0, 0)
        playerProgress[pid] = []

    games = GetAllGames(conn)
    tSkill = ts.TrueSkill()

    lastId = 0
    for g in games:
        p = (g['player1'], g['player2'], g['player3'], g['player4'])

        ok = False
        if p[1] == 0 and singles:
            team1 = {p[0]: players[p[0]]}
            team2 = {p[2]: players[p[2]]}
            ok = True
        if p[1] != 0 and doubles:
            team1 = {p[0]: players[p[0]], p[1]: players[p[1]]}
            team2 = {p[2]: players[p[2]], p[3]: players[p[3]]}
            ok = True

        if not ok:
            continue

        s = (g['score1'], g['score2'])
        am = g['gametype'] == 1

        for i in range(0, 4):
            if p[i] == 0:
                continue
            (win, draw, loss) = playerRecords[p[i]]
            myScoreIndex = 0 if i < 2 else 1
            otherScoreIndex = 1 - myScoreIndex
            if s[0] == s[1]:
                draw += 1
            if s[myScoreIndex] > s[otherScoreIndex]:
                win += 1
            if s[myScoreIndex] < s[otherScoreIndex]:
                loss += 1

            playerRecords[p[i]] = (win, draw, loss)

        newRatings = flatten(PlayGame_(tSkill, team1, team2, s[0], s[1], am))

        if verbose:
            if p[1] == 0:
                print("({}) vs ({})  {}-{}   {}".format(
                    playerNames[p[0]], playerNames[p[2]], s[0], s[1],
                    "Americano" if am else ""))
            else:
                print("({} {})  vs ({}  {})    {}-{}   {}".format(
                    playerNames[p[0]], playerNames[p[1]], playerNames[p[2]],
                    playerNames[p[3]], s[0], s[1], "Americano" if am else ""))

        for t in newRatings:
            exp = ts.expose(newRatings[t])
            if verbose:
                diffMu = newRatings[t].mu - players[t].mu
                diffRank = exp - ts.expose(players[t])
                print("\t{}: mu:{}  rank:{}".format(playerNames[t], diffMu,
                                                    diffRank))
            players[t] = newRatings[t]
            if len(playerProgress[t]) == 0:
                playerProgress[t].append((g['id'] - 1, 0.0))
            playerProgress[t].append((g['id'], exp))
        lastId = g['id']

    toRemove = []
    for t in playerProgress:
        if len(playerProgress[t]) == 0:
            toRemove.append(t)
        else:
            last = playerProgress[t][-1]
            if last != None and last[0] != lastId:
                playerProgress[t].append((lastId, last[1]))

    if singles != doubles and len(toRemove) > 0:
        for t in toRemove:
            del players[t]
            del playerRecords[t]
            del playerProgress[t]

    return (players, playerRecords, playerProgress)
Пример #39
0
            winners.append(team_ratings[team])

        losers = []
        for team in match['alliances'][loser]['team_keys']:
            if team not in team_ratings:
                team_ratings[team] = trueskill.Rating()

            losers.append(team_ratings[team])

        ratings_obj = [tuple(winners), tuple(losers)]

        ratings_obj = trueskill.rate(ratings_obj, ranks=outcome)

        for idx, team in enumerate(match['alliances'][winner]['team_keys']):
            team_ratings[team] = ratings_obj[0][idx]

        for idx, team in enumerate(match['alliances'][loser]['team_keys']):
            team_ratings[team] = ratings_obj[1][idx]

ratings_list = []
for team in team_ratings:
    ratings_list.append({
        'team': team,
        'rating': trueskill.expose(team_ratings[team])
    })

ratings_list = sorted(ratings_list, key=lambda k: k['rating'], reverse=True)
gen.listOfDictToCSV(dist + ' TrueSkill Ratings', ratings_list,
                    ['team', 'rating'])
Пример #40
0
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)
Пример #41
0
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!'
Пример #42
0
                beta=100.0,
                tau=2.0,
                draw_probability=0.01,
                backend="scipy")
env = gym.make("hex-v0", opponent_policy=None, board_size=5)
env.reset()
sim = env.simulator
agent_pool = [MCTSAgent(sim, depth=d) for d in [10, 50, 100, 250, 500, 750, 1000, 1250, 1500]]
agent_pool += [RandomAgent(board_size=5)]

for game_idx in range(5000):
    # pick the agent we are most uncertain about
    sigmas = [agent.rating.sigma for agent in agent_pool]
    player1_idx = np.argmax(sigmas)
    player1 = agent_pool[player1_idx]
    player2 = find_match(player1, agent_pool)
    print("---")
    print(f"MATCH {game_idx}: {player1} vs. {player2}")
    play_match(player1, player2, sim=sim)
    leaderboard = sorted(agent_pool,
                         key=lambda x: trueskill.expose(x.rating),
                         reverse=True)
    for agent in leaderboard:
        print(f"    {agent} mu:{agent.rating.mu:.2f} sigma:{agent.rating.sigma:.2f}")

ratings = {str(agent): {"mu": agent.rating.mu, "sigma": agent.rating.sigma}
           for agent in agent_pool}

with open("mcts_eval.json", "w") as json_file:
    json.dump(ratings, json_file)
Пример #43
0
 def save(self, *args, **kwargs):
     self.exposure = trueskill.expose(self.ts_rating)
     super(Rating, self).save(*args, **kwargs)
Пример #44
0
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!'