From fd9bde73c614304897e8f4c98f1fd225e69978b6 Mon Sep 17 00:00:00 2001 From: NikolajDanger Date: Sun, 18 Apr 2021 14:42:21 +0200 Subject: [PATCH] :sparkles: Trivia --- funcs/games/trivia.py | 207 ++++++++++++++++++++++++++----------- resources/longStrings.json | 4 +- 2 files changed, 150 insertions(+), 61 deletions(-) diff --git a/funcs/games/trivia.py b/funcs/games/trivia.py index eeb4003..e01fc1d 100644 --- a/funcs/games/trivia.py +++ b/funcs/games/trivia.py @@ -1,94 +1,175 @@ -import json -import urllib -import random -import asyncio +""" +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 discord_slash.context 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 - # Starts 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 games.json file. - def triviaStart(self, channel : str): - question = self.bot.database["trivia questions"].find_one({"_id":channel}) + def triviaStart(self, channel: str): + """ + Start a game of trivia. - self.bot.log("Trying to find a trivia question for "+channel) + 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. - if question == None: - with urllib.request.urlopen("https://opentdb.com/api.php?amount=10&type=multiple") as response: + *Parameters* + ------------ + channel: str + The id of the channel to start the game in + + *Returns* + --------- + sendMessage: 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()) - self.bot.log("Found the question \""+data["results"][0]["question"]+"\"") + 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 = answers.index(data["results"][0]["correct_answer"]) + 97 + correctAnswer = data["results"][0]["correct_answer"] + correctAnswer = answers.index(correctAnswer) + 97 - self.bot.database["trivia questions"].insert_one({"_id":channel,"answer" : str(chr(correctAnswer)),"players" : {}}) + newQuestion = { + "_id": channel, + "answer": str(chr(correctAnswer)), + "players": {} + } + triviaQuestions.insert_one(newQuestion) - replacements = {"'": "\'", - """: "\"", - "“": "\"", - "”": "\"", - "é": "é"} + replacements = { + "'": "\'", + """: "\"", + "“": "\"", + "”": "\"", + "é": "é" + } question = data["results"][0]["question"] for key, value in replacements.items(): - question = question.replace(key,value) + question = question.replace(key, value) for answer in answers: for key, value in replacements.items(): - answer = answer.replace(key,value) + answer = answer.replace(key, value) return question, answers, correctAnswer else: - self.bot.log("There was already a trivia question for that channel (error code 1106)") - return "There's already a trivia question going on. Try again in like, a minute (error code 1106)", "", "" + logMessage = "There was already a trivia question for that channel" + self.bot.log(logMessage) + return self.bot.longStrings["Trivia going on"], "", "" - # Lets players answer a trivia question - def triviaAnswer(self, user : str, channel : str, command : str): - question = self.bot.database["trivia questions"].find_one({"_id":channel}) + def triviaAnswer(self, user: str, channel: str, command: str): + """ + Answer the current trivia question. - if command in ["a","b","c","d"]: - if question != None: - if user not in question["players"]: - self.bot.log(user+" answered the question in "+channel) + *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. - self.bot.database["trivia questions"].update_one({"_id":channel},{"$set":{"players."+user : command}}) + *Returns* + --------- + sendMessage: str + The message to send if the function failed. + """ + triviaQuestions = self.bot.database["trivia questions"] + question = triviaQuestions.find_one({"_id": channel}) - return "Locked in "+user+"'s answer" - else: - self.bot.log(user+" has already answered this question (error code 1105)") - return user+" has already answered this question (error code 1105)" - else: - self.bot.log("There's no question right now (error code 1104)") - return "There's no question right now (error code 1104)" + 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("I didn't quite understand that (error code 1103)") - return "I didn't quite understand that (error code 1103)" + self.bot.log(f"{user} answered the question in {channel}") + updater = {"$set": {f"players.{user}": command}} + triviaQuestions.update_one({"_id": channel}, updater) + return None - # Adds 1 GwendoBuck to each player that got the question right and deletes question from games.json. - def triviaCountPoints(self, channel : str): - question = self.bot.database["trivia questions"].find_one({"_id":channel}) + 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 != None: + if question is not None: for player, answer in question["players"].items(): if answer == question["answer"]: - self.bot.money.addMoney(player,1) - - + self.bot.money.addMoney(player, 1) else: - self.bot.log("Couldn't find the question (error code 1102)") + self.bot.log("Couldn't find the questio") return None - async def triviaParse(self, ctx, answer): + 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(str(ctx.channel_id)) + question, options, correctAnswer = self.triviaStart(channelId) if options != "": results = "**"+question+"**\n" for x, option in enumerate(options): @@ -98,21 +179,27 @@ class Trivia(): await asyncio.sleep(60) - self.triviaCountPoints(str(ctx.channel_id)) + self.triviaCountPoints(channelId) - self.bot.databaseFuncs.deleteGame("trivia questions",str(ctx.channel_id)) + deleteGameParams = ["trivia questions", channelId] + self.bot.databaseFuncs.deleteGame(*deleteGameParams) - self.bot.log("Time's up for the trivia question",str(ctx.channel_id)) - await ctx.send("Time's up The answer was \"*"+chr(correctAnswer)+") "+options[correctAnswer-97]+"*\". Anyone who answered that has gotten 1 GwendoBuck") + self.bot.log("Time's up for the trivia question", channelId) + sendMessage = self.bot.longStrings["Trivia time up"] + formatParams = [chr(correctAnswer), options[correctAnswer-97]] + sendMessage = sendMessage.format(*formatParams) + await ctx.send(sendMessage) else: await ctx.send(question, hidden=True) - elif answer in ["a","b","c","d"]: - response = self.triviaAnswer("#"+str(ctx.author.id), str(ctx.channel_id), answer) - if response.startswith("Locked in "): - await ctx.send(f"{ctx.author.display_name} answered **{answer}**") + elif answer in ["a", "b", "c", "d"]: + userId = f"#{ctx.author.id}" + response = self.triviaAnswer(userId, channelId, answer) + if response is None: + userName = ctx.author.display_name + await ctx.send(f"{userName} answered **{answer}**") else: await ctx.send(response) else: - self.bot.log("I didn't understand that (error code 1101)",str(ctx.channel_id)) - await ctx.send("I didn't understand that (error code 1101)") + self.bot.log("I didn't understand that", channelId) + await ctx.send("I didn't understand that") diff --git a/resources/longStrings.json b/resources/longStrings.json index d1e1a0e..188fc7f 100644 --- a/resources/longStrings.json +++ b/resources/longStrings.json @@ -10,5 +10,7 @@ "Blackjack started": "Blackjack game started. Use \"/blackjack bet [amount]\" to enter the game within the next 30 seconds.", "Blackjack going on": "There's already a blackjack game going on. Try again in a few minutes.", "Stock value": "The current {} stock is valued at **{}** GwendoBucks", - "Stock parameters": "You must give both a stock name and an amount of GwendoBucks you wish to spend." + "Stock parameters": "You must give both a stock name and an amount of GwendoBucks you wish to spend.", + "Trivia going on": "There's already a trivia question going on. Try again in like, a minute", + "Trivia time up": "Time's up! The answer was \"*{}) {}*\". Anyone who answered that has gotten 1 GwendoBuck" } \ No newline at end of file