diff options
| author | 2021-12-12 18:00:15 +0100 | |
|---|---|---|
| committer | 2022-02-09 18:13:37 -0500 | |
| commit | 2a7d6942646f9cd0c71d3f1e5812dd1e49043be8 (patch) | |
| tree | 7b11f9aa3c188ba9c1f94b285b30fec624a929e7 /bot/exts/events/trivianight/_game.py | |
| parent | typo in trivianight cog explanation (diff) | |
Add Question representation for trivia night data
Diffstat (limited to 'bot/exts/events/trivianight/_game.py')
| -rw-r--r-- | bot/exts/events/trivianight/_game.py | 105 | 
1 files changed, 105 insertions, 0 deletions
| diff --git a/bot/exts/events/trivianight/_game.py b/bot/exts/events/trivianight/_game.py new file mode 100644 index 00000000..086d0de6 --- /dev/null +++ b/bot/exts/events/trivianight/_game.py @@ -0,0 +1,105 @@ +import time +from string import ascii_uppercase +from typing import Iterable, Optional, TypedDict + + +DEFAULT_QUESTION_POINTS = 10 +DEFAULT_QUESTION_TIME = 10 + + +class QuestionData(TypedDict): +    """Representing the different 'keys' of the question taken from the JSON.""" + +    number: str +    description: str +    answers: list[str] +    correct: str +    points: Optional[int] +    time: Optional[int] + + +UserGuess = tuple[ +    str,  # The answer that was guessed +    bool,  # Whether the answer can be changed again +    float  # The time it took to guess +] + + +class Question: +    """Interface for one question in a trivia night game.""" + +    def __init__(self, data: QuestionData): +        self._data = data +        self._guesses: dict[int, UserGuess] = {} +        self._started = None + +    # These properties are mostly proxies to the underlying data: + +    @property +    def number(self) -> str: +        """The number of the question.""" +        return self._data["number"] + +    @property +    def description(self) -> str: +        """The description of the question.""" +        return self._data["description"] + +    @property +    def answers(self) -> list[tuple[str, str]]: +        """The possible answers for this answer. + +        This is a property that returns a list of letter, answer pairs. +        """ +        return [(ascii_uppercase[i], q) for (i, q) in enumerate(self._data["answers"])] + +    @property +    def correct(self) -> str: +        """The correct answer for this question.""" +        return self._data["correct"] + +    @property +    def max_points(self) -> int: +        """The maximum points that can be awarded for this question.""" +        return self._data.get("points") or DEFAULT_QUESTION_POINTS + +    @property +    def time(self) -> float: +        """The time allowed to answer the question.""" +        return self._data.get("time") or DEFAULT_QUESTION_TIME + +    def start(self) -> float: +        """Start the question and return the time it started.""" +        self._started = time.perf_counter() +        return self._started + +    def _update_guess(self, user: int, answer: str) -> UserGuess: +        """Update an already existing guess.""" +        if self._started is None: +            raise RuntimeError("Question is not open for answers.") + +        if self._guesses[user][1] is False: +            raise RuntimeError(f"User({user}) has already updated their guess once.") + +        self._guesses[user] = (answer, False, time.perf_counter() - self._started) +        return self._guesses[user] + +    def guess(self, user: int, answer: str) -> UserGuess: +        """Add a guess made by a user to the current question.""" +        if user in self._guesses: +            return self._update_guess(user, answer) + +        if self._started is None: +            raise RuntimeError("Question is not open for answers.") + +        self._guesses[user] = (answer, True, time.perf_counter() - self._started) +        return self._guesses[user] + +    def stop(self) -> dict[int, UserGuess]: +        """Stop the question and return the guesses that were made.""" +        guesses = self._guesses + +        self._started = None +        self._guesses = {} + +        return guesses | 
