aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--bot/exts/fun/trivia_quiz.py422
-rw-r--r--bot/resources/fun/trivia_quiz.json94
2 files changed, 299 insertions, 217 deletions
diff --git a/bot/exts/fun/trivia_quiz.py b/bot/exts/fun/trivia_quiz.py
index cf9e6cd3..236586b0 100644
--- a/bot/exts/fun/trivia_quiz.py
+++ b/bot/exts/fun/trivia_quiz.py
@@ -3,12 +3,16 @@ import json
import logging
import operator
import random
+import re
+import string
+from collections import defaultdict
from dataclasses import dataclass
+from datetime import datetime, timedelta
from pathlib import Path
from typing import Callable, Optional
import discord
-from discord.ext import commands
+from discord.ext import commands, tasks
from rapidfuzz import fuzz
from bot.bot import Bot
@@ -16,177 +20,194 @@ from bot.constants import Colours, NEGATIVE_REPLIES, Roles
logger = logging.getLogger(__name__)
-DEFAULT_QUESTION_LIMIT = 6
+DEFAULT_QUESTION_LIMIT = 7
STANDARD_VARIATION_TOLERANCE = 88
DYNAMICALLY_GEN_VARIATION_TOLERANCE = 97
+MAX_ERROR_FETCH_TRIES = 3
+
WRONG_ANS_RESPONSE = [
"No one answered correctly!",
"Better luck next time...",
]
-N_PREFIX_STARTS_AT = 5
-N_PREFIXES = [
- "penta", "hexa", "hepta", "octa", "nona",
- "deca", "hendeca", "dodeca", "trideca", "tetradeca",
-]
+RULES = (
+ "No cheating and have fun!",
+ "Points for each question reduces by 25 after 10s or after a hint. Total time is 30s per question"
+)
-PLANETS = [
- ("1st", "Mercury"),
- ("2nd", "Venus"),
- ("3rd", "Earth"),
- ("4th", "Mars"),
- ("5th", "Jupiter"),
- ("6th", "Saturn"),
- ("7th", "Uranus"),
- ("8th", "Neptune"),
-]
-
-TAXONOMIC_HIERARCHY = [
- "species", "genus", "family", "order",
- "class", "phylum", "kingdom", "domain",
-]
-
-UNITS_TO_BASE_UNITS = {
- "hertz": ("(unit of frequency)", "s^-1"),
- "newton": ("(unit of force)", "m*kg*s^-2"),
- "pascal": ("(unit of pressure & stress)", "m^-1*kg*s^-2"),
- "joule": ("(unit of energy & quantity of heat)", "m^2*kg*s^-2"),
- "watt": ("(unit of power)", "m^2*kg*s^-3"),
- "coulomb": ("(unit of electric charge & quantity of electricity)", "s*A"),
- "volt": ("(unit of voltage & electromotive force)", "m^2*kg*s^-3*A^-1"),
- "farad": ("(unit of capacitance)", "m^-2*kg^-1*s^4*A^2"),
- "ohm": ("(unit of electric resistance)", "m^2*kg*s^-3*A^-2"),
- "weber": ("(unit of magnetic flux)", "m^2*kg*s^-2*A^-1"),
- "tesla": ("(unit of magnetic flux density)", "kg*s^-2*A^-1"),
-}
+WIKI_FEED_API_URL = "https://en.wikipedia.org/api/rest_v1/feed/featured/{date}"
+TRIVIA_QUIZ_ICON = (
+ "https://raw.githubusercontent.com/python-discord/branding/main/icons/trivia_quiz/trivia-quiz-dist.png"
+)
@dataclass(frozen=True)
class QuizEntry:
- """Dataclass for a quiz entry (a question and a string containing answers separated by commas)."""
+ """Stores quiz entry (a question and a list of answers)."""
question: str
- answer: str
-
-
-def linear_system(q_format: str, a_format: str) -> QuizEntry:
- """Generate a system of linear equations with two unknowns."""
- x, y = random.randint(2, 5), random.randint(2, 5)
- answer = a_format.format(x, y)
-
- coeffs = random.sample(range(1, 6), 4)
-
- question = q_format.format(
- coeffs[0],
- coeffs[1],
- coeffs[0] * x + coeffs[1] * y,
- coeffs[2],
- coeffs[3],
- coeffs[2] * x + coeffs[3] * y,
- )
-
- return QuizEntry(question, answer)
-
-
-def mod_arith(q_format: str, a_format: str) -> QuizEntry:
- """Generate a basic modular arithmetic question."""
- quotient, m, b = random.randint(30, 40), random.randint(10, 20), random.randint(200, 350)
- ans = random.randint(0, 9) # max remainder is 9, since the minimum modulus is 10
- a = quotient * m + ans - b
-
- question = q_format.format(a, b, m)
- answer = a_format.format(ans)
+ answers: list[str]
+ var_tol: int
+
+
+class DynamicQuestionGen:
+ """Class that contains functions to generate math/science questions for TriviaQuiz Cog."""
+
+ N_PREFIX_STARTS_AT = 5
+ N_PREFIXES = [
+ "penta", "hexa", "hepta", "octa", "nona",
+ "deca", "hendeca", "dodeca", "trideca", "tetradeca",
+ ]
+
+ PLANETS = [
+ ("1st", "Mercury"),
+ ("2nd", "Venus"),
+ ("3rd", "Earth"),
+ ("4th", "Mars"),
+ ("5th", "Jupiter"),
+ ("6th", "Saturn"),
+ ("7th", "Uranus"),
+ ("8th", "Neptune"),
+ ]
+
+ TAXONOMIC_HIERARCHY = [
+ "species", "genus", "family", "order",
+ "class", "phylum", "kingdom", "domain",
+ ]
+
+ UNITS_TO_BASE_UNITS = {
+ "hertz": ("(unit of frequency)", "s^-1"),
+ "newton": ("(unit of force)", "m*kg*s^-2"),
+ "pascal": ("(unit of pressure & stress)", "m^-1*kg*s^-2"),
+ "joule": ("(unit of energy & quantity of heat)", "m^2*kg*s^-2"),
+ "watt": ("(unit of power)", "m^2*kg*s^-3"),
+ "coulomb": ("(unit of electric charge & quantity of electricity)", "s*A"),
+ "volt": ("(unit of voltage & electromotive force)", "m^2*kg*s^-3*A^-1"),
+ "farad": ("(unit of capacitance)", "m^-2*kg^-1*s^4*A^2"),
+ "ohm": ("(unit of electric resistance)", "m^2*kg*s^-3*A^-2"),
+ "weber": ("(unit of magnetic flux)", "m^2*kg*s^-2*A^-1"),
+ "tesla": ("(unit of magnetic flux density)", "kg*s^-2*A^-1"),
+ }
+
+ @classmethod
+ def linear_system(cls, q_format: str, a_format: str) -> QuizEntry:
+ """Generate a system of linear equations with two unknowns."""
+ x, y = random.randint(2, 5), random.randint(2, 5)
+ answer = a_format.format(x, y)
+
+ coeffs = random.sample(range(1, 6), 4)
+
+ question = q_format.format(
+ coeffs[0],
+ coeffs[1],
+ coeffs[0] * x + coeffs[1] * y,
+ coeffs[2],
+ coeffs[3],
+ coeffs[2] * x + coeffs[3] * y,
+ )
- return QuizEntry(question, answer)
+ return QuizEntry(question, [answer], DYNAMICALLY_GEN_VARIATION_TOLERANCE)
+ @classmethod
+ def mod_arith(cls, q_format: str, a_format: str) -> QuizEntry:
+ """Generate a basic modular arithmetic question."""
+ quotient, m, b = random.randint(30, 40), random.randint(10, 20), random.randint(200, 350)
+ ans = random.randint(0, 9) # max remainder is 9, since the minimum modulus is 10
+ a = quotient * m + ans - b
-def ngonal_prism(q_format: str, a_format: str) -> QuizEntry:
- """Generate a question regarding vertices on n-gonal prisms."""
- n = random.randint(0, len(N_PREFIXES) - 1)
+ question = q_format.format(a, b, m)
+ answer = a_format.format(ans)
- question = q_format.format(N_PREFIXES[n])
- answer = a_format.format((n + N_PREFIX_STARTS_AT) * 2)
+ return QuizEntry(question, [answer], DYNAMICALLY_GEN_VARIATION_TOLERANCE)
- return QuizEntry(question, answer)
+ @classmethod
+ def ngonal_prism(cls, q_format: str, a_format: str) -> QuizEntry:
+ """Generate a question regarding vertices on n-gonal prisms."""
+ n = random.randint(0, len(cls.N_PREFIXES) - 1)
+ question = q_format.format(cls.N_PREFIXES[n])
+ answer = a_format.format((n + cls.N_PREFIX_STARTS_AT) * 2)
-def imag_sqrt(q_format: str, a_format: str) -> QuizEntry:
- """Generate a negative square root question."""
- ans_coeff = random.randint(3, 10)
+ return QuizEntry(question, [answer], DYNAMICALLY_GEN_VARIATION_TOLERANCE)
- question = q_format.format(ans_coeff ** 2)
- answer = a_format.format(ans_coeff)
+ @classmethod
+ def imag_sqrt(cls, q_format: str, a_format: str) -> QuizEntry:
+ """Generate a negative square root question."""
+ ans_coeff = random.randint(3, 10)
- return QuizEntry(question, answer)
+ question = q_format.format(ans_coeff ** 2)
+ answer = a_format.format(ans_coeff)
+ return QuizEntry(question, [answer], DYNAMICALLY_GEN_VARIATION_TOLERANCE)
-def binary_calc(q_format: str, a_format: str) -> QuizEntry:
- """Generate a binary calculation question."""
- a = random.randint(15, 20)
- b = random.randint(10, a)
- oper = random.choice(
- (
- ("+", operator.add),
- ("-", operator.sub),
- ("*", operator.mul),
+ @classmethod
+ def binary_calc(cls, q_format: str, a_format: str) -> QuizEntry:
+ """Generate a binary calculation question."""
+ a = random.randint(15, 20)
+ b = random.randint(10, a)
+ oper = random.choice(
+ (
+ ("+", operator.add),
+ ("-", operator.sub),
+ ("*", operator.mul),
+ )
)
- )
- # if the operator is multiplication, lower the values of the two operands to make it easier
- if oper[0] == "*":
- a -= 5
- b -= 5
+ # if the operator is multiplication, lower the values of the two operands to make it easier
+ if oper[0] == "*":
+ a -= 5
+ b -= 5
- question = q_format.format(a, oper[0], b)
- answer = a_format.format(oper[1](a, b))
+ question = q_format.format(a, oper[0], b)
+ answer = a_format.format(oper[1](a, b))
- return QuizEntry(question, answer)
+ return QuizEntry(question, [answer], DYNAMICALLY_GEN_VARIATION_TOLERANCE)
+ @classmethod
+ def solar_system(cls, q_format: str, a_format: str) -> QuizEntry:
+ """Generate a question on the planets of the Solar System."""
+ planet = random.choice(cls.PLANETS)
-def solar_system(q_format: str, a_format: str) -> QuizEntry:
- """Generate a question on the planets of the Solar System."""
- planet = random.choice(PLANETS)
+ question = q_format.format(planet[0])
+ answer = a_format.format(planet[1])
- question = q_format.format(planet[0])
- answer = a_format.format(planet[1])
+ return QuizEntry(question, [answer], DYNAMICALLY_GEN_VARIATION_TOLERANCE)
- return QuizEntry(question, answer)
+ @classmethod
+ def taxonomic_rank(cls, q_format: str, a_format: str) -> QuizEntry:
+ """Generate a question on taxonomic classification."""
+ level = random.randint(0, len(cls.TAXONOMIC_HIERARCHY) - 2)
+ question = q_format.format(cls.TAXONOMIC_HIERARCHY[level])
+ answer = a_format.format(cls.TAXONOMIC_HIERARCHY[level + 1])
-def taxonomic_rank(q_format: str, a_format: str) -> QuizEntry:
- """Generate a question on taxonomic classification."""
- level = random.randint(0, len(TAXONOMIC_HIERARCHY) - 2)
+ return QuizEntry(question, [answer], DYNAMICALLY_GEN_VARIATION_TOLERANCE)
- question = q_format.format(TAXONOMIC_HIERARCHY[level])
- answer = a_format.format(TAXONOMIC_HIERARCHY[level + 1])
+ @classmethod
+ def base_units_convert(cls, q_format: str, a_format: str) -> QuizEntry:
+ """Generate a SI base units conversion question."""
+ unit = random.choice(list(cls.UNITS_TO_BASE_UNITS))
- return QuizEntry(question, answer)
-
-
-def base_units_convert(q_format: str, a_format: str) -> QuizEntry:
- """Generate a SI base units conversion question."""
- unit = random.choice(list(UNITS_TO_BASE_UNITS))
-
- question = q_format.format(
- unit + " " + UNITS_TO_BASE_UNITS[unit][0]
- )
- answer = a_format.format(
- UNITS_TO_BASE_UNITS[unit][1]
- )
+ question = q_format.format(
+ unit + " " + cls.UNITS_TO_BASE_UNITS[unit][0]
+ )
+ answer = a_format.format(
+ cls.UNITS_TO_BASE_UNITS[unit][1]
+ )
- return QuizEntry(question, answer)
+ return QuizEntry(question, [answer], DYNAMICALLY_GEN_VARIATION_TOLERANCE)
DYNAMIC_QUESTIONS_FORMAT_FUNCS = {
- 201: linear_system,
- 202: mod_arith,
- 203: ngonal_prism,
- 204: imag_sqrt,
- 205: binary_calc,
- 301: solar_system,
- 302: taxonomic_rank,
- 303: base_units_convert,
+ 201: DynamicQuestionGen.linear_system,
+ 202: DynamicQuestionGen.mod_arith,
+ 203: DynamicQuestionGen.ngonal_prism,
+ 204: DynamicQuestionGen.imag_sqrt,
+ 205: DynamicQuestionGen.binary_calc,
+ 301: DynamicQuestionGen.solar_system,
+ 302: DynamicQuestionGen.taxonomic_rank,
+ 303: DynamicQuestionGen.base_units_convert,
}
@@ -202,7 +223,7 @@ class TriviaQuiz(commands.Cog):
self.questions = self.load_questions()
self.question_limit = 0
- self.player_scores = {} # A variable to store all player's scores for a bot session.
+ self.player_scores = defaultdict(int) # A variable to store all player's scores for a bot session.
self.game_player_scores = {} # A variable to store temporary game player's scores.
self.categories = {
@@ -212,8 +233,72 @@ class TriviaQuiz(commands.Cog):
"science": "Put your understanding of science to the test!",
"cs": "A large variety of computer science questions.",
"python": "Trivia on our amazing language, Python!",
+ "wikipedia": "Guess the title of random wikipedia passages.",
}
+ self.get_wiki_questions.start()
+
+ def cog_unload(self) -> None:
+ """Cancel `get_wiki_questions` task when Cog will unload."""
+ self.get_wiki_questions.cancel()
+
+ @tasks.loop(hours=24.0)
+ async def get_wiki_questions(self) -> None:
+ """Get yesterday's most read articles from wikipedia and format them like trivia questions."""
+ error_fetches = 0
+ wiki_questions = []
+ # trivia_quiz.json follows a pattern, every new category starts with the next century.
+ start_id = 501
+ yesterday = datetime.strftime(datetime.now() - timedelta(1), '%Y/%m/%d')
+
+ while error_fetches < MAX_ERROR_FETCH_TRIES:
+ async with self.bot.http_session.get(url=WIKI_FEED_API_URL.format(date=yesterday)) as r:
+ if r.status != 200:
+ error_fetches += 1
+ continue
+ raw_json = await r.json()
+ articles_raw = raw_json["mostread"]["articles"]
+
+ for article in articles_raw:
+ question = article.get("extract")
+ if not question:
+ continue
+
+ # Normalize the wikipedia article title to remove all punctuations from it
+ for word in re.split(r"[\s-]", title := article["normalizedtitle"]):
+ cleaned_title = re.sub(
+ rf'\b{word.strip(string.punctuation)}\b', word, title, flags=re.IGNORECASE
+ )
+
+ # Since the extract contains the article name sometimes this would replace all the matching words
+ # in that article with *** of that length.
+ # NOTE: This removes the "answer" for 99% of the cases, but sometimes the wikipedia article is
+ # very different from the words in the extract, for example the title would be the nickname of a
+ # person (Bob Ross) whereas in the extract it would the full name (Robert Norman Ross) so it comes
+ # out as (Robert Norman ****) and (Robert Norman Ross) won't be a right answer :(
+ for word in re.split(r"[\s-]", cleaned_title):
+ word = word.strip(string.punctuation)
+ secret_word = r"\*" * len(word)
+ question = re.sub(rf'\b{word}\b', f"**{secret_word}**", question, flags=re.IGNORECASE)
+
+ formatted_article_question = {
+ "id": start_id,
+ "question": f"Guess the title of the Wikipedia article.\n\n{question}",
+ "answer": cleaned_title,
+ "info": article["extract"]
+ }
+ start_id += 1
+ wiki_questions.append(formatted_article_question)
+
+ # If everything has gone smoothly until now, we can break out of the while loop
+ break
+
+ if error_fetches < MAX_ERROR_FETCH_TRIES:
+ self.questions["wikipedia"] = wiki_questions.copy()
+ else:
+ del self.categories["wikipedia"]
+ logger.warning(f"Not loading wikipedia guess questions, hit max error fetches: {MAX_ERROR_FETCH_TRIES}.")
+
@staticmethod
def load_questions() -> dict:
"""Load the questions from the JSON file."""
@@ -221,7 +306,7 @@ class TriviaQuiz(commands.Cog):
return json.loads(p.read_text(encoding="utf-8"))
- @commands.group(name="quiz", aliases=["trivia"], invoke_without_command=True)
+ @commands.group(name="quiz", aliases=("trivia", "triviaquiz"), invoke_without_command=True)
async def quiz_game(self, ctx: commands.Context, category: Optional[str], questions: Optional[int]) -> None:
"""
Start a quiz!
@@ -233,6 +318,7 @@ class TriviaQuiz(commands.Cog):
- science: Put your understanding of science to the test!
- cs: A large variety of computer science questions.
- python: Trivia on our amazing language, Python!
+ - wikipedia: Guess the title of random wikipedia passages.
(More to come!)
"""
@@ -264,7 +350,7 @@ class TriviaQuiz(commands.Cog):
topic_length = len(topic)
if questions is None:
- self.question_limit = DEFAULT_QUESTION_LIMIT
+ self.question_limit = min(DEFAULT_QUESTION_LIMIT, topic_length)
else:
if questions > topic_length:
await ctx.send(
@@ -279,13 +365,13 @@ class TriviaQuiz(commands.Cog):
await ctx.send(
embed=self.make_error_embed(
"You must choose to complete at least one question. "
- f"(or enter nothing for the default value of {DEFAULT_QUESTION_LIMIT + 1} questions)"
+ f"(or enter nothing for the default value of {DEFAULT_QUESTION_LIMIT} questions)"
)
)
return
else:
- self.question_limit = questions - 1
+ self.question_limit = questions
# Start game if not running.
if not self.game_status[ctx.channel.id]:
@@ -296,13 +382,13 @@ class TriviaQuiz(commands.Cog):
await ctx.send(embed=start_embed) # send an embed with the rules
await asyncio.sleep(5)
- done_question = []
+ done_questions = []
hint_no = 0
- answers = None
+ quiz_entry = None
while self.game_status[ctx.channel.id]:
# Exit quiz if number of questions for a round are already sent.
- if len(done_question) > self.question_limit and hint_no == 0:
+ if len(done_questions) == self.question_limit and hint_no == 0:
await ctx.send("The round has ended.")
await self.declare_winner(ctx.channel, self.game_player_scores[ctx.channel.id])
@@ -317,32 +403,27 @@ class TriviaQuiz(commands.Cog):
# Select a random question which has not been used yet.
while True:
question_dict = random.choice(topic)
- if question_dict["id"] not in done_question:
- done_question.append(question_dict["id"])
+ if question_dict["id"] not in done_questions:
+ done_questions.append(question_dict["id"])
break
if "dynamic_id" not in question_dict:
- question = question_dict["question"]
- answers = question_dict["answer"].split(", ")
-
- var_tol = STANDARD_VARIATION_TOLERANCE
+ quiz_entry = QuizEntry(
+ question_dict["question"],
+ quiz_answers if isinstance(quiz_answers := question_dict["answer"], list) else [quiz_answers],
+ STANDARD_VARIATION_TOLERANCE
+ )
else:
format_func = DYNAMIC_QUESTIONS_FORMAT_FUNCS[question_dict["dynamic_id"]]
-
quiz_entry = format_func(
question_dict["question"],
question_dict["answer"],
)
- question, answers = quiz_entry.question, quiz_entry.answer
- answers = [answers]
-
- var_tol = DYNAMICALLY_GEN_VARIATION_TOLERANCE
-
embed = discord.Embed(
colour=Colours.gold,
- title=f"Question #{len(done_question)}",
- description=question,
+ title=f"Question #{len(done_questions)}",
+ description=quiz_entry.question,
)
if img_url := question_dict.get("img_url"):
@@ -354,13 +435,13 @@ class TriviaQuiz(commands.Cog):
def contains_correct_answer(m: discord.Message) -> bool:
return m.channel == ctx.channel and any(
fuzz.ratio(answer.lower(), m.content.lower()) > variation_tolerance
- for answer in answers
+ for answer in quiz_entry.answers
)
return contains_correct_answer
try:
- msg = await self.bot.wait_for("message", check=check_func(var_tol), timeout=10)
+ msg = await self.bot.wait_for("message", check=check_func(quiz_entry.var_tol), timeout=10)
except asyncio.TimeoutError:
# In case of TimeoutError and the game has been stopped, then do nothing.
if not self.game_status[ctx.channel.id]:
@@ -388,10 +469,10 @@ class TriviaQuiz(commands.Cog):
await self.send_answer(
ctx.channel,
- answers,
+ quiz_entry.answers,
False,
question_dict,
- self.question_limit - len(done_question) + 1,
+ self.question_limit - len(done_questions),
)
await asyncio.sleep(1)
@@ -421,10 +502,10 @@ class TriviaQuiz(commands.Cog):
await self.send_answer(
ctx.channel,
- answers,
+ quiz_entry.answers,
True,
question_dict,
- self.question_limit - len(done_question) + 1,
+ self.question_limit - len(done_questions),
)
await self.send_score(ctx.channel, self.game_player_scores[ctx.channel.id])
@@ -432,19 +513,18 @@ class TriviaQuiz(commands.Cog):
def make_start_embed(self, category: str) -> discord.Embed:
"""Generate a starting/introduction embed for the quiz."""
+ rules = "\n".join([f"{index}: {rule}" for index, rule in enumerate(RULES, start=1)])
+
start_embed = discord.Embed(
- colour=Colours.blue,
- title="A quiz game is starting!",
+ title="Quiz game Starting!!",
description=(
- f"This game consists of {self.question_limit + 1} questions.\n\n"
- "**Rules: **\n"
- "1. Only enclose your answer in backticks when the question tells you to.\n"
- "2. If the question specifies an answer format, follow it or else it won't be accepted.\n"
- "3. You have 30s per question. Points for each question reduces by 25 after 10s or after a hint.\n"
- "4. No cheating and have fun!\n\n"
- f"**Category**: {category}"
+ f"Each game consists of {self.question_limit} questions.\n"
+ f"**Rules :**\n{rules}"
+ f"\n **Category** : {category}"
),
+ colour=Colours.blue
)
+ start_embed.set_thumbnail(url=TRIVIA_QUIZ_ICON)
return start_embed
@@ -503,6 +583,7 @@ class TriviaQuiz(commands.Cog):
title="Score Board",
description="",
)
+ embed.set_thumbnail(url=TRIVIA_QUIZ_ICON)
sorted_dict = sorted(player_data.items(), key=operator.itemgetter(1), reverse=True)
for item in sorted_dict:
@@ -534,8 +615,8 @@ class TriviaQuiz(commands.Cog):
winners_mention = winner.mention
await channel.send(
- f"Congratulations {winners_mention} :tada: "
- f"You have won this quiz game with a grand total of {highest_points} points!"
+ f"{winners_mention} Congratulations "
+ f"on winning this quiz game with a grand total of {highest_points} points :tada:"
)
def category_embed(self) -> discord.Embed:
@@ -578,7 +659,8 @@ class TriviaQuiz(commands.Cog):
description="",
)
- if info is not None:
+ # Don't check for info is not None, as we want to filter out empty strings.
+ if info:
embed.description += f"**Information**\n{info}\n\n"
embed.description += (
diff --git a/bot/resources/fun/trivia_quiz.json b/bot/resources/fun/trivia_quiz.json
index 8008838c..0b3e6802 100644
--- a/bot/resources/fun/trivia_quiz.json
+++ b/bot/resources/fun/trivia_quiz.json
@@ -52,7 +52,7 @@
"They generally have handdrawn nature images on them."
],
"question": "What did Nintendo make before video games and toys?",
- "answer": "Hanafuda, Hanafuda cards"
+ "answer": ["Hanafuda", "Hanafuda cards"]
},
{
"id": 7,
@@ -292,22 +292,22 @@
{
"id": 201,
"question": "What is the highest power of a biquadratic polynomial?",
- "answer": "4, four"
+ "answer": ["4", "four"]
},
{
"id": 202,
"question": "What is the formula for surface area of a sphere?",
- "answer": "4pir^2, 4πr^2"
+ "answer": ["4pir^2", "4πr^2"]
},
{
"id": 203,
"question": "Which theorem states that hypotenuse^2 = base^2 + height^2?",
- "answer": "Pythagorean's, Pythagorean's theorem"
+ "answer": ["Pythagorean's", "Pythagorean's theorem"]
},
{
"id": 204,
"question": "Which trigonometric function is defined as hypotenuse/opposite?",
- "answer": "cosecant, cosec, csc"
+ "answer": ["cosecant", "cosec", "csc"]
},
{
"id": 205,
@@ -317,7 +317,7 @@
{
"id": 206,
"question": "How many quadrants are there in a cartesian plane?",
- "answer": "4, four"
+ "answer": ["4", "four"]
},
{
"id": 207,
@@ -328,7 +328,7 @@
"id": 208,
"question": "What's the following formula that finds the area of a triangle called?",
"img_url": "https://wikimedia.org/api/rest_v1/media/math/render/png/d22b8566e8187542966e8d166e72e93746a1a6fc",
- "answer": "Heron's formula, Heron"
+ "answer": ["Heron's formula", "Heron"]
},
{
"id": 209,
@@ -372,12 +372,12 @@
{
"id": 216,
"question": "In set builder notation, what does {p/q | q ≠ 0, p & q ∈ Z} represent?",
- "answer": "Rationals, Rational Numbers"
+ "answer": ["Rationals", "Rational Numbers"]
},
{
"id": 217,
"question": "What is the natural log of -1 (use i for imaginary number)?",
- "answer": "pi*i, pii, πi"
+ "answer": ["pi*i", "pii", "πi"]
},
{
"id": 218,
@@ -397,7 +397,7 @@
{
"id": 221,
"question": "Prime numbers only have __ factors.",
- "answer": "2, two"
+ "answer": ["2", "two"]
},
{
"id": 222,
@@ -408,7 +408,7 @@
"id": 223,
"question": "In statistics, what does this formula represent?",
"img_url": "https://www.statisticshowto.com/wp-content/uploads/2013/11/sample-standard-deviation.jpg",
- "answer": "sample standard deviation, standard deviation of a sample"
+ "answer": ["sample standard deviation", "standard deviation of a sample"]
},
{
"id": 224,
@@ -418,7 +418,7 @@
{
"id": 225,
"question": "A matrix multiplied by its inverse matrix equals...",
- "answer": "the identity matrix, identity matrix"
+ "answer": ["the identity matrix", "identity matrix"]
},
{
"id": 226,
@@ -429,19 +429,19 @@
{
"id": 227,
"question": "What is the only number in the entire number system which can be spelled with the same number of letters as itself?",
- "answer": "4, four"
+ "answer": ["4", "four"]
},
{
"id": 228,
"question": "1/100th of a second is also termed as what?",
- "answer": "a jiffy, jiffy, centisecond"
+ "answer": ["a jiffy", "jiffy", "centisecond"]
},
{
"id": 229,
"question": "What is this triangle called?",
"img_url": "https://cdn.askpython.com/wp-content/uploads/2020/07/Pascals-triangle.png",
- "answer": "Pascal's triangle, Pascal"
+ "answer": ["Pascal's triangle", "Pascal"]
},
{
"id": 230,
@@ -468,17 +468,17 @@
{
"id": 304,
"question": "What do you call an organism composed of only one cell?",
- "answer": "unicellular, single-celled"
+ "answer": ["unicellular", "single-celled"]
},
{
"id": 305,
"question": "The Heisenberg's Uncertainty Principle states that the position and \\_\\_\\_\\_\\_\\_\\_\\_ of a quantum object can't be both exactly measured at the same time.",
- "answer": "velocity, momentum"
+ "answer": ["velocity", "momentum"]
},
{
"id": 306,
"question": "A \\_\\_\\_\\_\\_\\_\\_\\_\\_\\_\\_\\_ reaction is the one wherein an atom or a set of atoms is/are replaced by another atom or a set of atoms",
- "answer": "displacement, exchange"
+ "answer": ["displacement", "exchange"]
},
{
"id": 307,
@@ -512,7 +512,7 @@
{
"id": 312,
"question": "What is the intermolecular force caused by temporary and induced dipoles?",
- "answer": "LDF, London dispersion, London dispersion force"
+ "answer": ["LDF", "London dispersion", "London dispersion force"]
},
{
"id": 313,
@@ -522,7 +522,7 @@
{
"id": 314,
"question": "About how many neurons are in the human brain?\n(A. 1 billion, B. 10 billion, C. 100 billion, D. 300 billion)",
- "answer": "C, 100 billion, 100 bil"
+ "answer": ["C", "100 billion", "100 bil"]
},
{
"id": 315,
@@ -537,12 +537,12 @@
{
"id": 317,
"question": "Which vascular tissue transports water and minerals from the roots to the rest of a plant?",
- "answer": "the xylem, xylem"
+ "answer": ["the xylem", "xylem"]
},
{
"id": 318,
"question": "Who discovered the theories of relativity?",
- "answer": "Albert Einstein, Einstein"
+ "answer": ["Albert Einstein", "Einstein"]
},
{
"id": 319,
@@ -557,7 +557,7 @@
{
"id": 321,
"question": "What range of frequency are the average human ears capable of hearing?\n(A. 10Hz-10kHz, B. 20Hz-20kHz, C. 20Hz-2000Hz, D. 10kHz-20kHz)",
- "answer": "B, 20Hz-20kHz"
+ "answer": ["B", "20Hz-20kHz"]
},
{
"id": 322,
@@ -572,7 +572,7 @@
{
"id": 324,
"question": "The type of rock that is formed by the accumulation or deposition of mineral or organic particles at the Earth's surface, followed by cementation, is called...",
- "answer": "sedimentary, sedimentary rock"
+ "answer": ["sedimentary", "sedimentary rock"]
},
{
"id": 325,
@@ -582,7 +582,7 @@
{
"id": 326,
"question": "What type of image is formed by a convex mirror?",
- "answer": "virtual image, virtual"
+ "answer": ["virtual image", "virtual"]
},
{
"id": 327,
@@ -592,17 +592,17 @@
{
"id": 328,
"question": "Which law states that the global entropy in a closed system can only increase?",
- "answer": "second law, second law of thermodynamics"
+ "answer": ["second law", "second law of thermodynamics"]
},
{
"id": 329,
"question": "Which particle is emitted during the beta decay of a radioactive element?",
- "answer": "an electron, the electron, electron"
+ "answer": ["an electron", "the electron", "electron"]
},
{
"id": 330,
"question": "When DNA is unzipped, two strands are formed. What are they called (separate both answers by the word \"and\")?",
- "answer": "leading and lagging, leading strand and lagging strand"
+ "answer": ["leading and lagging", "leading strand and lagging strand"]
}
],
"cs": [
@@ -619,7 +619,7 @@
{
"id": 403,
"question": "What does SASS stand for?",
- "answer": "Syntactically Awesome Stylesheets, Syntactically Awesome Style Sheets"
+ "answer": ["Syntactically Awesome Stylesheets", "Syntactically Awesome Style Sheets"]
},
{
"id": 404,
@@ -629,7 +629,7 @@
{
"id": 405,
"question": "What is computing capable of performing exaFLOPS called?",
- "answer": "exascale computing, exascale"
+ "answer": ["exascale computing", "exascale"]
},
{
"id": 406,
@@ -654,7 +654,7 @@
{
"id": 410,
"question": "A hypothetical point in time at which technological growth becomes uncontrollable and irreversible, resulting in unforeseeable changes to human civilization is termed as...?",
- "answer": "technological singularity, singularity"
+ "answer": ["technological singularity", "singularity"]
},
{
"id": 411,
@@ -664,12 +664,12 @@
{
"id": 412,
"question": "How many bits are in a TCP checksum header?",
- "answer": "16, sixteen"
+ "answer": ["16", "sixteen"]
},
{
"id": 413,
"question": "What is the most popular protocol (as of 2021) that handles communication between email servers?",
- "answer": "SMTP, Simple Mail Transfer Protocol"
+ "answer": ["SMTP", "Simple Mail Transfer Protocol"]
},
{
"id": 414,
@@ -679,12 +679,12 @@
{
"id": 415,
"question": "Which DNS record contains mail servers of a given domain?",
- "answer": "MX, mail exchange"
+ "answer": ["MX", "mail exchange"]
},
{
"id": 416,
"question": "Which newline sequence does HTTP use?",
- "answer": "carriage return line feed, CRLF, \\r\\n"
+ "answer": ["carriage return line feed", "CRLF", "\\r\\n"]
},
{
"id": 417,
@@ -694,7 +694,7 @@
{
"id": 418,
"question": "Name a universal logic gate.",
- "answer": "NAND, NOR"
+ "answer": ["NAND", "NOR"]
},
{
"id": 419,
@@ -729,7 +729,7 @@
{
"id": 425,
"question": "What does the \"a\" represent in a HSLA color value?",
- "answer": "transparency, translucency, alpha value, alpha channel, alpha"
+ "answer": ["transparency", "translucency", "alpha value", "alpha channel", "alpha"]
},
{
"id": 426,
@@ -749,7 +749,7 @@
{
"id": 429,
"question": "Which of these sorting algorithms is not stable?\n(Counting sort, quick sort, insertion sort, tim sort, bubble sort)",
- "answer": "quick, quick sort"
+ "answer": ["quick", "quick sort"]
},
{
"id": 430,
@@ -761,7 +761,7 @@
{
"id": 501,
"question": "Is everything an instance of the `object` class (y/n)?",
- "answer": "y, yes"
+ "answer": ["y", "yes"]
},
{
"id": 502,
@@ -781,7 +781,7 @@
{
"id": 505,
"question": "Can you pickle a running `list_iterator` (y/n)?",
- "answer": "y, yes"
+ "answer": ["y", "yes"]
},
{
"id": 506,
@@ -821,12 +821,12 @@
{
"id": 513,
"question": "Where does the name Python come from?",
- "answer": "Monty Python, Monty Python's Flying Circus"
+ "answer": ["Monty Python", "Monty Python's Flying Circus"]
},
{
"id": 514,
"question": "How is infinity represented in Python?",
- "answer": "float(\"infinity\"), float('infinity'), float(\"inf\"), float('inf')"
+ "answer": ["float(\"infinity\")", "float('infinity')", "float(\"inf\")", "float('inf')"]
},
{
"id": 515,
@@ -846,12 +846,12 @@
{
"id": 518,
"question": "What decorator is used to allow a protocol to be checked at runtime?",
- "answer": "runtime_checkable, typing.runtime_checkable"
+ "answer": ["runtime_checkable", "typing.runtime_checkable"]
},
{
"id": 519,
"question": "Does `numbers.Rational` include the builtin object float (y/n)",
- "answer": "n, no"
+ "answer": ["n", "no"]
},
{
"id": 520,
@@ -866,7 +866,7 @@
{
"id": 522,
"question": "What is the garbage collection strategy used by cpython to collect everything but reference cycles?",
- "answer": "reference counting, refcounting"
+ "answer": ["reference counting", "refcounting"]
},
{
"id": 523,
@@ -891,12 +891,12 @@
{
"id": 527,
"question": "Is the `__aiter__` method async (y/n)?",
- "answer": "n, no"
+ "answer": ["n", "no"]
},
{
"id": 528,
"question": "How does one call a class who defines the behavior of their instance classes?",
- "answer": "a metaclass, metaclass"
+ "answer": ["a metaclass", "metaclass"]
},
{
"id": 529,