Exemple #1
0
    async def teamrate(self, ctx, *handles: str):
        """Provides the combined rating of the entire team.
        If +server is provided as the only handle, will display the rating of the entire server.
        Supports multipliers. e.g: ;teamrate gamegame*1000"""

        handles = handles or ('!' + str(ctx.author),)
        is_entire_server = (handles == ('+server',))
        if is_entire_server:
            res = cf_common.user_db.get_cf_users_for_guild(ctx.guild.id)
            ratings = [cf_user.rating for user_id, cf_user in res if cf_user.rating is not None]
            user_str = '+server'
        else:
            def normalize(x):
                return [i.lower() for i in x]
            handle_counts = {}
            parsed_handles = []
            for i in handles:
                parse_str = normalize(i.split('*'))
                if len(parse_str) > 1:
                    try:
                        handle_counts[parse_str[0]] = int(parse_str[1])
                    except ValueError:
                        raise CodeforcesCogError("Can't multiply by non-integer")
                else:
                    handle_counts[parse_str[0]] = 1
                parsed_handles.append(parse_str[0])
            if sum(handle_counts.values()) > 100000:
                raise CodeforcesCogError('Too large of a team!')
            cf_handles = await cf_common.resolve_handles(ctx, self.converter, parsed_handles, mincnt=1, maxcnt=1000)
            cf_handles = normalize(cf_handles)
            cf_to_original = {a: b for a, b in zip(cf_handles, parsed_handles)}
            original_to_cf = {a: b for a, b in zip(parsed_handles, cf_handles)}
            users = await cf.user.info(handles=cf_handles)
            user_strs = []
            for a, b in handle_counts.items():
                if b > 1:
                    user_strs.append(f'{original_to_cf[a]}*{b}')
                elif b == 1:
                    user_strs.append(original_to_cf[a])
                elif b < 0:
                    raise CodeforcesCogError('How can you have negative members in team?')

            user_str = ', '.join(user_strs)
            ratings = [user.rating for user in users if user.rating for _ in range(handle_counts[cf_to_original[user.handle.lower()]])]

        if len(ratings) == 0:
            raise CodeforcesCogError("No CF usernames with ratings passed in.")

        left = -100.0
        right = 10000.0
        teamRating = Codeforces.composeRatings(left, right, ratings)
        embed = discord.Embed(title=user_str, description=teamRating, color=cf.rating2rank(teamRating).color_embed)
        await ctx.send(embed = embed)
Exemple #2
0
def _make_pages(users):
    chunks = paginator.chunkify(users, _HANDLES_PER_PAGE)
    pages = []
    done = 0

    style = table.Style('{:>}  {:<}  {:<}  {:<}')
    for chunk in chunks:
        t = table.Table(style)
        t += table.Header('#', 'Name', 'Handle', 'Rating')
        t += table.Line()
        for i, (member, handle, rating) in enumerate(chunk):
            rank = cf.rating2rank(rating)
            rating_str = 'N/A' if rating is None else str(rating)
            t += table.Data(i + done, member.display_name, handle,
                            f'{rating_str} ({rank.title_abbr})')
        table_str = '```\n' + str(t) + '\n```'
        embed = discord_common.cf_color_embed(description=table_str)
        pages.append(('Handles of server members', embed))
        done += len(chunk)
    return pages
Exemple #3
0
def _make_pages(users, title):
    chunks = paginator.chunkify(users, _HANDLES_PER_PAGE)
    pages = []
    done = 0

    style = table.Style("{:>}  {:<}  {:<}  {:<}")
    for chunk in chunks:
        t = table.Table(style)
        t += table.Header("#", "Name", "Handle", "Rating")
        t += table.Line()
        for i, (member, handle, rating) in enumerate(chunk):
            name = member.display_name
            if len(name) > _NAME_MAX_LEN:
                name = name[: _NAME_MAX_LEN - 1] + "…"
            rank = cf.rating2rank(rating)
            rating_str = "N/A" if rating is None else str(rating)
            t += table.Data(i + done, name, handle, f"{rating_str} ({rank.title_abbr})")
        table_str = "```\n" + str(t) + "\n```"
        embed = discord_common.cf_color_embed(description=table_str)
        pages.append((title, embed))
        done += len(chunk)
    return pages
Exemple #4
0
def _make_pages_gudgitters(users, title):
    chunks = paginator.chunkify(users, _HANDLES_PER_PAGE)
    pages = []
    done = 0

    style = table.Style('{:>}  {:<}  {:<}  {:<}')
    for chunk in chunks:
        t = table.Table(style)
        t += table.Header('#', 'Name', 'Handle', 'Rating')
        t += table.Line()
        for i, (member, handle, rating) in enumerate(chunk):
            name = member
            if len(name) > _NAME_MAX_LEN:
                name = name[:_NAME_MAX_LEN - 1] + '…'
            rank = cf.rating2rank(rating)
            rating_str = 'N/A' if rating is None else str(rating)
            t += table.Data(i + done, name, handle, f'{rating_str}')
        table_str = '```\n' + str(t) + '\n```'
        embed = discord_common.cf_color_embed(description=table_str)
        pages.append((title, embed))
        done += len(chunk)
    return pages
Exemple #5
0
    async def visualrank(self, ctx, contest_id: int, *args: str):
        """Plot rating changes by rank. Add handles to specify a handle in the plot.
        if arguments contains `+server`, it will include just server members and not all codeforces users.
        Specify `+zoom` to zoom to the neighborhood of handles."""

        args = set(args)
        (in_server, zoom), handles = cf_common.filter_flags(args, ['+server', '+zoom'])
        handles = await cf_common.resolve_handles(ctx, self.converter, handles, mincnt=0, maxcnt=20)

        rating_changes = await cf.contest.ratingChanges(contest_id=contest_id)
        if in_server:
            guild_handles = set(handle for discord_id, handle
                                in cf_common.user_db.get_handles_for_guild(ctx.guild.id))
            rating_changes = [rating_change for rating_change in rating_changes
                              if rating_change.handle in guild_handles or rating_change.handle in handles]

        if not rating_changes:
            raise GraphCogError(f'No rating changes for contest `{contest_id}`')

        users_to_mark = {}
        for rating_change in rating_changes:
            user_delta = rating_change.newRating - rating_change.oldRating
            if rating_change.handle in handles:
                users_to_mark[rating_change.handle] = (rating_change.rank, user_delta)

        ymargin = 50
        xmargin = 50
        if users_to_mark and zoom:
            xmin = min(point[0] for point in users_to_mark.values())
            xmax = max(point[0] for point in users_to_mark.values())
            ymin = min(point[1] for point in users_to_mark.values())
            ymax = max(point[1] for point in users_to_mark.values())
        else:
            ylim = 0
            if users_to_mark:
                ylim = max(abs(point[1]) for point in users_to_mark.values())
            ylim = max(ylim, 200)

            xmin = 0
            xmax = max(rating_change.rank for rating_change in rating_changes)
            ymin = -ylim
            ymax = ylim

        ranks = []
        delta = []
        color = []
        for rating_change in rating_changes:
            user_delta = rating_change.newRating - rating_change.oldRating

            if (xmin - xmargin <= rating_change.rank <= xmax + xmargin
                    and ymin - ymargin <= user_delta <= ymax + ymargin):
                ranks.append(rating_change.rank)
                delta.append(user_delta)
                color.append(cf.rating2rank(rating_change.oldRating).color_graph)

        title = rating_changes[0].contestName

        plt.clf()
        fig = plt.figure(figsize=(12, 8))
        plt.title(title)
        plt.xlabel('Rank')
        plt.ylabel('Rating Changes')

        mark_size = 2e4 / len(ranks)
        plt.xlim(xmin - xmargin, xmax + xmargin)
        plt.ylim(ymin - ymargin, ymax + ymargin)
        plt.scatter(ranks, delta, s=mark_size, c=color)

        for handle, point in users_to_mark.items():
            plt.annotate(handle,
                         xy=point,
                         xytext=(0, 0),
                         textcoords='offset points',
                         ha='left',
                         va='bottom',
                         fontsize='large')
            plt.plot(*point,
                     marker='o',
                     markersize=5,
                     color='black')

        discord_file = gc.get_current_figure_as_file()
        plt.close(fig)

        embed = discord_common.cf_color_embed(title=title)
        discord_common.attach_image(embed, discord_file)
        discord_common.set_author_footer(embed, ctx.author)
        await ctx.send(embed=embed, file=discord_file)
Exemple #6
0
 def rating_to_displayable_rank(rating):
     rank = cf.rating2rank(rating).title
     role = rank_to_role.get(rank)
     return role.mention if role else rank
Exemple #7
0
    async def visualrank(self, ctx, contest_id: int, *args: str):
        """Plot rating changes by rank. Add handles to specify a handle in the plot.
        if arguments contains `+server`, it will include just server members and not all codeforces users.
        Specify `+zoom` to zoom to the neighborhood of handles."""

        args = set(args)
        (in_server,
         zoom), handles = cf_common.filter_flags(args, ["+server", "+zoom"])
        handles = await cf_common.resolve_handles(ctx,
                                                  self.converter,
                                                  handles,
                                                  mincnt=0,
                                                  maxcnt=20)

        users = cf_common.cache2.rating_changes_cache.get_rating_changes_for_contest(
            contest_id)

        if not users:
            raise GraphCogError(
                f"No rating change cache for contest `{contest_id}`")

        if in_server:
            guild_handles = [
                handle for discord_id, handle in
                cf_common.user_db.get_handles_for_guild(ctx.guild.id)
            ]
            users = [user for user in users if user.handle in guild_handles]

        ranks = []
        delta = []
        color = []
        users_to_mark = dict()

        for user in users:
            user_delta = user.newRating - user.oldRating

            ranks.append(user.rank)
            delta.append(user_delta)
            color.append(cf.rating2rank(user.oldRating).color_graph)

            if user.handle in handles:
                users_to_mark[user.handle] = (user.rank, user_delta)

        title = users[0].contestName

        plt.clf()
        fig = plt.figure(figsize=(12, 8))
        plt.title(title)
        plt.xlabel("Rank")
        plt.ylabel("Rating Changes")

        ymargin = 50
        xmargin = 50
        if users_to_mark and zoom:
            xmin = min(point[0] for point in users_to_mark.values())
            xmax = max(point[0] for point in users_to_mark.values())
            ymin = min(point[1] for point in users_to_mark.values())
            ymax = max(point[1] for point in users_to_mark.values())
            mark_size = 2e4 / (xmax - xmin + 2 * xmargin)

            plt.xlim(xmin - xmargin, xmax + xmargin)
            plt.ylim(ymin - ymargin, ymax + ymargin)
        else:
            ylim = 0
            if users_to_mark:
                ylim = max(abs(point[1]) for point in users_to_mark.values())
            ylim = max(ylim, 200)
            xmax = max(user.rank for user in users)
            mark_size = 2e4 / (xmax + 2 * xmargin)

            plt.xlim(-xmargin, xmax + xmargin)
            plt.ylim(-ylim - ymargin, ylim + ymargin)

        plt.scatter(ranks, delta, s=mark_size, c=color)

        for handle, point in users_to_mark.items():
            plt.annotate(
                handle,
                xy=point,
                xytext=(0, 0),
                textcoords="offset points",
                ha="left",
                va="bottom",
                fontsize="large",
            )
            plt.plot(*point, marker="o", markersize=5, color="black")

        discord_file = gc.get_current_figure_as_file()
        plt.close(fig)

        embed = discord_common.cf_color_embed(title=title)
        discord_common.attach_image(embed, discord_file)
        discord_common.set_author_footer(embed, ctx.author)
        await ctx.send(embed=embed, file=discord_file)