async def rating(ctx): """Plot rating progression""" peak = ctx.options.peak 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") 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() def get_rating_change(rankings, users): ret = {} for ranking in rankings: for user in users: if user.username == ranking["user"] and ranking["new_rating"]: ret[user.username] = ranking["new_rating"] return ret data = {} data["users"] = [user.username for user in users] userPrevRating = {} for contest in contests: changes = get_rating_change(contest.rankings, users) data[contest.end_time] = [] for user in users: if user.username in changes and ( not peak or changes[user.username] >= userPrevRating.get(user.username, -9999) ): change = changes[user.username] userPrevRating[user.username] = change data[contest.end_time].append(change) else: data[contest.end_time].append(None) plot_rating(data) embed = hikari.Embed( title="Rating 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)
async def rating(self, ctx, peak: typing.Optional[plot_peak] = False, *usernames): """Plot rating 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') 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() def get_rating_change(rankings, users): ret = {} for ranking in rankings: for user in users: if (user.username == ranking['user'] and ranking['new_rating']): ret[user.username] = ranking['new_rating'] return ret data = {} data['users'] = [user.username for user in users] userPrevRating = {} for contest in contests: changes = get_rating_change(contest.rankings, users) data[contest.end_time] = [] for user in users: if user.username in changes \ and (not peak or changes[user.username] >= userPrevRating.get(user.username, -9999)): change = changes[user.username] userPrevRating[user.username] = change data[contest.end_time].append(change) 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)
async def solved(self, ctx, *usernames): """Plot problems solved over time""" 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)\ .filter(Submission_DB._user == username) if q.count() == 0: not_cached.append(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(first_tuple, q.all())) dates.sort() data_to_plot = {} cnt = 0 for date in dates: cnt += 1 data_to_plot[date] = cnt total_data[username] = data_to_plot plot_solved(total_data) 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='Problems Solved', color=0xfcdb05, ) embed.set_image(url=f'attachment://plot.png', ) return await ctx.send(embed=embed, file=file)
async def solved(ctx): """Plot problems solved over time""" 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).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) 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: cnt += 1 data_to_plot[date] = cnt total_data[username] = data_to_plot plot_solved(total_data) embed = hikari.Embed( title="Problems 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)
async def vc(self, ctx, *usernames): """Suggest a contest""" usernames = list(usernames) query = Query() if usernames == []: username = query.get_handle(ctx.author.id, ctx.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.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' is_rated = 'Not Rated' if contest.time_limit: window = f"{contest.time_limit/60/60} Hr" if contest.is_rated: is_rated = "Rated" embed = discord.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.send(embed=embed)
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)
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)
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)
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)
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)
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)
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)
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)] 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)\ .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.send( 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) 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)