diff options
author | 2021-10-20 20:44:42 -0400 | |
---|---|---|
committer | 2022-02-09 18:13:36 -0500 | |
commit | 00b2f33e3366f885ad7d24bade546f604e065710 (patch) | |
tree | 3522743ad27da52117fc388d9a363301faa59d34 /bot/exts | |
parent | add trivianight structure in the main cog (diff) |
added functionality
trivianight next, trivianight stop, trivianight end added
Diffstat (limited to 'bot/exts')
-rw-r--r-- | bot/exts/events/trivianight/_questions.py | 74 | ||||
-rw-r--r-- | bot/exts/events/trivianight/_scoreboard.py | 30 | ||||
-rw-r--r-- | bot/exts/events/trivianight/trivianight.py | 32 |
3 files changed, 89 insertions, 47 deletions
diff --git a/bot/exts/events/trivianight/_questions.py b/bot/exts/events/trivianight/_questions.py index ef56ee81..f558c50e 100644 --- a/bot/exts/events/trivianight/_questions.py +++ b/bot/exts/events/trivianight/_questions.py @@ -1,7 +1,9 @@ -from random import choice +from random import choice, randrange from time import perf_counter +from typing import Union -from discord import ButtonStyle, Embed, Interaction +import discord +from discord import Embed, Interaction from discord.ui import Button, View from bot.constants import Colours, NEGATIVE_REPLIES @@ -11,22 +13,21 @@ from ._scoreboard import Scoreboard class QuestionButton(Button): """Button subclass for the options of the questions.""" - def __init__(self, label: str): - self._time = perf_counter() - self.users_picked = {} - super().__init__(label=label, style=ButtonStyle.green) + def __init__(self, label: str, users_picked: dict): + self.users_picked = users_picked + super().__init__(label=label, style=discord.ButtonStyle.green) - def answer(self, label: str) -> dict: - """Returns the dictionary of the users who picked the answer only if it was correct.""" - return self.users_picked if label == self.label else {} + def set_time(self) -> None: + """Sets an instance attribute to a perf counter simulating the question beginning.""" + self._time = perf_counter() async def callback(self, interaction: Interaction) -> None: """When a user interacts with the button, this will be called.""" if interaction.user.id not in self.users_picked.keys(): self.users_picked[interaction.user.id] = [self.label, 1, perf_counter() - self._time] - elif self.users_picked[interaction.user.id][1] < 3: + elif self.users_picked[interaction.user.id][1] < 2: self.users_picked[interaction.user.id] = [ - self.label, self.users_picked[interaction.user.id][0] + 1, perf_counter() - self._time + self.label, self.users_picked[interaction.user.id][1] + 1, perf_counter() - self._time ] else: await interaction.response.send_message( @@ -43,7 +44,12 @@ class QuestionView(View): """View for the questions.""" def __init__(self): + super().__init__() self.current_question = {} + self.users_picked = {} + self.buttons = [QuestionButton(label, self.users_picked) for label in ("A", "B", "C", "D")] + for button in self.buttons: + self.add_item(button) def create_current_question(self) -> Embed: """Helper function to create the embed for the current question.""" @@ -53,30 +59,27 @@ class QuestionView(View): color=Colours.python_yellow ) for label, answer in zip(("A", "B", "C", "D"), self.current_question["answers"]): - question_embed.add_field(name=label, value=answer, inline=False) + question_embed.add_field(name=f"Choice {label}", value=answer, inline=False) - self.buttons = [QuestionButton(label) for label in ("A", "B", "C", "D")] for button in self.buttons: - self.add_item(button) + button.set_time() + return question_embed 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["correct"].index(self.current_question["answers"])] - return_dict = {} + 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} + self.users_picked = {} + for button in self.buttons: - return_dict.update(button.answer(label)) - self.remove_item(button) + button.users_picked = self.users_picked answer_embed = Embed( title=f"The correct answer for Question {self.current_question['number']} was", - color=Colours.grass_green - ) - answer_embed.add_field( - name=label, - value=self.current_question["correct"].index(self.current_question["answers"]), - inline=False + description=self.current_question["correct"], + color=Colours.soft_green ) return return_dict, answer_embed @@ -87,7 +90,6 @@ class Questions: def __init__(self, scoreboard: Scoreboard): self.scoreboard = scoreboard - self.view = QuestionView() self.questions = [] self._ptr = -1 @@ -95,18 +97,26 @@ class Questions: """Setting `self.questions` dynamically via a function to set it.""" self.questions = questions - def next_question(self) -> None: - """Advances to the next question.""" - self._ptr += 1 - if self._ptr < len(self.questions): - self.questions[self._ptr]["visited"] = True - self.view.current_question = self.questions[self._ptr] + def next_question(self) -> Union[Embed, None]: + """Uses another, new question.""" + if all("visited" in question.keys() for question in self.questions.values()): + return Embed( + title=choice(NEGATIVE_REPLIES), + description="All of the questions in the question bank have been used.", + color=Colours.soft_red + ) + + while "visited" in self.questions[self._ptr].keys(): + self._ptr = randrange(0, len(self.questions)) + + self.questions[self._ptr]["visited"] = True + self.view.current_question = self.questions[self._ptr] def current_question(self) -> tuple[Embed, QuestionView]: """Returns an embed entailing the current question as an embed with a view.""" return self.view.create_current_question(), self.view - def end_question(self) -> None: + def end_question(self) -> Embed: """Terminates answering of the question and displays the correct answer.""" scores, answer_embed = self.view.end_question() for user, score in scores.items(): diff --git a/bot/exts/events/trivianight/_scoreboard.py b/bot/exts/events/trivianight/_scoreboard.py index 96ff5ced..cab0288f 100644 --- a/bot/exts/events/trivianight/_scoreboard.py +++ b/bot/exts/events/trivianight/_scoreboard.py @@ -12,32 +12,41 @@ class ScoreboardView(View): """View for the scoreboard.""" def __init__(self, bot: Bot): + super().__init__() self.bot = bot self.points = {} self.speed = {} - def create_main_leaderboard(self) -> Embed: + async def create_main_leaderboard(self) -> Embed: """Helper function that iterates through `self.points` to generate the main leaderboard embed.""" main_embed = Embed( title="Winners of the Trivia Night", description="See the leaderboard for who got the most points during the Trivia Night!", color=Colours.python_blue, ) - for user, points in list(self.points.items())[:10]: - main_embed.add_field(name=self.bot.get_user(user), value=f"`{points}` pts", inline=False) + + # Limit self.points.items() to 10 items at maximum (top 10 users) in the future + for user, points in list(self.points.items()): + user = await self.bot.fetch_user(int(user)) + main_embed.add_field( + name=f"{user.name}#{user.discriminator}", + value=f"`{points}` pts", + inline=False + ) return main_embed - def _create_speed_embed(self) -> Embed: + async def _create_speed_embed(self) -> Embed: """Helper function that iterates through `self.speed` to generate a leaderboard embed.""" speed_embed = Embed( title="Average Time Taken to Answer a Question", description="See the leaderboard for how fast each user took to answer a question correctly!", color=Colours.python_blue, ) - for user, time_taken in list(self.speed.items())[:10]: + for user, time_taken in list(self.speed.items()): + user = await self.bot.fetch_user(int(user)) speed_embed.add_field( - name=self.bot.get_user(user), + name=f"{user.name}#{user.discriminator}", value=f"`{(time_taken[1] / time_taken[0]):.3f}s` (on average)", inline=False ) @@ -47,15 +56,12 @@ class ScoreboardView(View): @discord.ui.button(label="Scoreboard for Speed", style=ButtonStyle.green) async def speed_leaderboard(self, button: Button, interaction: Interaction) -> None: """Send an ephemeral message with the speed leaderboard embed.""" - await interaction.response.send_message(embed=self._create_speed_embed(), ephemeral=True) + await interaction.response.send_message(embed=await self._create_speed_embed(), ephemeral=True) class Scoreboard: """Class for the scoreboard for the trivianight event.""" - def __init__(self, bot: Bot): - self.view = ScoreboardView(bot) - def __setitem__(self, key: str, value: int): if key.startswith("points: "): key = key.removeprefix("points: ") @@ -76,6 +82,6 @@ class Scoreboard: elif item.startswith("speed: "): return self.view.speed[item.removeprefix("speed: ")] - def display(self) -> Union[Embed, View]: + async def display(self) -> Union[Embed, View]: """Returns the embed of the main leaderboard along with the ScoreboardView.""" - return self.view.create_main_leaderboard(), self.view + return await self.view.create_main_leaderboard(), self.view diff --git a/bot/exts/events/trivianight/trivianight.py b/bot/exts/events/trivianight/trivianight.py index 66b2ae43..609f6651 100644 --- a/bot/exts/events/trivianight/trivianight.py +++ b/bot/exts/events/trivianight/trivianight.py @@ -1,3 +1,4 @@ +import logging from json import loads from random import choice @@ -6,8 +7,8 @@ from discord.ext import commands from bot.bot import Bot from bot.constants import Colours, POSITIVE_REPLIES -from ._questions import Questions -from ._scoreboard import Scoreboard +from ._questions import QuestionView, Questions +from ._scoreboard import Scoreboard, ScoreboardView class TriviaNight(commands.Cog): @@ -15,7 +16,7 @@ class TriviaNight(commands.Cog): def __init__(self, bot: Bot): self.bot = bot - self.scoreboard = Scoreboard(self.bot) + self.scoreboard = Scoreboard() self.questions = Questions(self.scoreboard) @commands.group() @@ -28,6 +29,9 @@ class TriviaNight(commands.Cog): """Load the JSON file provided into the questions.""" json_text = (await ctx.message.attachments[0].read()).decode("utf8") serialized_json = loads(json_text) + self.questions.view = QuestionView() + logging.getLogger(__name__).debug(self.questions.view) + self.scoreboard.view = ScoreboardView(self.bot) self.questions.set_questions(serialized_json) success_embed = Embed( title=choice(POSITIVE_REPLIES), @@ -36,6 +40,28 @@ class TriviaNight(commands.Cog): ) await ctx.send(embed=success_embed) + @trivianight.command() + async def next(self, ctx: commands.Context) -> None: + """Gets a random question from the unanswered question list and lets user choose the answer.""" + next_question = self.questions.next_question() + if isinstance(next_question, Embed): + await ctx.send(embed=next_question) + return + + question_embed, question_view = self.questions.current_question() + await ctx.send(embed=question_embed, view=question_view) + + @trivianight.command() + async def stop(self, ctx: commands.Context) -> None: + """End the ongoing question to show the correct question.""" + await ctx.send(embed=self.questions.end_question()) + + @trivianight.command() + async def end(self, ctx: commands.Context) -> None: + """Ends the trivia night event and displays the scoreboard.""" + scoreboard_embed, scoreboard_view = await self.scoreboard.display() + await ctx.send(embed=scoreboard_embed, view=scoreboard_view) + def setup(bot: Bot) -> None: """Load the TriviaNight cog.""" |