aboutsummaryrefslogtreecommitdiffstats
path: root/bot/exts/events/trivianight/_questions.py
blob: ef56ee81f9ec4c5bc6f4731637eac71e7b1f0320 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
from random import choice
from time import perf_counter

from discord import ButtonStyle, Embed, Interaction
from discord.ui import Button, View

from bot.constants import Colours, NEGATIVE_REPLIES
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 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 {}

    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:
            self.users_picked[interaction.user.id] = [
                self.label, self.users_picked[interaction.user.id][0] + 1, perf_counter() - self._time
            ]
        else:
            await interaction.response.send_message(
                embed=Embed(
                    title=choice(NEGATIVE_REPLIES),
                    description="You've already changed your answer more than once!",
                    color=Colours.soft_red
                ),
                ephemeral=True
            )


class QuestionView(View):
    """View for the questions."""

    def __init__(self):
        self.current_question = {}

    def create_current_question(self) -> Embed:
        """Helper function to create the embed for the current question."""
        question_embed = Embed(
            title=f"Question {self.current_question['number']}",
            description=self.current_question["description"],
            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)

        self.buttons = [QuestionButton(label) for label in ("A", "B", "C", "D")]
        for button in self.buttons:
            self.add_item(button)
        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 = {}
        for button in self.buttons:
            return_dict.update(button.answer(label))
            self.remove_item(button)

        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
        )

        return return_dict, answer_embed


class Questions:
    """An interface to use from the TriviaNight cog for questions."""

    def __init__(self, scoreboard: Scoreboard):
        self.scoreboard = scoreboard
        self.view = QuestionView()
        self.questions = []
        self._ptr = -1

    def set_questions(self, questions: list) -> None:
        """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 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:
        """Terminates answering of the question and displays the correct answer."""
        scores, answer_embed = self.view.end_question()
        for user, score in scores.items():
            self.scoreboard[f"points: {user}"] = score[1]
            self.scoreboard[f"speed: {user}"] = score[2]

        return answer_embed