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/events | |
| parent | add trivianight structure in the main cog (diff) | |
added functionality
trivianight next, trivianight stop, trivianight end added
Diffstat (limited to 'bot/exts/events')
| -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.""" | 
