Files
Gwendolyn/gwendolyn_old/funcs/games/trivia.py
2024-10-28 13:05:06 +01:00

206 lines
6.9 KiB
Python

"""
Contains code for trivia games.
*Classes*
---------
Trivia
Contains all the code for the trivia commands.
"""
import urllib # Used to get data from api
import json # Used to read data from api
import random # Used to shuffle answers
import asyncio # Used to sleep
from interactions import SlashContext # Used for type hints
class Trivia():
"""
Contains the code for trivia games.
*Methods*
---------
triviaStart(channel: str) -> str, str, str
triviaAnswer(user: str, channel: str, command: str) -> str
triviaCountPoints(channel: str)
triviaParse(ctx: SlashContext, answer: str)
"""
def __init__(self, bot):
"""Initialize the class."""
self.bot = bot
def triviaStart(self, channel: str):
"""
Start a game of trivia.
Downloads a question with answers, shuffles the wrong answers
with the correct answer and returns the questions and answers.
Also saves the question in the database.
*Parameters*
------------
channel: str
The id of the channel to start the game in
*Returns*
---------
send_message: str
The message to return to the user.
"""
triviaQuestions = self.bot.database["trivia questions"]
question = triviaQuestions.find_one({"_id": channel})
self.bot.log(f"Trying to find a trivia question for {channel}")
if question is None:
apiUrl = "https://opentdb.com/api.php?amount=10&type=multiple"
with urllib.request.urlopen(apiUrl) as response:
data = json.loads(response.read())
question = data["results"][0]["question"]
self.bot.log(f"Found the question \"{question}\"")
answers = data["results"][0]["incorrect_answers"]
answers.append(data["results"][0]["correct_answer"])
random.shuffle(answers)
correctAnswer = data["results"][0]["correct_answer"]
correctAnswer = answers.index(correctAnswer) + 97
newQuestion = {
"_id": channel,
"answer": str(chr(correctAnswer)),
"players": {}
}
triviaQuestions.insert_one(newQuestion)
replacements = {
"'": "\'",
""": "\"",
"“": "\"",
"”": "\"",
"é": "é"
}
question = data["results"][0]["question"]
for key, value in replacements.items():
question = question.replace(key, value)
for answer in answers:
for key, value in replacements.items():
answer = answer.replace(key, value)
return question, answers, correctAnswer
else:
log_message = "There was already a trivia question for that channel"
self.bot.log(log_message)
return self.bot.long_strings["Trivia going on"], "", ""
def triviaAnswer(self, user: str, channel: str, command: str):
"""
Answer the current trivia question.
*Parameters*
------------
user: str
The id of the user who answered.
channel: str
The id of the channel the game is in.
command: str
The user's answer.
*Returns*
---------
send_message: str
The message to send if the function failed.
"""
triviaQuestions = self.bot.database["trivia questions"]
question = triviaQuestions.find_one({"_id": channel})
if command not in ["a", "b", "c", "d"]:
self.bot.log("I didn't quite understand that")
return "I didn't quite understand that"
elif question is None:
self.bot.log("There's no question right now")
return "There's no question right now"
elif user in question["players"]:
self.bot.log(f"{user} has already answered this question")
return f"{user} has already answered this question"
else:
self.bot.log(f"{user} answered the question in {channel}")
updater = {"$set": {f"players.{user}": command}}
triviaQuestions.update_one({"_id": channel}, updater)
return None
def triviaCountPoints(self, channel: str):
"""
Add money to every winner's account.
*Parameters*
------------
channel: str
The id of the channel the game is in.
"""
triviaQuestions = self.bot.database["trivia questions"]
question = triviaQuestions.find_one({"_id": channel})
self.bot.log("Counting points for question in "+channel)
if question is not None:
for player, answer in question["players"].items():
if answer == question["answer"]:
self.bot.money.addMoney(player, 1)
else:
self.bot.log("Couldn't find the questio")
return None
async def triviaParse(self, ctx: SlashContext, answer: str):
"""
Parse a trivia command.
*Parameters*
------------
ctx: SlashContext
The context of the command.
answer: str
The answer, if any.
"""
await self.bot.defer(ctx)
channelId = str(ctx.channel_id)
if answer == "":
question, options, correctAnswer = self.triviaStart(channelId)
if options != "":
results = "**"+question+"**\n"
for x, option in enumerate(options):
results += chr(x+97) + ") "+option+"\n"
await ctx.send(results)
await asyncio.sleep(60)
self.triviaCountPoints(channelId)
delete_gameParams = ["trivia questions", channelId]
self.bot.database_funcs.delete_game(*delete_gameParams)
self.bot.log("Time's up for the trivia question", channelId)
send_message = self.bot.long_strings["Trivia time up"]
format_parameters = [chr(correctAnswer), options[correctAnswer-97]]
send_message = send_message.format(*format_parameters)
await ctx.send(send_message)
else:
await ctx.send(question, hidden=True)
elif answer in ["a", "b", "c", "d"]:
userId = f"#{ctx.author.id}"
response = self.triviaAnswer(userId, channelId, answer)
if response is None:
user_name = ctx.author.display_name
await ctx.send(f"{user_name} answered **{answer}**")
else:
await ctx.send(response)
else:
self.bot.log("I didn't understand that", channelId)
await ctx.send("I didn't understand that")