aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGravatar Shom770 <[email protected]>2021-11-04 13:17:50 -0400
committerGravatar Shom770 <[email protected]>2022-02-09 18:13:37 -0500
commit1848d0ddd318ff3eee0c9c9efed9fef89f460b21 (patch)
tree44a43ed600d0d05e007e3466df7e44bad494bdc8
parentcog 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.py59
-rw-r--r--bot/exts/events/trivianight/_scoreboard.py2
-rw-r--r--bot/exts/events/trivianight/trivianight.py40
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."""