Exemplo n.º 1
0
    async def whois(self,
                    ctx,
                    member: typing.Optional[discord.Member] = None,
                    handle: typing.Optional[str] = None):

        query = Query()
        username, linked_username, pfp = None, None, None
        if handle:
            user = None
            try:
                user = await query.get_user(handle)
            except ObjectNotFound:
                username = None
            if user:
                handle = user.username
                author_id = query.get_handle_user(handle, ctx.guild.id)
                username = handle
                if author_id:
                    member = ctx.message.guild.get_member(author_id)
                    linked_username = member.nick or member.name
                    pfp = member.avatar_url
        elif member:
            handle = query.get_handle(member.id, ctx.guild.id)
            username = member.nick or member.name
            if handle:
                linked_username = handle
                pfp = await query.get_pfp(handle)
        if linked_username:
            embed = discord.Embed(
                color=0xfcdb05,
                title=f'{username} is {linked_username}',
            )
            embed.set_thumbnail(url=pfp)
            await ctx.send(embed=embed)
        elif username:
            embed = discord.Embed(
                title=f'{username} is not linked with any account here',
                color=0xfcdb05,
            )
            await ctx.send(embed=embed)
        else:
            name = None
            if member:
                name = member.nick or member.name
            embed = discord.Embed(
                title=f'Nothing found on {handle or name}',
                color=0xfcdb05,
            )
            await ctx.send(embed=embed)
Exemplo n.º 2
0
    async def recommend(self, ctx, username: typing.Optional[parse_gimme] = None,
                        points: typing.Optional[point_range] = [1, 50], *filters):
        """
        Recommend a problem

        Use surround your username with '' if it can be interpreted as a number

        SHORTHANDS:
        - adhoc
        - math
        - bf
        - ctf
        - ds
        - d&c
        - dp
        - geo
        - gt
        - greedy
        - regex
        - string
        """
        filters = list(filters)
        query = Query()
        username = username or query.get_handle(ctx.author.id, ctx.guild.id)

        if username is None:
            return await ctx.send('No username provided')

        user = await query.get_user(username)
        if user is None:
            return await ctx.send(f'{username} does not exist on DMOJ')

        username = user.username
        filter_list = []
        for filter in filters:
            if filter in SHORTHANDS:
                filter_list += SHORTHANDS[filter]
            else:
                filter_list.append(filter.title())

        filters = filter_list

        # Get all problems that are unsolved by user and fits the filter and
        # point range
        result, problem = await gimme_common(username, points, filters)
        # print(result)
        if result is None:
            return await ctx.send("No problem that satisfies the filter")
        return await ctx.send(embed=result)
Exemplo n.º 3
0
async def nogud(ctx):
    query = Query()
    gitgud_util = Gitgud_utils()

    username = query.get_handle(ctx.author.id, ctx.get_guild().id)

    if username is None:
        return await ctx.respond("You do not have a linked DMOJ account")

    current = gitgud_util.get_current(username, ctx.get_guild().id)
    if current is None or current.problem_id is None:
        return await ctx.respond("Nothing to cancel")

    gitgud_util.clear(username, ctx.get_guild().id)
    return await ctx.respond("Challenge skipped")
Exemplo n.º 4
0
async def whois(ctx):
    member = ctx.options.member
    handle = ctx.options.handle

    query = Query()
    username, linked_username, pfp = None, None, None
    if handle:
        user = None
        try:
            user = await query.get_user(handle)
        except ObjectNotFound:
            username = None
        if user:
            handle = user.username
            author_id = query.get_handle_user(handle, ctx.get_guild().id)
            username = handle
            if author_id:
                member = ctx.get_guild().get_member(author_id)
                linked_username = member.nickname or member.username
                pfp = member.avatar_url
    elif member:
        handle = query.get_handle(member.id, ctx.get_guild().id)
        username = member.nickname or member.username
        if handle:
            linked_username = handle
            pfp = await query.get_pfp(handle)
    if linked_username:
        embed = hikari.Embed(
            color=0xFCDB05,
            title=escape_markdown(f"{username} is {linked_username}"),
        )
        embed.set_thumbnail(pfp)
        return await ctx.respond(embed=embed)
    elif username:
        embed = hikari.Embed(
            title=escape_markdown(f"{username} is not linked with any account here"),
            color=0xFCDB05,
        )
        return await ctx.respond(embed=embed)

    name = None
    if member:
        name = member.nickname or member.username
    embed = hikari.Embed(
        title=escape_markdown(f"Nothing found on {handle or name}"),
        color=0xFCDB05,
    )
    await ctx.respond(embed=embed)
Exemplo n.º 5
0
async def gitlog(ctx):
    """
    Show the past gitgud history of a user
    """
    query = Query()
    username = ctx.options.username
    username = username or query.get_handle(ctx.author.id, ctx.get_guild().id)
    try:
        user = await query.get_user(username)
        username = user.username
    except TypeError:
        username = None
    if username is None:
        return await ctx.respond("You have not entered a valid DMOJ handle " "or linked with a DMOJ Account")

    gitgud_util = Gitgud_utils()
    history = gitgud_util.get_all(username, ctx.get_guild().id)

    if len(history) == 0:
        embed = hikari.Embed(description="User have not completed any " "challenge")
        return await ctx.respond(embed=embed)
    # paginate

    pag = lightbulb.utils.EmbedPaginator()
    for idx, solved in enumerate(history):
        # problem = solved.problem_id or await query.get_problem(solved.problem_id)
        problem = await query.get_problem(solved.problem_id)
        days = (datetime.now() - solved.time).days
        if days == 0:
            days_str = "today"
        elif days == 1:
            days_str = "yesterday"
        else:
            days_str = f"{days} days ago"
        pag.add_line(f"[{problem.name}](https://dmoj.ca/problem/{problem.code}) " f"[+{solved.point}] ({days_str})")
        if idx == 100:
            break

    @pag.embed_factory()
    def build_embed(page_index, content):
        return hikari.Embed(color=0xFCDB05,).add_field(
            name=f"Gitgud Log for {username} " f"(page {page_index})",  # Can't put total length :/
            value=content,
            inline=True,
        )

    navigator = nav.ButtonNavigator(pag.build_pages())
    await navigator.run(ctx)
Exemplo n.º 6
0
async def howgud(ctx):
    username = ctx.options.username
    query = Query()
    if username is None:
        username = query.get_handle(ctx.author.id, ctx.get_guild().id)
    user = await query.get_user(username)
    username = user.username
    ret = Gitgud_utils().get_point(username, ctx.get_guild().id)
    if ret is None:
        ret = 0
    # TODO Add profile pic?
    embed = hikari.Embed(
        title=username,
        description=f"points: {ret}",
        color=0xFCDB05,
    )
    return await ctx.respond(embed=embed)
Exemplo n.º 7
0
async def unlink(ctx: lightbulb.Context) -> None:
    # TODO: Add admin ability to manually unlink
    query = Query()
    if not query.get_handle(ctx.author.id, ctx.get_guild().id):
        await ctx.respond("You are not linked with any user")
        return
    handle = (
        session.query(Handle_DB)
        .filter(Handle_DB.id == ctx.author.id)
        .filter(Handle_DB.guild_id == ctx.get_guild().id)
        .first()
    )
    session.query(User_DB).filter(User_DB.id == handle.user_id).delete()
    session.query(Submission_DB).filter(Submission_DB._user == handle.handle).delete()
    session.delete(handle)
    session.commit()
    await ctx.respond(escape_markdown(f"Unlinked you with handle {handle.handle}"))
Exemplo n.º 8
0
	async def howgud(self, ctx, username = None):
		"""
		Returns total amount of gitgud points
		"""
		query = Query()
		if username is None:
			username = query.get_handle(ctx.author.id, ctx.guild.id)
		user = await query.get_user(username)
		username = user.username
		ret = Gitgud_utils().get_point(username, ctx.guild.id)
		if ret is None:
			ret = 0
		embed = discord.Embed(
			title=username,
			description=f"points: {ret}"
		)
		return await ctx.send(embed=embed)
Exemplo n.º 9
0
    async def vc(self, ctx, *usernames):
        """Suggest a contest"""
        usernames = list(usernames)

        query = Query()
        if usernames == []:
            usernames = [query.get_handle(ctx.author.id, ctx.guild.id)]

        users = await asyncio.gather(
            *[query.get_user(username) for username in usernames])
        usernames = [user.username for user in users]
        for i in range(len(users)):
            if users[i] is None:
                return await ctx.send(f'{usernames[i]} does not exist on DMOJ')

        q = session.query(Contest_DB)
        for user in users:
            # if the user has attempted any problems from the problem set
            sub_q = session.query(Submission_DB,
                                  func.max(Submission_DB.points))\
                .filter(Submission_DB._user == user.username)\
                .group_by(Submission_DB._code).subquery()
            sub_q = session.query(Problem_DB.code)\
                .join(sub_q, Problem_DB.code == sub_q.c._code, isouter=True)\
                .filter(func.ifnull(sub_q.c.points, 0) != 0)
            sub_q = list(map(itemgetter(0), sub_q.all()))
            q = q.filter(not_(Contest_DB.rankings.contains(user.username)))\
                .filter(~Contest_DB.problems.any(Problem_DB.code.in_(sub_q)))

        if q.count() == 0:
            await ctx.send("Cannot find any contests which "
                           "all users have not done")
            return
        contest = random.choice(q.all())

        # When problems are private, it says there are no problems
        window = 'No'
        if contest.time_limit:
            window = f"{contest.time_limit/60/60} Hr"
        embed = discord.Embed(
            title=contest.name,
            url=f"https://dmoj.ca/contest/{contest.key}",
            description=f"{window} window | {len(contest.problems)} Problems",
            color=0xfcdb05)
        await ctx.send(embed=embed)
Exemplo n.º 10
0
    async def nogud(self, ctx):
        '''
        Cancels any unfinished challenge
        '''
        query = Query()
        gitgud_util = Gitgud_utils()

        username = query.get_handle(ctx.author.id, ctx.guild.id)

        if username is None:
            return await ctx.send('You do not have a linked DMOJ account')

        current = gitgud_util.get_current(username, ctx.guild.id)
        if current is None or current.problem_id is None:
            return await ctx.send('Nothing to cancel')

        gitgud_util.clear(username, ctx.guild.id)
        return await ctx.send('Challenge skipped')
Exemplo n.º 11
0
    async def postcontest(self, ctx, key):
        """Updates post-contest role"""

        await ctx.message.delete()
        query = Query()

        username = query.get_handle(ctx.author.id, ctx.guild.id)

        if username is None:
            return await ctx.send("Your account is not linked!")

        q = session.query(Contest_DB).filter(Contest_DB.key == key)
        # Clear cache
        if q.count():
            q.delete()
            session.commit()
        try:
            contest = await query.get_contest(key)
        except ObjectNotFound:
            await ctx.send("Contest not found")
            return

        if contest.is_organization_private:
            return await ctx.send("Contest not found")

        role = get(ctx.guild.roles, name="postcontest " + key)
        if not role:
            return await ctx.send(f"No `postcontest {key}` role found.")

        for ranking in contest.rankings:
            if ranking['user'].lower() != username.lower():
                continue

            endTime = datetime.strptime(ranking['end_time'],
                                        '%Y-%m-%dT%H:%M:%S%z')
            if endTime > datetime.now(timezone.utc).astimezone():
                return await ctx.send("Your window is not done.")
            else:
                try:
                    await ctx.author.add_roles(role)
                except discord.Forbidden:
                    return await ctx.send("No permission to assign the role.")
                return await ctx.send("You've been added to post contest.")
        return await ctx.send("You haven't joined the contest yet.")
Exemplo n.º 12
0
    async def gitlog(self, ctx, username=None):
        """
        Show the past gitgud history of a user
        """
        query = Query()
        username = username or query.get_handle(ctx.author.id, ctx.guild.id)
        try:
            user = await query.get_user(username)
            username = user.username
        except TypeError:
            username = None
        if username is None:
            return await ctx.send("You have not entered a valid DMOJ handle "
                                  "or linked with a DMOJ Account")

        gitgud_util = Gitgud_utils()
        history = gitgud_util.get_all(username, ctx.guild.id)

        if len(history) == 0:
            embed = discord.Embed(description="User have not completed any"
                                  "challenge")
            return await ctx.send(embed=embed)
        # paginate
        count = 0
        page_cnt = min(10, len(history) // 10 + bool(len(history) % 10))
        embeds = []
        content = ""
        paginator = Pagination.CustomEmbedPaginator(ctx,
                                                    timeout=60,
                                                    remove_reactions=True)
        paginator.add_reaction('⏮️', "first")
        paginator.add_reaction('⏪', "back")
        paginator.add_reaction('⏩', "next")
        paginator.add_reaction('⏭️', "last")
        for solved in history:
            # print(solved.problem_id)
            problem = await query.get_problem(solved.problem_id)
            days = (datetime.now() - solved.time).days
            if days == 0:
                days_str = "today"
            elif days == 1:
                days_str = "yesterday"
            else:
                days_str = f"{days} days ago"
            content += f"[{problem.name}](https://dmoj.ca/problem/{problem.code}) " \
                       f"[+{solved.point}] ({days_str})\n"
            count += 1
            if count % 10 == 0:
                embed = discord.Embed(color=0xfcdb05, )
                embed.add_field(name=f"Gitgud Log for {username} "
                                f"(page {count//10}/{page_cnt})",
                                value=content,
                                inline=True)
                embeds.append(embed)
                content = ""
            if count == 100:
                break
        if count % 10 != 0:
            embed = discord.Embed()
            embed.add_field(name=f"Gitlog for {username} "
                            f"(page {count//10 + 1}/{page_cnt})",
                            value=content,
                            inline=True)
            embeds.append(embed)
        return await paginator.run(embeds)
Exemplo n.º 13
0
    async def type(self,
                   ctx,
                   as_percent: typing.Optional[as_percentage] = True,
                   graph: typing.Optional[graph_type] = 'radar',
                   *usernames):
        """Graph problems solved by popular problem types"""
        # This is aids, pls fix

        usernames = list(usernames)

        query = Query()
        if usernames == []:
            usernames = [query.get_handle(ctx.author.id, ctx.guild.id)]

        users = await asyncio.gather(
            *[query.get_user(username) for username in usernames])
        for i in range(len(users)):
            if users[i] is None:
                return await ctx.send(f'{usernames[i]} does not exist on DMOJ')

        if len(users) > 6:
            return await ctx.send('Too many users given, max 6')

        usernames = [data.username for data in users]

        important_types = [['Data Structures'], ['Dynamic Programming'],
                           ['Graph Theory'], ['String Algorithms'],
                           [
                               'Advanced Math', 'Geometry',
                               'Intermediate Math', 'Simple Math'
                           ], ['Ad Hoc'], ['Greedy Algorithms']]
        labels = [
            'Data Structures', 'Dynamic Programming', 'Graph Theory',
            'String Algorithms', 'Math', 'Ad Hoc', 'Greedy Algorithms'
        ]

        data = {}
        data['group'] = []
        for label in labels:
            data[label] = []
        for username in usernames:
            data['group'].append(username)

        def calculate_points(points: int):
            p = 0
            for i in range(min(100, len(points))):
                p += (0.95**i) * points[i]
            return p

        def to_points(problem):
            return problem.points

        max_percentage = 0
        not_cached = []

        for username in usernames:
            q = session.query(Submission_DB)\
                .filter(Submission_DB._user == username)
            if q.count() == 0:
                not_cached.append(username)

        for i, types in enumerate(important_types):
            total_problems = await query.get_problems(_type=types, cached=True)
            total_points = list(map(to_points, total_problems))
            total_points.sort(reverse=True)
            total_points = calculate_points(total_points)

            for username in usernames:
                problems = query.get_attempted_problems(username, types)

                points = list(map(to_points, problems))
                points.sort(reverse=True)

                points = calculate_points(points)
                if as_percent:
                    percentage = 100 * points / total_points
                else:
                    percentage = points
                max_percentage = max(max_percentage, percentage)
                data[labels[i]].append(percentage)

        print(data)
        if len(not_cached):
            await ctx.send(f"`{', '.join(not_cached)} do not have any cached "
                           f"submissions. Please use +cache [username]`")

        if graph == 'radar':
            plot_type_radar(data, as_percent, max_percentage)
        elif graph == 'bar':
            plot_type_bar(data, as_percent)

        with open('./graphs/plot.png', 'rb') as file:
            file = discord.File(io.BytesIO(file.read()), filename='plot.png')
        embed = discord.Embed(
            title='Problem types solved',
            color=0xfcdb05,
        )
        embed.set_image(url='attachment://plot.png')

        return await ctx.send(embed=embed, file=file)
Exemplo n.º 14
0
    async def points(self, ctx, *usernames):
        """Plot point progression"""
        usernames = list(usernames)

        query = Query()
        if usernames == []:
            usernames = [query.get_handle(ctx.author.id, ctx.guild.id)]

        users = await asyncio.gather(
            *[query.get_user(username) for username in usernames])
        usernames = [user.username for user in users]
        for i in range(len(users)):
            if users[i] is None:
                return await ctx.send(f'{usernames[i]} does not exist on DMOJ')
        if len(users) > 10:
            return await ctx.send('Too many users given, max 10')

        total_data = {}
        not_cached = []
        for username in usernames:
            q = session.query(Submission_DB)\
                .options(orm.joinedload('problem'))\
                .join(User_DB, User_DB.username == Submission_DB._user,
                      aliased=True)\
                .filter(User_DB.username == username)\
                .order_by(Submission_DB.date)

            def calculate_points(points, fully_solved):
                b = 150 * (1 - 0.997**fully_solved)
                p = 0
                for i in range(min(100, len(points))):
                    p += (0.95**i) * points[i]
                return b + p

            submissions = q.all()
            if len(submissions) == 0:
                not_cached.append(username)
            problems_ACed = dict()
            code_to_points = dict()

            points_arr = []
            data_to_plot = {}
            # O(N^2logN) :blobcreep:
            for submission in submissions:
                code = submission.problem[0].code
                points = submission.points
                result = submission.result

                if points is not None:
                    if result == 'AC':
                        problems_ACed[code] = 1
                    if code not in code_to_points:
                        # log N search, N insert
                        code_to_points[code] = points
                        bisect.insort(points_arr, points)
                    elif points > code_to_points[code]:
                        # N remove, log N search, N insert
                        points_arr.remove(code_to_points[code])
                        code_to_points[code] = points
                        bisect.insort(points_arr, points)
                    cur_points = calculate_points(points_arr[::-1],
                                                  len(problems_ACed))
                    data_to_plot[submission.date] = cur_points
            total_data[username] = data_to_plot

        if len(not_cached):
            await ctx.send(f"`{', '.join(not_cached)} do not have any cached "
                           f"submissions. Please use +cache [username]`")

        plot_points(total_data)

        with open('./graphs/plot.png', 'rb') as file:
            file = discord.File(io.BytesIO(file.read()), filename='plot.png')
        embed = discord.Embed(
            title='Point Progression',
            color=0xfcdb05,
        )
        embed.set_image(url='attachment://plot.png')

        return await ctx.send(embed=embed, file=file)
Exemplo n.º 15
0
    async def predict(self, ctx, username: typing.Optional[str_not_int] = None,
                      amounts: commands.Greedy[int] = []):
        """Predict total points after solving N pointer problem(s)

        Use surround your username with '' if it can be interpreted as a number
        """
        query = Query()
        username = username or query.get_handle(ctx.author.id, ctx.guild.id)

        if username is None and len(amounts) > 0:
            username = str([0])
            amounts.pop(0)

        if amounts == []:
            return await ctx.send('No points given!')

        if username is None:
            return

        amounts = amounts[:10]

        user = await query.get_user(username)
        if user is None:
            return await ctx.send(f'{username} does not exist on DMOJ')

        username = user.username
        q = session.query(Submission_DB).options(orm.joinedload('problem'))\
            .join(User_DB, User_DB.username == Submission_DB._user,
                  aliased=True)\
            .filter(User_DB.username == user.username)

        if q.count():
            submissions = q.all()
            msg = None
        else:
            await ctx.send('No submissions cached, '
                           'Please use +cache to get new submissions')
            return

        problems_ACed = dict()
        code_to_points = dict()
        for submission in submissions:
            code = submission.problem[0].code
            points = submission.points
            result = submission.result

            if points is not None:
                if result == 'AC':
                    problems_ACed[code] = 1
                if code not in code_to_points:
                    code_to_points[code] = points
                elif points > code_to_points[code]:
                    code_to_points[code] = points

        fully_solved = len(problems_ACed)
        points = list(code_to_points.values())
        points.sort(reverse=True)

        embed = discord.Embed(
            title=f'Point prediction for {username}',
            description='Current points: %.2fp' %
                        calculate_points(points, fully_solved),
            color=0xfcdb05,
        )

        embed.set_thumbnail(url=await query.get_pfp(username))

        for predict_val in amounts:
            points.append(int(predict_val))
            fully_solved += 1
            points.sort(reverse=True)
            updated_points = calculate_points(points, fully_solved)
            embed.add_field(
                name="Solve another %sp" % predict_val,
                value="Total points: %.2fp" % updated_points,
                inline=False,
            )

        if msg:
            await msg.delete()
        await ctx.send(embed=embed)
        return
Exemplo n.º 16
0
async def postcontest(ctx):
    """Updates post-contest role"""
    key = ctx.options.key
    option = ctx.options.option
    try:
        await ctx.event.message.delete()
    except hikari.ForbiddenError as e:
        logger.info(e)
        pass

    def has_admin_perms(ctx):
        return any(role.name in ADMIN_ROLES for role in ctx.member.get_roles())

    update_all = option == "+all" and has_admin_perms(ctx)

    query = Query()

    if update_all:
        usernames = session.query(Handle_DB).filter(Handle_DB.guild_id == ctx.get_guild().id).all()
    else:
        username = query.get_handle(ctx.author.id, ctx.get_guild().id)

        if username is None:
            return await ctx.respond("Your account is not linked!")

    q = session.query(Contest_DB).filter(Contest_DB.key == key)
    # Clear cache
    if q.count():
        q.delete()
        session.commit()
    try:
        contest = await query.get_contest(key)
    except ObjectNotFound:
        await ctx.respond("Contest not found")
        return

    if contest.is_organization_private:
        return await ctx.respond("Contest not found")

    rc = lightbulb.RoleConverter(ctx)
    for role_id in ctx.get_guild().get_roles():
        _role = await rc.convert(str(role_id))
        if _role.name == "postcontest " + key:
            role = _role
            break
    else:
        return await ctx.respond(f"No `postcontest {key}` role found.")

    if update_all:
        participants = set()
        for ranking in contest.rankings:
            endTime = datetime.strptime(ranking["end_time"], "%Y-%m-%dT%H:%M:%S%z")
            if endTime < datetime.now(timezone.utc).astimezone():
                participants.add(ranking["user"])

        for user in usernames:
            if user.handle in participants:
                await ctx.get_guild().get_member(user.id).add_role(role)
        return await ctx.respond("Updated post contest for " + key)

    for ranking in contest.rankings:
        if ranking["user"].lower() != username.lower():
            continue

        endTime = datetime.strptime(ranking["end_time"], "%Y-%m-%dT%H:%M:%S%z")
        if endTime > datetime.now(timezone.utc).astimezone():
            return await ctx.respond("Your window is not done")
        else:
            await ctx.member.add_role(role)
            return await ctx.respond("You've been added to post contest")
    return await ctx.respond("You haven't joined the contest yet")
Exemplo n.º 17
0
async def userinfo(ctx):
    """Show user profile and latest submissions

    Use surround your username with '' if it can be interpreted as a number
    """
    username = ctx.options.username
    amount = ctx.options.amount
    query = Query()
    username = username or query.get_handle(ctx.author.id, ctx.get_guild().id)
    # If user is not found in db
    if username is None:
        username = str(amount)
        amount = None

    if username is None:
        return await ctx.respond("No username given!")

    username = username.replace("'", "")

    if amount is not None:
        amount = min(amount, 8)
        if amount < 1:
            return await ctx.respond("Please request at least one submission")

    try:
        user = await query.get_user(username)
    except ObjectNotFound:
        return await ctx.respond(f"{username} does not exist on DMOJ")

    username = user.username

    def is_rated(contest):
        return 1 if contest.is_rated else 0

    discordHandle = ctx.get_guild().get_member(
        query.get_handle_user(username,
                              ctx.get_guild().id))
    if discordHandle:
        discordHandle = discordHandle.nickname or discordHandle.username
    else:
        discordHandle = "Unknown"
    if user.rating is None:
        color = 0xFEFEFE  # it breaks when I set it to white
    elif user.rating >= 3000:
        color = 0x000000
    elif user.rating >= 2700:
        color = 0xA00000
    elif user.rating >= 2400:
        color = 0xEE0000
    elif user.rating >= 1900:
        color = 0xFFB100
    elif user.rating >= 1600:
        color = 0x800080
    elif user.rating >= 1300:
        color = 0x0000FF
    elif user.rating >= 1000:
        color = 0x00A900
    elif user.rating >= 0:
        color = 0x999999
    else:
        color = 0x000000
    description = f"Discord name: {discordHandle}"
    embed = hikari.Embed(
        title=username,
        url=f"https://dmoj.ca/user/{username}",
        description=description,
        color=color,  # rating color
    )

    embed.set_thumbnail(await query.get_pfp(username))
    embed.add_field(name="Points",
                    value=str(round(user.performance_points)) + "/" +
                    str(round(user.points)),
                    inline=True)
    embed.add_field(name="Problems Solved",
                    value=user.problem_count,
                    inline=True)
    embed.add_field(name="Rating",
                    value=str(user.rating) + "/" + str(user.max_rating),
                    inline=True)
    embed.add_field(name="Contests Written",
                    value=sum(map(is_rated, user.contests)),
                    inline=True)

    await ctx.respond(embed=embed)

    if amount is None:
        return

    submissions = await query.get_latest_submissions(username, amount)

    embed = hikari.Embed(title=f"{username}'s latest submissions",
                         color=0xFFFF00)
    for submission in submissions:
        problem = submission.problem[0]
        if problem.points is not None:
            points = str(int(problem.points)) + "p"
            if problem.partial:
                points += "p"
        else:
            points = "???"

        true_short_name = submission.language[0].short_name
        if true_short_name == "":
            # wtf dmoj
            true_short_name = submission.language[0].key

        embed.add_field(
            name="%s / %s" %
            (str(submission.score_num), str(submission.score_denom)),
            value="%s | %s" % (submission.result, true_short_name),
            inline=True,
        )

        embed.add_field(
            name="%s (%s)" % (submission.problem[0].name, points),
            value="%s | [Problem](https://dmoj.ca/problem/%s)" % (
                submission.date.astimezone(TZ).strftime("%b. %d, %Y, %I:%M %p")
                .replace("AM", "a.m.").replace("PM", "p.m."),
                submission.problem[0].code,
            ),
            # Jan. 13, 2021, 12:17 a.m.
            # %b. %d, %Y, %I:%M %p
            inline=True,
        )
        try:
            embed.add_field(
                name="%.2fs" % submission.time,
                value="%s" % submission.memory_str,
                inline=True,
            )
        except TypeError:
            embed.add_field(
                name="---",
                value="%s" % submission.memory_str,
                inline=True,
            )

    await ctx.respond(embed=embed)
    return None
Exemplo n.º 18
0
async def type(ctx):
    """Graph problems solved by popular problem types"""
    # TODO: This is aids, pls fix

    usernames = ctx.options.usernames
    graph_type = ctx.options.graph_type
    as_percent = ctx.options.as_percent

    query = Query()
    if usernames == []:
        usernames = [query.get_handle(ctx.author.id, ctx.get_guild().id)]

    try:
        users = await asyncio.gather(*[query.get_user(username) for username in usernames])
    except ObjectNotFound:
        return await ctx.respond("User not found")

    for i in range(len(users)):
        if users[i] is None:
            return await ctx.respond(f"{usernames[i]} does not exist on DMOJ")

    if len(users) > 6:
        return await ctx.respond("Too many users given, max 6")

    usernames = [data.username for data in users]

    important_types = [
        ["Data Structures"],
        ["Dynamic Programming"],
        ["Graph Theory"],
        ["String Algorithms"],
        ["Advanced Math", "Geometry", "Intermediate Math", "Simple Math"],
        ["Ad Hoc"],
        ["Greedy Algorithms"],
    ]
    labels = [
        "Data Structures",
        "Dynamic Programming",
        "Graph Theory",
        "String Algorithms",
        "Math",
        "Ad Hoc",
        "Greedy Algorithms",
    ]

    data = {}
    data["group"] = []
    for label in labels:
        data[label] = []
    for username in usernames:
        data["group"].append(username)

    def calculate_partial_points(points: int):
        p = 0
        for i in range(min(100, len(points))):
            p += (0.95**i) * points[i]
        return p

    max_percentage = 0

    for username in usernames:
        q = session.query(Submission_DB).filter(Submission_DB._user == username)
        if q.count() == 0:
            await ctx.respond(f"`{username}` does not have any cached submissions, caching now")
            await query.get_submissions(username)

    for i, types in enumerate(important_types):
        total_problems = await query.get_problems(_type=types, cached=True)
        total_points = list(map(attrgetter("points"), total_problems))
        total_points.sort(reverse=True)
        total_points = calculate_partial_points(total_points)

        for username in usernames:
            points = query.get_attempted_problems(username, types)

            points.sort(reverse=True)

            points = calculate_partial_points(points)
            if as_percent:
                percentage = 100 * points / total_points
            else:
                percentage = points
            max_percentage = max(max_percentage, percentage)
            data[labels[i]].append(percentage)

    logger.debug("plot type data: %s", data)

    if graph_type == "radar":
        plot_type_radar(data, as_percent, max_percentage)
    elif graph_type == "bar":
        plot_type_bar(data, as_percent)

    embed = hikari.Embed(
        title="Problem types solved",
        color=0xFCDB05,
    )
    with open("./graphs/plot.png", "rb") as file:
        embed.set_image(hikari.Bytes(file.read(), "plot.png"))

    return await ctx.respond(embed=embed)
Exemplo n.º 19
0
async def vc(ctx):
    usernames = ctx.options.usernames
    print(usernames)
    query = Query()
    if usernames == []:
        username = query.get_handle(ctx.author.id, ctx.get_guild().id)
        if username:
            usernames = [username]

    users = await asyncio.gather(
        *[query.get_user(username) for username in usernames])
    usernames = [user.username for user in users]
    for i in range(len(users)):
        if users[i] is None:
            return await ctx.respond(f"{usernames[i]} does not exist on DMOJ")

    q = session.query(Contest_DB)
    for user in users:
        # if the user has attempted any problems from the problem set
        sub_q = (session.query(Submission_DB, func.max(
            Submission_DB.points)).filter(
                Submission_DB._user == user.username).group_by(
                    Submission_DB._code).subquery())
        sub_q = (session.query(Problem_DB.code).join(
            sub_q, Problem_DB.code == sub_q.c._code,
            isouter=True).filter(func.ifnull(sub_q.c.points, 0) != 0))
        sub_q = list(map(itemgetter(0), sub_q.all()))
        q = (q.filter(not_(Contest_DB.rankings.contains(
            user.username))).filter(
                ~Contest_DB.problems.any(Problem_DB.code.in_(sub_q))).filter(
                    Contest_DB.is_private == 0).filter(
                        Contest_DB.is_organization_private == 0))

    if q.count() == 0:
        await ctx.respond("Cannot find any contests which "
                          "all users have not done")
        return

    contests = q.all()

    while True:
        contest = random.choice(contests)
        try:
            contest = await query.get_contest(contest.key, cached=False)
            break
        except ObjectNotFound:
            pass

    # When problems are private, it says there are no problems
    window = "No"
    is_rated = "Not Rated"
    if contest.time_limit:
        window = f"{round(contest.time_limit/60/60, 2)} Hr"
    if contest.is_rated:
        is_rated = "Rated"
    embed = hikari.Embed(
        title=contest.name,
        url=f"https://dmoj.ca/contest/{contest.key}",
        description=
        f"{window} window | {len(contest.problems)} Problems | {is_rated}",
        color=0xFCDB05,
    )
    await ctx.respond(embed=embed)
Exemplo n.º 20
0
    async def rating(self, ctx, *args, perf=False):
        '''Plot rating progression'''
        usernames = []
        peak = False
        raw = False
        for arg in args:
            if arg in ['+peak', '+max']:
                peak = True
            elif arg == '+raw':
                raw = True
            elif arg == '+perf':
                perf = True
            else:
                usernames.append(arg)
        query = Query()
        if usernames == []:
            usernames = [query.get_handle(ctx.author.id, ctx.guild.id)]

        try:
            users = await asyncio.gather(
                *[query.get_user(username) for username in usernames])
        except ObjectNotFound:
            return await ctx.send('User not found')

        usernames = [user.username for user in users]
        for i in range(len(users)):
            if users[i] is None:
                return await ctx.send(f'{usernames[i]} does not exist on DMOJ')
        if len(users) > 10:
            return await ctx.send('Too many users given, max 10')

        cond = [Contest_DB.rankings.contains(user.username) for user in users]
        q = session.query(Contest_DB).filter(or_(*cond))\
            .filter(Contest_DB.is_rated == 1)
        contests = q.all()

        ratingVals = {}
        for (i, user) in enumerate(users):
            prevMax = -1e9
            for contest in user._contests:
                val = 0
                if perf:
                    val = contest['performance']
                elif raw:
                    val = contest['raw_rating']
                else:
                    val = contest['rating']
                if not peak or val and prevMax < val:
                    prevMax = val
                    ratingVals[contest['key'] + '.' + user.username] = val

        data = {}
        data['users'] = [user.username for user in users]

        for contest in contests:
            data[contest.end_time] = []
            for user in users:
                if contest.key + '.' + user.username in ratingVals:
                    data[contest.end_time].append(
                        ratingVals[contest.key + '.' + user.username])
                else:
                    data[contest.end_time].append(None)
        plot_rating(data)
        with open('./graphs/plot.png', 'rb') as file:
            file = discord.File(io.BytesIO(file.read()), filename='plot.png')
        embed = discord.Embed(
            title='Contest Rating',
            color=0xfcdb05,
        )
        embed.set_image(url='attachment://plot.png')

        return await ctx.send(embed=embed, file=file)
Exemplo n.º 21
0
    async def solved(self, ctx, *args):
        '''Plot problems solved over time'''
        usernames = []
        minDate = datetime.min
        maxDate = datetime.max
        for arg in args:
            if arg.startswith('d>='):
                minDate = arg[3:]
                minDate = datetime(int(minDate[4:]), int(minDate[2:4]),
                                   int(minDate[0:2]))
            elif arg.startswith('d<='):
                maxDate = arg[3:]
                maxDate = datetime(int(maxDate[4:]), int(maxDate[2:4]),
                                   int(maxDate[0:2]))
            else:
                usernames.append(arg)

        query = Query()
        if usernames == []:
            usernames = [query.get_handle(ctx.author.id, ctx.guild.id)]

        try:
            users = await asyncio.gather(
                *[query.get_user(username) for username in usernames])
        except ObjectNotFound:
            return await ctx.send('User not found')

        usernames = [user.username for user in users]
        for i in range(len(users)):
            if users[i] is None:
                return await ctx.send(f'{usernames[i]} does not exist on DMOJ')
        if len(users) > 10:
            return await ctx.send('Too many users given, max 10')

        total_data = {}
        for username in usernames:
            await query.get_submissions(username)
            q = session.query(Submission_DB)\
                .filter(Submission_DB._user == username)
            if q.count() == 0:
                await ctx.send(
                    f'`{username}` does not have any cached submissions, caching now'
                )
                await query.get_submissions(username)

            q = session.query(func.min(Submission_DB.date))\
                .join(Problem_DB, Problem_DB.code == Submission_DB._code)\
                .filter(Submission_DB._user == username)\
                .filter(Submission_DB.points == Problem_DB.points)\
                .group_by(Submission_DB._code)
            dates = list(map(itemgetter(0), q.all()))
            dates.sort()
            data_to_plot = {}
            cnt = 0
            for date in dates:
                if minDate <= date and date <= maxDate:
                    cnt += 1
                    data_to_plot[date] = cnt
            total_data[username] = data_to_plot

        plot_solved(total_data)

        with open('./graphs/plot.png', 'rb') as file:
            file = discord.File(io.BytesIO(file.read()), filename='plot.png')
        embed = discord.Embed(
            title='Problems Solved',
            color=0xfcdb05,
        )
        embed.set_image(url='attachment://plot.png')

        return await ctx.send(embed=embed, file=file)
Exemplo n.º 22
0
async def _set(ctx):
    """Manually link two accounts together"""
    # TODO: I don't like the bot spamming replies to itself, figure out a way to lessen that
    member = ctx.options.member
    username = ctx.options.handle
    query = Query()

    if username != "+remove":
        try:
            user = await query.get_user(username)

            if user is None:
                raise ObjectNotFound()
        except ObjectNotFound:
            await ctx.respond(escape_markdown(f"{username} does not exist on dmoj"))
            return

        username = user.username

    handle = query.get_handle(member.id, ctx.get_guild().id)
    if handle == username:
        return await ctx.respond(escape_markdown(f"{member.display_name} is already linked with {handle}"))

    if handle:
        handle = (
            session.query(Handle_DB)
            .filter(Handle_DB.id == member.id)
            .filter(Handle_DB.guild_id == ctx.get_guild().id)
            .first()
        )
        session.delete(handle)
        session.commit()
        await ctx.respond(escape_markdown(f"Unlinked {member.display_name} with handle {handle.handle}"))

    if username == "+remove":
        return

    if query.get_handle_user(username, ctx.get_guild().id):
        await ctx.respond("This handle is already linked with another user")
        return

    handle = Handle_DB()
    handle.id = member.id
    handle.handle = username
    handle.user_id = user.id
    handle.guild_id = ctx.get_guild().id
    session.add(handle)
    session.commit()
    await ctx.respond(escape_markdown(f"Linked {member.display_name} with {username}"))

    rank_to_role = {}
    rc = lightbulb.RoleConverter(ctx)
    for role_id in ctx.get_guild().get_roles():
        role = await rc.convert(str(role_id))
        if role.name in RANKS:
            rank_to_role[role.name] = role

    rank = rating_to_rank(user.rating)
    if rank in rank_to_role:
        await _update_rank(member, rank_to_role[rank], "Dmoj account linked")
    else:
        await ctx.respond("You are missing the `" + rank.name + "` role")
Exemplo n.º 23
0
    async def gotgud(self, ctx):
        """
        Confirm completion of gitgud challenge
        """
        query = Query()
        gitgud_util = Gitgud_utils()
        username = query.get_handle(ctx.author.id, ctx.guild.id)

        if username is None:
            return await ctx.send("You are not linked with a DMOJ Account")

        user = await query.get_user(username)
        current = gitgud_util.get_current(username, ctx.guild.id)
        closest = -1000
        for key in RATING_TO_POINT:
            if abs(key - user.rating) <= abs(closest - user.rating):
                closest = key

        # convert rating to point and get difference
        rating_point = RATING_TO_POINT[closest]
        if current is None or current.problem_id is None:
            return await ctx.send("No pending challenges")

        # check if user is scamming the bot :monkey:
        if gitgud_util.has_solved(username, current.problem_id):
            # get closest rating
            closest = -1000
            for key in RATING_TO_POINT:
                if abs(key - user.rating) <= abs(closest - user.rating):
                    closest = key
            # convert rating to point and get difference
            rating_point = RATING_TO_POINT[closest]
            point_diff = (POINT_VALUES.index(current.point) -
                          POINT_VALUES.index(rating_point))
            print(point_diff)
            point = 10 + 2 * (point_diff)
            point = max(point, 0)

            gitgud_util.insert(username, ctx.guild.id, point,
                               current.problem_id, datetime.now())
            gitgud_util.clear(username, ctx.guild.id)

            completion_time = datetime.now() - current.time
            # convert from timedelta to readable string
            ret = ""
            cnt = 0
            if completion_time.days // 365 != 0:
                ret += f" {completion_time.days // 365} years"
                cnt += 1
            if completion_time.days % 365 != 0:
                ret += f" {completion_time.days % 365} days"
                cnt += 1
            if completion_time.seconds // 3600 != 0:
                ret += f" {completion_time.seconds // 3600} hours"
                cnt += 1
            if cnt < 3 and completion_time.seconds % 3600 // 60 != 0:
                ret += f" {completion_time.seconds % 3600 // 60} minutes"
                cnt += 1
            if cnt < 3 and completion_time.seconds % 60 != 0:
                ret += f" {completion_time.seconds % 60} seconds"

            return await ctx.send(f"Challenge took{ret}. "
                                  f"{current.handle} gained {point} points")

        else:
            return await ctx.send("You have not completed the challenge")
Exemplo n.º 24
0
    async def userinfo(self, ctx, username: typing.Optional[str_not_int] = None,
                       amount: typing.Optional[int] = None):
        """Show user profile and latest submissions

        Use surround your username with '' if it can be interpreted as a number
        """

        query = Query()
        username = username or query.get_handle(ctx.author.id, ctx.guild.id)
        # If user is not found in db
        if username is None:
            username = str(amount)
            amount = None

        if username is None:
            return

        if amount is not None:
            amount = min(amount, 8)
            if amount < 1:
                return await ctx.send('Please request at least one submission')

        try:
            user = await query.get_user(username)
        except ObjectNotFound:
            return await ctx.send(f'{username} does not exist on DMOJ')

        username = user.username

        def is_rated(contest):
            return 1 if contest.is_rated else 0

        discordHandle = ctx.message.guild.get_member(query.get_handle_user(username, ctx.guild.id))
        if discordHandle:
            discordHandle = discordHandle.nick or discordHandle.name
        else:
            discordHandle = "Unknown"
        if user.rating is None:
            color = 0xfefefe  # it breaks when I set it to white
        elif user.rating >= 3000:
            color = 0x000000
        elif user.rating >= 2600:
            color = 0xa00000
        elif user.rating >= 2200:
            color = 0xee0000
        elif user.rating >= 1800:
            color = 0xffb100
        elif user.rating >= 1500:
            color = 0x800080
        elif user.rating >= 1200:
            color = 0x0000ff
        elif user.rating >= 1000:
            color = 0x00a900
        elif user.rating >= 0:
            color = 0x999999
        else:
            color = 0x000000
        description = f'Discord name: {discordHandle}'
        embed = discord.Embed(
            title=username,
            url=f'https://dmoj.ca/user/{username}',
            description=description,
            color=color,  # rating color
        )

        embed.set_thumbnail(url=await query.get_pfp(username))
        embed.add_field(
            name="Points",
            value=str(round(user.performance_points)) + "/" + str(round(user.points)),
            inline=True
        )
        embed.add_field(
            name="Problems Solved",
            value=user.problem_count,
            inline=True
        )
        embed.add_field(
            name="Rating",
            value=str(user.rating) + "/" + str(user.max_rating),
            inline=True
        )
        embed.add_field(
            name="Contests Written",
            value=sum(map(is_rated, user.contests)),
            inline=True
        )

        await ctx.send(embed=embed)

        if amount is None:
            return

        submissions = await query.get_latest_submissions(username, amount)

        embed = discord.Embed(
            title=f"{username}'s latest submissions",
            color=0xffff00
        )
        for submission in submissions:
            problem = submission.problem[0]
            if problem.points is not None:
                points = str(int(problem.points)) + 'p'
                if problem.partial:
                    points += 'p'
            else:
                points = '???'

            true_short_name = submission.language[0].short_name
            if true_short_name == '':
                # wtf dmoj
                true_short_name = submission.language[0].key

            embed.add_field(
                name="%s / %s" %
                     (str(submission.score_num), str(submission.score_denom)),
                value="%s | %s" % (submission.result,
                                   true_short_name),
                inline=True
            )

            embed.add_field(
                name="%s (%s)" %
                     (submission.problem[0].name, points),
                value="%s | [Problem](https://dmoj.ca/problem/%s)" %
                      (submission.date.astimezone(TZ).
                       strftime("%b. %d, %Y, %I:%M %p").
                       replace('AM', 'a.m.').
                       replace('PM', 'p.m.'),
                       submission.problem[0].code),
                      # Jan. 13, 2021, 12:17 a.m.
                      # %b. %d, %Y, %I:%M %p
                inline=True
            )
            try:
                embed.add_field(
                    name="%.2fs" % submission.time,
                    value="%s" % submission.memory_str,
                    inline=True,
                )
            except TypeError:
                embed.add_field(
                    name="---",
                    value="%s" % submission.memory_str,
                    inline=True,
                )

        await ctx.send(embed=embed)
        return None
Exemplo n.º 25
0
    async def gitgud(self, ctx, points: typing.Optional[point_range],
                     *filters):
        """
          Recommend a problem and gain point upon completion

        SHORTHANDS:
        - adhoc
        - math
        - bf
        - ctf
        - ds
        - d&c
        - dp
        - geo
        - gt
        - greedy
        - regex
        - string
        """

        filters = list(filters)
        query = Query()
        gitgud_util = Gitgud_utils()
        # get the user's dmoj handle
        username = query.get_handle(ctx.author.id, ctx.guild.id)
        # user = await query.get_user(username)

        if username is None:
            return await ctx.send("You are not linked to a DMOJ Account. "
                                  "Please link your account before continuing")

        user = await query.get_user(username)

        if points is None:
            points = [0, 0]
            closest = -1000
            for key in RATING_TO_POINT:
                if abs(key - user.rating) <= abs(closest - user.rating):
                    closest = key
            points[0] = RATING_TO_POINT[closest]
            points[1] = points[0]
        # return if the user haven't finished the previous problem
        current = gitgud_util.get_current(username, ctx.guild.id)

        if current is not None and current.problem_id is not None:
            if not gitgud_util.has_solved(username, current.problem_id):
                # User has a current problem unsolved
                problem = await query.get_problem(current.problem_id)
                embed = discord.Embed(
                    description=f"You currently have an uncompleted "
                    f"challenge, [{problem.name}]"
                    f"(https://dmoj.ca/problem/{problem.code})",
                    color=0xfcdb05,
                )
                return await ctx.send(embed=embed)

        filter_list = []
        for filter in filters:
            if filter in SHORTHANDS:
                filter_list.append(SHORTHANDS[filter])

        filters = filter_list

        embed, problem = await gimme_common(username, points, filters)

        if embed is None:
            return await ctx.send("No problems that satisfies the filter")

        gitgud_util.bind(username, ctx.guild.id, problem.code, problem.points,
                         datetime.now())

        embed.description = "Points: %s\nProblem Types ||%s||" % \
                            (problem.points, ', '.join(problem.types))

        return await ctx.send(embed=embed)
Exemplo n.º 26
0
    async def user(self, ctx, username: typing.Optional[str_not_int] = None,
                   amount: typing.Optional[int] = None):
        """Show user profile and latest submissions
        Use surround your username with '' if it can be interpreted as a number
        """

        query = Query()
        username = username or query.get_handle(ctx.author.id, ctx.guild.id)

        # If user is not found in db
        if username is None:
            username = str(amount)
            amount = None

        if username is None:
            return

        if amount is not None:
            amount = min(amount, 8)
            if amount < 1:
                return await ctx.send('Please request at least one submission')

        try:
            user = await query.get_user(username)
        except ObjectNotFound:
            return await ctx.send(f'{username} does not exist on DMOJ')

        username = user.username

        def is_rated(contest):
            return 1 if contest.is_rated else 0

        description = 'Calculated points: %.2f' % user.performance_points
        embed = discord.Embed(
            title=username,
            url=f'https://dmoj.ca/user/{username}',
            description=description,
            color=0xfcdb05,
        )

        embed.set_thumbnail(url=await query.get_pfp(username))
        embed.add_field(
            name="Rank by points",
            value=await query.get_placement(username),
            inline=False
        )
        embed.add_field(
            name="Problems Solved",
            value=user.problem_count,
            inline=False
        )
        embed.add_field(
            name="Rating",
            value=user.rating,
            inline=True
        )
        embed.add_field(
            name="Contests Written",
            value=sum(map(is_rated, user.contests)),
            inline=True
        )

        await ctx.send(embed=embed)

        if amount is None:
            return

        submissions = await query.get_latest_submissions(username, amount)

        embed = discord.Embed(
            title=f"{username}'s latest submissions",
            color=0xfcdb05
        )
        for submission in submissions:
            problem = submission.problem[0]
            if problem.points is not None:
                points = str(int(problem.points)) + 'p'
                if problem.partial:
                    points += 'p'
            else:
                points = '???'

            true_short_name = submission.language[0].short_name
            if true_short_name == '':
                # wtf dmoj
                true_short_name = submission.language[0].key

            embed.add_field(
                name="%s / %s" %
                     (str(submission.score_num), str(submission.score_denom)),
                value="%s | %s" % (submission.result,
                                   true_short_name),
                inline=True
            )

            embed.add_field(
                name="%s (%s)" %
                     (submission.problem[0].name, points),
                value="%s | [Problem](https://dmoj.ca/problem/%s)" %
                      (submission.date.astimezone(TZ).
                       strftime("%b. %d, %Y, %I:%M %p").
                       replace('AM', 'a.m.').
                       replace('PM', 'p.m.'),
                       submission.problem[0].code),
                      # Jan. 13, 2021, 12:17 a.m.
                      # %b. %d, %Y, %I:%M %p
                inline=True
            )
            try:
                embed.add_field(
                    name="%.2fs" % submission.time,
                    value="%s" % submission.memory_str,
                    inline=True,
                )
            except TypeError:
                embed.add_field(
                    name="---",
                    value="%s" % submission.memory_str,
                    inline=True,
                )

        await ctx.send(embed=embed)
        return None
Exemplo n.º 27
0
async def predict(ctx):
    username = ctx.options.username
    amounts = ctx.options.point_vals

    query = Query()
    username = username or query.get_handle(ctx.author.id, ctx.get_guild().id)
    if username is None and len(amounts) > 0:
        username = str([0])
        amounts.pop(0)

    if amounts == []:
        return await ctx.respond("No points given!")

    if username is None:
        return await ctx.respond("No username given!")

    username = username.replace("'", "")

    amounts = amounts[:10]

    user = await query.get_user(username)
    if user is None:
        return await ctx.respond(f"{username} does not exist on DMOJ")

    username = user.username
    q = (session.query(Submission_DB).options(orm.joinedload("problem")).join(
        User_DB, User_DB.username == Submission_DB._user,
        aliased=True).filter(User_DB.username == user.username))

    if q.count():
        submissions = q.all()
        msg = None
    else:
        await ctx.respond("No submissions cached, "
                          "Please use +cache or /cache to get new submissions")
        return

    problems_ACed = dict()
    code_to_points = dict()
    for submission in submissions:
        code = submission.problem[0].code
        points = submission.points
        result = submission.result

        if points is not None:
            if result == "AC":
                problems_ACed[code] = 1
            if code not in code_to_points:
                code_to_points[code] = points
            elif points > code_to_points[code]:
                code_to_points[code] = points

    fully_solved = len(problems_ACed)
    points = list(code_to_points.values())
    points.sort(reverse=True)

    embed = hikari.Embed(
        title=f"Point prediction for {username}",
        description="Current points: %.2fp" %
        calculate_points(points, fully_solved),
        color=0xFCDB05,
    )

    embed.set_thumbnail(await query.get_pfp(username))

    for predict_val in amounts:
        points.append(int(predict_val))
        fully_solved += 1
        points.sort(reverse=True)
        updated_points = calculate_points(points, fully_solved)
        embed.add_field(
            name="Solve another %sp" % predict_val,
            value="Total points: %.2fp" % updated_points,
            inline=False,
        )

    if msg:
        await msg.delete()
    await ctx.respond(embed=embed)
    return
Exemplo n.º 28
0
    async def postcontest(self, ctx, key, option=''):
        '''Updates post-contest role'''
        def has_admin_perms(ctx):
            return any(
                get(ctx.guild.roles, name=role) in ctx.author.roles
                for role in ADMIN_ROLES)

        update_all = option == '+all' and has_admin_perms(ctx)

        query = Query()

        if update_all:
            usernames = session.query(Handle_DB).filter(
                Handle_DB.guild_id == ctx.guild.id).all()
        else:
            username = query.get_handle(ctx.author.id, ctx.guild.id)

            if username is None:
                return await ctx.send('Your account is not linked!')

        q = session.query(Contest_DB).filter(Contest_DB.key == key)
        # Clear cache
        if q.count():
            q.delete()
            session.commit()
        try:
            contest = await query.get_contest(key)
        except ObjectNotFound:
            await ctx.send('Contest not found')
            return

        if contest.is_organization_private:
            return await ctx.send('Contest not found')

        role = get(ctx.guild.roles, name='postcontest ' + key)
        if not role:
            return await ctx.send(f'No `postcontest {key}` role found.')

        if update_all:
            participants = set()
            for ranking in contest.rankings:
                endTime = datetime.strptime(ranking['end_time'],
                                            '%Y-%m-%dT%H:%M:%S%z')
                if endTime < datetime.now(timezone.utc).astimezone():
                    participants.add(ranking['user'])

            for user in usernames:
                if user.handle in participants:
                    try:
                        await ctx.guild.get_member(user.id).add_roles(role)
                    except discord.Forbidden:
                        return await ctx.send(
                            'No permission to assign the role')
                    except AttributeError:
                        pass
            return await ctx.send('Updated post contest for ' + key)

        for ranking in contest.rankings:
            if ranking['user'].lower() != username.lower():
                continue

            endTime = datetime.strptime(ranking['end_time'],
                                        '%Y-%m-%dT%H:%M:%S%z')
            if endTime > datetime.now(timezone.utc).astimezone():
                return await ctx.send('Your window is not done')
            else:
                try:
                    await ctx.author.add_roles(role)
                except discord.Forbidden:
                    return await ctx.send('No permission to assign the role')
                return await ctx.send('You\'ve been added to post contest')
        return await ctx.send('You haven\'t joined the contest yet')
Exemplo n.º 29
0
async def user(ctx):
    # TODO Optimize the two calls to /user
    username = ctx.options.username
    amount = ctx.options.amount
    query = Query()
    username = username or query.get_handle(ctx.author.id, ctx.get_guild().id)

    # If user is not found in db
    if username is None:
        username = str(amount)
        amount = None

    if username is None:
        return await ctx.respond("No username given!")

    username = username.replace("'", "")

    if amount is not None:
        amount = min(amount, 8)
        if amount < 1:
            return await ctx.respond("Please request at least one submission")

    try:
        user = await query.get_user(username)
    except ObjectNotFound:
        return await ctx.respond(f"{username} does not exist on DMOJ")

    username = user.username

    def is_rated(contest):
        return 1 if contest.is_rated else 0

    description = "Calculated points: %.2f" % user.performance_points
    embed = hikari.Embed(
        title=username,
        url=f"https://dmoj.ca/user/{username}",
        description=description,
        color=0xFCDB05,
    )

    embed.set_thumbnail(await query.get_pfp(username))
    embed.add_field(name="Rank by points",
                    value=await query.get_placement(username),
                    inline=False)
    embed.add_field(name="Problems Solved",
                    value=user.problem_count,
                    inline=False)
    embed.add_field(name="Rating", value=user.rating, inline=True)
    embed.add_field(name="Contests Written",
                    value=sum(map(is_rated, user.contests)),
                    inline=True)

    await ctx.respond(embed=embed)

    if amount is None:
        return

    submissions = await query.get_latest_submissions(username, amount)

    embed = hikari.Embed(title=f"{username}'s latest submissions",
                         color=0xFCDB05)
    for submission in submissions:
        problem = submission.problem[0]
        if problem.points is not None:
            points = str(int(problem.points)) + "p"
            if problem.partial:
                points += "p"
        else:
            points = "???"

        true_short_name = submission.language[0].short_name
        if true_short_name == "":
            # wtf dmoj
            true_short_name = submission.language[0].key

        embed.add_field(
            name="%s / %s" %
            (str(submission.score_num), str(submission.score_denom)),
            value="%s | %s" % (submission.result, true_short_name),
            inline=True,
        )

        embed.add_field(
            name="%s (%s)" % (submission.problem[0].name, points),
            value="%s | [Problem](https://dmoj.ca/problem/%s)" % (
                submission.date.astimezone(TZ).strftime("%b. %d, %Y, %I:%M %p")
                .replace("AM", "a.m.").replace("PM", "p.m."),
                submission.problem[0].code,
            ),
            # Jan. 13, 2021, 12:17 a.m.
            # %b. %d, %Y, %I:%M %p
            inline=True,
        )
        try:
            embed.add_field(
                name="%.2fs" % submission.time,
                value="%s" % submission.memory_str,
                inline=True,
            )
        except TypeError:
            embed.add_field(
                name="---",
                value="%s" % submission.memory_str,
                inline=True,
            )

    await ctx.respond(embed=embed)
    return None
Exemplo n.º 30
0
async def points(ctx):
    """Plot point progression"""
    usernames = ctx.options.usernames

    query = Query()
    if usernames == []:
        usernames = [query.get_handle(ctx.author.id, ctx.get_guild().id)]

    try:
        users = await asyncio.gather(*[query.get_user(username) for username in usernames])
    except ObjectNotFound:
        return await ctx.respond("User not found")

    usernames = [user.username for user in users]
    for i in range(len(users)):
        if users[i] is None:
            return await ctx.respond(f"{usernames[i]} does not exist on DMOJ")
    if len(users) > 10:
        return await ctx.respond("Too many users given, max 10")

    total_data = {}
    for username in usernames:
        q = (
            session.query(Submission_DB)
            .options(orm.joinedload("problem"))
            .join(User_DB, User_DB.username == Submission_DB._user, aliased=True)
            .filter(User_DB.username == username)
            .order_by(Submission_DB.date)
        )

        submissions = q.all()
        if len(submissions) == 0:
            await ctx.respond(f"`{username}` does not have any cached submissions, caching now")
            await query.get_submissions(username)
            submissions = q.all()
        problems_ACed = dict()
        code_to_points = dict()

        points_arr = []
        data_to_plot = {}
        # O(N^2logN) :blobcreep:
        for submission in submissions:
            code = submission.problem[0].code
            points = submission.points
            result = submission.result

            if points is not None:
                if result == "AC":
                    problems_ACed[code] = 1
                if code not in code_to_points:
                    # log N search, N insert
                    code_to_points[code] = points
                    bisect.insort(points_arr, points)
                elif points > code_to_points[code]:
                    # N remove, log N search, N insert
                    points_arr.remove(code_to_points[code])
                    code_to_points[code] = points
                    bisect.insort(points_arr, points)
                cur_points = calculate_points(points_arr[::-1], len(problems_ACed))
                data_to_plot[submission.date] = cur_points
        total_data[username] = data_to_plot

    plot_points(total_data)

    embed = hikari.Embed(
        title="Problems Progression",
        color=0xFCDB05,
    )
    with open("./graphs/plot.png", "rb") as file:
        embed.set_image(hikari.Bytes(file.read(), "plot.png"))

    return await ctx.respond(embed=embed)