diff options
author | 2021-11-04 13:17:50 -0400 | |
---|---|---|
committer | 2022-02-09 18:13:37 -0500 | |
commit | 1848d0ddd318ff3eee0c9c9efed9fef89f460b21 (patch) | |
tree | 44a43ed600d0d05e007e3466df7e44bad494bdc8 | |
parent | cog description for .trivianight, and allowing to pick questions that were al... (diff) |
kahoot style scoring, time limits, and bug fixes
-rw-r--r-- | bot/exts/events/trivianight/_questions.py | 59 | ||||
-rw-r--r-- | bot/exts/events/trivianight/_scoreboard.py | 2 | ||||
-rw-r--r-- | bot/exts/events/trivianight/trivianight.py | 40 |
3 files changed, 66 insertions, 35 deletions
diff --git a/bot/exts/events/trivianight/_questions.py b/bot/exts/events/trivianight/_questions.py index 8b4df74d..aaedf068 100644 --- a/bot/exts/events/trivianight/_questions.py +++ b/bot/exts/events/trivianight/_questions.py @@ -1,6 +1,6 @@ from random import choice, randrange from time import perf_counter -from typing import TypedDict, Union +from typing import Optional, TypedDict, Union import discord from discord import Embed, Interaction @@ -27,6 +27,8 @@ class CurrentQuestion(TypedDict): description: str answers: list[str] correct: str + points: Optional[int] + time: Optional[int] class QuestionButton(Button): @@ -106,22 +108,16 @@ class QuestionView(View): for button in self.buttons: button._time = current_time - return question_embed + time_limit = self.current_question.get("time", 10) + + return question_embed, time_limit def end_question(self) -> tuple[dict, Embed]: """Returns the dictionaries from the corresponding buttons for those who got it correct.""" labels = ("A", "B", "C", "D") label = labels[self.current_question["answers"].index(self.current_question["correct"])] - return_dict = {name: info for name, info in self.users_picked.items() if info[0] == label} + return_dict = {name: (*info, info[0] == label) for name, info in self.users_picked.items()} all_players = list(self.users_picked.items()) - answers_chosen = { - answer_choice: len( - tuple(filter(lambda x: x[0] == answer_choice, self.users_picked.values())) - ) / len(all_players) - for answer_choice in "ABCD" - } - - answers_chosen = dict(sorted(answers_chosen.items(), key=lambda item: item[1], reverse=True)) answer_embed = Embed( title=f"The correct answer for Question {self.current_question['number']} was..", @@ -129,20 +125,33 @@ class QuestionView(View): color=Colours.soft_green ) - for answer, percent in answers_chosen.items(): - # The `ord` function is used here to change the letter, say 'A' to its corresponding position in the answers - answer_embed.add_field( - name=f"{percent * 100:.1f}% of players chose", - value=self.current_question['answers'][ord(answer) - 65], - inline=False - ) + if len(all_players) != 0: + answers_chosen = { + answer_choice: len( + tuple(filter(lambda x: x[0] == answer_choice, self.users_picked.values())) + ) / len(all_players) + for answer_choice in "ABCD" + } + + answers_chosen = dict(sorted(answers_chosen.items(), key=lambda item: item[1], reverse=True)) + + for answer, percent in answers_chosen.items(): + # The `ord` function is used here to change the letter to its corresponding position + answer_embed.add_field( + name=f"{percent * 100:.1f}% of players chose", + value=self.current_question['answers'][ord(answer) - 65], + inline=False + ) self.users_picked = {} for button in self.buttons: button.users_picked = self.users_picked - return return_dict, answer_embed + time_limit = self.current_question.get("time", 10) + question_points = self.current_question.get("points", 10) + + return return_dict, answer_embed, time_limit, question_points class Questions: @@ -209,8 +218,14 @@ class Questions: def end_question(self) -> Embed: """Terminates answering of the question and displays the correct answer.""" - scores, answer_embed = self.view.end_question() + scores, answer_embed, time_limit, total_points = self.view.end_question() for user, score in scores.items(): - self.scoreboard[UserScore(user)] = {"points": 1, "speed": score[2]} - + # Overhead with calculating scores leads to inflated times, subtracts 0.5 to give an accurate depiction + time_taken = score[2] - 0.5 + point_calculation = (1 - (time_taken / time_limit) / 2) * total_points + if score[-1] is True: + self.scoreboard[UserScore(user)] = {"points": point_calculation, "speed": time_taken} + elif score[-1] is False and score[2] <= 2: + # Get the negative of the point_calculation to deduct it + self.scoreboard[UserScore(user)] = {"points": -point_calculation} return answer_embed diff --git a/bot/exts/events/trivianight/_scoreboard.py b/bot/exts/events/trivianight/_scoreboard.py index 1bde59f5..2adb5e37 100644 --- a/bot/exts/events/trivianight/_scoreboard.py +++ b/bot/exts/events/trivianight/_scoreboard.py @@ -27,7 +27,7 @@ class ScoreboardView(View): user = await self.bot.fetch_user(int(user)) formatted_string += f"**{current_placement + 1}.** {user.mention} " - formatted_string += f"({points} pts)\n" + formatted_string += f"({points:.1f} pts)\n" if (current_placement + 1) % 10 == 0: formatted_string += "⎯⎯⎯⎯⎯⎯⎯⎯\n" diff --git a/bot/exts/events/trivianight/trivianight.py b/bot/exts/events/trivianight/trivianight.py index 37a29222..9973b6b1 100644 --- a/bot/exts/events/trivianight/trivianight.py +++ b/bot/exts/events/trivianight/trivianight.py @@ -1,3 +1,4 @@ +import asyncio from json import loads from random import choice @@ -27,18 +28,19 @@ class TriviaNight(commands.Cog): for idx, letter in enumerate(text) ) - @commands.group() + @commands.group(aliases=["tn"], invoke_without_command=True) async def trivianight(self, ctx: commands.Context) -> None: """No-op subcommand group for organizing different commands.""" - cog_description = Embed( - title="What is .trivianight?", - description=( - "This 'cog' is for the Python Discord's TriviaNight (date tentative)! Compete against other" - "players in a trivia about Python!" - ), - color=Colours.soft_green - ) - await ctx.send(embed=cog_description) + if ctx.invoked_subcommand is None: + cog_description = Embed( + title="What is .trivianight?", + description=( + "This 'cog' is for the Python Discord's TriviaNight (date tentative)! Compete against other" + "players in a trivia about Python!" + ), + color=Colours.soft_green + ) + await ctx.send(embed=cog_description) @trivianight.command() async def load(self, ctx: commands.Context) -> None: @@ -79,9 +81,16 @@ class TriviaNight(commands.Cog): await ctx.send(embed=next_question) return - question_embed, question_view = self.questions.current_question() + (question_embed, time_limit), question_view = self.questions.current_question() await ctx.send(embed=question_embed, view=question_view) + for time_remaining in range(time_limit - 1, -1, -1): + await asyncio.sleep(1) + if time_remaining % 5 == 0: + await ctx.send(f"{time_remaining}s remaining") + + await ctx.send(embed=self.questions.end_question()) + @trivianight.command() async def question(self, ctx: commands.Context, question_number: int) -> None: """Gets a question from the question bank depending on the question number provided.""" @@ -90,9 +99,16 @@ class TriviaNight(commands.Cog): await ctx.send(embed=question) return - question_embed, question_view = self.questions.current_question() + (question_embed, time_limit), question_view = self.questions.current_question() await ctx.send(embed=question_embed, view=question_view) + for time_remaining in range(time_limit - 1, -1, -1): + await asyncio.sleep(1) + if time_remaining % 5 == 0: + await ctx.send(f"{time_remaining}s remaining") + + await ctx.send(embed=self.questions.end_question()) + @trivianight.command() async def list(self, ctx: commands.Context) -> None: """Displays all the questions from the question bank.""" |