From c558d88e74fa6e638dd38bc1232e2839ba72c8da Mon Sep 17 00:00:00 2001 From: Rohan Date: Tue, 27 Aug 2019 17:32:50 +0530 Subject: A fun trivia quiz that can be played on multiple channelsThe trivia quiz has the following features: quiz has the following features: - There wont be any options to the questions asked, the users have to type the answer in the chat and the bot will pick up the right anwer - If 3 questions have not been answered in a row, the quiz will be brought to a halt assuming inactivity. - There are also hints in this game! A hint will be sent after 10s after the question has been sent.Each question has a maximum if 2 hints. - The bot checks for the closest answer rather than the exact one(Incase of typoes in the users answer --- bot/resources/evergreen/trivia_quiz.json | 34 ++++ bot/seasons/evergreen/TriviaQuiz.py | 263 +++++++++++++++++++++++++++++++ 2 files changed, 297 insertions(+) create mode 100644 bot/resources/evergreen/trivia_quiz.json create mode 100644 bot/seasons/evergreen/TriviaQuiz.py (limited to 'bot') diff --git a/bot/resources/evergreen/trivia_quiz.json b/bot/resources/evergreen/trivia_quiz.json new file mode 100644 index 00000000..f884e67a --- /dev/null +++ b/bot/resources/evergreen/trivia_quiz.json @@ -0,0 +1,34 @@ +{ + "retro": [ + { + "id": 1, + "hints": ["It was not a mainline Mario Game, although the plumber was present.", "It was not a mainline Zelda Game, although Link was present."], + "question": "What was the best selling game on the Nintendo Gamecube?", + "answer": "Super Smash Bros" + }, + { + "id": 2, + "hints": ["It was released before the 90s.", "It was released after 1980."], + "question": "What year was Tetris released?", + "answer": "1984" + }, + { + "id": 3, + "hints": ["The occupation was in construction", "He appeared as this kind of worker in 1981's Donkey Kong"], + "question": "What was Mario's original occupation?", + "answer": "Carpenter" + }, + { + "id": 4, + "hints": ["It was revelead in the Nintendo Character Guide in 1993.", "His last name has to do with eating Mario's enemies."], + "question": "What is Yoshi's(from Mario Bros) full name?", + "answer": "Yoshisaur Munchakoopas" + }, + { + "id": 5, + "hints": ["The game was released in 1990.", "It was released on the SNES."], + "question": "What was the first game Yoshi appeared in?", + "answer": "Super Mario World" + } + ] +} diff --git a/bot/seasons/evergreen/TriviaQuiz.py b/bot/seasons/evergreen/TriviaQuiz.py new file mode 100644 index 00000000..38f19922 --- /dev/null +++ b/bot/seasons/evergreen/TriviaQuiz.py @@ -0,0 +1,263 @@ +import asyncio +import logging +import random +from dataclasses import dataclass +from json import load +from pathlib import Path + +import discord +from discord.ext import commands +from fuzzywuzzy import fuzz + +from bot.constants import Roles + + +logger = logging.getLogger(__name__) + + +annoyed_expressions = ["-_-", "-.-"] + +wrong_ans_responses = [ + "No one gave the correct answer", + "Losers", + "You guys really need to learn" +] + + +@dataclass +class GameData: + """A dataclass for game data.""" + + owner: int + players = [] + points = [] + done_questions = [] + category: str + question: dict = None + hints = 0 + unanswered_questions = 0 + + +class TriviaQuiz(commands.Cog): + """A cog for all quiz commands.""" + + def __init__(self, bot): + self.bot = bot + self.questions = self.load_questions() + self.games = {} # channel as key and value as instinct of dataclass GameData + self.categories = { + "retro": "Questions related to retro gaming." + } + self.inactivity_limit = 3 # Number of questions unanswered in a row after which quiz stops. + + @staticmethod + def load_questions(): + """Load the questions from json file.""" + p = Path("bot", "resources", "evergreen", "trivia_quiz.json ") + with p.open() as json_data: + questions = load(json_data) + return questions + + @commands.group(name="tquiz", invoke_without_command=False) + async def tquiz(self, ctx): + """Trivia Quiz game for fun!""" + await ctx.send_help("tquiz") + + @tquiz.command(name="start") + async def start(self, ctx, category=None): + """Start a quiz! + + Questions for the quiz can be selected from the following categories: + - Retro : questions related to retro gaming. + """ + await ctx.send("Quiz triggered! Gonna start in a couple of seconds...") + await asyncio.sleep(1) + + # Checking if there is already a game running in that channel. + if ctx.channel.id in list(self.games.keys()): + return await ctx.send("Game already running in this channel!") + + if category is None: + category = random.choice(list(self.categories.keys())) + + else: + category = category.lower() + if category not in self.categories.keys(): + embed = self.category_embed() + return await ctx.send(f"Category {category} does not exist!", embed=embed) + + self.games[ctx.channel.id] = GameData( + owner=ctx.author.id, + category=category + ) + + await self.send_question(ctx.channel) + + def category_embed(self): + """A function which returns an embed showing all avilable categories""" + embed = discord.Embed(colour=discord.Colour.blue()) + embed.title = "The available question categories are:" + embed.description = "" + for cat, description in self.categories.items(): + embed.description += f"**- {cat.capitalize()}**\n{description.capitalize()}\n" + embed.set_footer(text="If not category is chosen, then a random one will be selected.") + return embed + + async def send_question(self, channel): + """This function is to be called whenever a question needs to be sent.""" + await asyncio.sleep(2) + game = self.games[channel.id] + if game.unanswered_questions == self.inactivity_limit: + del self.games[channel.id] + return await channel.send("Game stopped due to inactivity.") + + category = game.category + category_dict = self.questions[category] + question_dict = random.choice(category_dict) + + same_question = True + + # Making sure a question is not repeated. + while same_question is True: + question_dict = random.choice(category_dict) + if question_dict["id"] not in game.done_questions: + same_question = False + else: + pass + + # Initial points for a question. + question_dict["points"] = 100 + game.question = question_dict + game.hints = 0 + + embed = discord.Embed(colour=discord.Colour.dark_gold()) + + question = question_dict["question"] + question_id = question_dict["id"] + + game.done_questions.append(question_id) + question_number = len(game.done_questions) + + embed.title = f"#{question_number} Question" + embed.description = question + embed.set_footer(text="A hint will be provided after every 10s if no one gives the right answer.Max of 2 hints") + + await channel.send(embed=embed) + await self.send_hint(channel, question_dict) + + @commands.Cog.listener() + async def on_message(self, message): + """A function triggered when a message is sent.""" + channel = message.channel + if channel.id not in list(self.games.keys()): + return + if message.author.bot: + return + + game = self.games[message.channel.id] + question_data = game.question + answer = question_data["answer"].lower() + user_answer = message.content.lower() + ratio = fuzz.ratio(answer, user_answer) + if ratio > 84: + points = question_data["points"] - game.hints*25 + if message.author in game.players: + author_index = game.players.index(message.author) + game.points[author_index] = game.points[author_index] + points + else: + game.players.append(message.author) + game.points.append(points) + + await channel.send(f"{message.author.mention} got it right! Good job :tada:" + f"You got {points} points.") + await self.score_embed(channel) + await self.send_question(channel) + elif ratio in range(75, 84): + await channel.send(f"Your close to the answer {message.author.mention}") + + async def send_hint(self, channel, question_dict): + """Function to be called whenever a hint has to be sent.""" + await asyncio.sleep(10) + try: + game = self.games[channel.id] + except KeyError: + return + + # Checking if the question is the same after 10 seconds. + if question_dict["id"] == game.question["id"]: + + # If the max number of hints is already reached, then send the answer. + if 2 - game.hints == 0: + return await self.send_answer(channel) + + hint_list = question_dict["hints"] + hint_index = game.hints + hint = hint_list[hint_index] + game.hints += 1 + message = f"**Hint {game.hints}**: {hint}\n*Number of hints remaining: {2-game.hints}*" + await channel.send(message) + await self.send_hint(channel, question_dict) + else: + pass + + async def send_answer(self, channel): + """A function to send the answer in the channel if no user have given the correct answer even after 2 hints.""" + game = self.games[channel.id] + answer = game.question["answer"] + response = random.choice(wrong_ans_responses) + expression = random.choice(annoyed_expressions) + await channel.send(f"{response} {expression}, the correct answer is **{answer}**.") + self.games[channel.id].unanswered_questions += 1 + await self.score_embed(channel) + await self.send_question(channel) + + @tquiz.command(name="score") + async def send_score(self, ctx): + """Show scoreboard of the game running in this channel.""" + await self.score_embed(ctx.channel) + + async def score_embed(self, channel): + """Show score of each player in the quiz.""" + if channel.id not in list(self.games.keys()): + return await channel.send("There are no games running in this channel!") + game = self.games[channel.id] + players = game.players + if len(players) == 0: + return + points = game.points + embed = discord.Embed(color=discord.Colour.dark_gold()) + embed.title = "Scoreboard" + embed.description = "" + for player, score in zip(players, points): + embed.description = f"{player} - {score}\n" + await channel.send(embed=embed) + + @tquiz.command(name="stop") + async def stop_quiz(self, ctx): + """Stop the quiz.""" + if ctx.channel.id not in list(self.games.keys()): + return await ctx.send("No game running, nothing to stop here -.-") + game = self.games[ctx.channel.id] + owner = game.owner + mods = Roles.moderator + if ctx.author.id == owner or mods in [role.id for role in ctx.author.roles]: + await ctx.send("Game is not running anymore!") + await self.score_embed(ctx.channel) + if game.players: + highest_points = max(game.points) + author_index = game.points.index(highest_points) + winner = game.players[author_index] + await ctx.send( + f"Congratz {winner.mention} :tada: " + f"You have won this quiz game with a grand total of {highest_points} points!!" + ) + await asyncio.sleep(2) + del self.games[ctx.channel.id] + else: + await ctx.send("You are not authorised to close this game!") + + +def setup(bot): + """Loading the cog.""" + bot.add_cog(TriviaQuiz(bot)) + logger.debug("TriviaQuiz cog loaded!") -- cgit v1.2.3 From e14ea852571835d662bb0ee829321be2b330557e Mon Sep 17 00:00:00 2001 From: RohanJnr Date: Wed, 11 Sep 2019 22:26:26 +0530 Subject: Made the following changes: - Linting - renamed self.games to self.running_games - using self.running_games insted of list(self.running_games.keys()) to loop over its keys. - Renamed the file to trivia_quiz --- bot/seasons/evergreen/TriviaQuiz.py | 263 ---------------------------------- bot/seasons/evergreen/trivia_quiz.py | 266 +++++++++++++++++++++++++++++++++++ 2 files changed, 266 insertions(+), 263 deletions(-) delete mode 100644 bot/seasons/evergreen/TriviaQuiz.py create mode 100644 bot/seasons/evergreen/trivia_quiz.py (limited to 'bot') diff --git a/bot/seasons/evergreen/TriviaQuiz.py b/bot/seasons/evergreen/TriviaQuiz.py deleted file mode 100644 index 38f19922..00000000 --- a/bot/seasons/evergreen/TriviaQuiz.py +++ /dev/null @@ -1,263 +0,0 @@ -import asyncio -import logging -import random -from dataclasses import dataclass -from json import load -from pathlib import Path - -import discord -from discord.ext import commands -from fuzzywuzzy import fuzz - -from bot.constants import Roles - - -logger = logging.getLogger(__name__) - - -annoyed_expressions = ["-_-", "-.-"] - -wrong_ans_responses = [ - "No one gave the correct answer", - "Losers", - "You guys really need to learn" -] - - -@dataclass -class GameData: - """A dataclass for game data.""" - - owner: int - players = [] - points = [] - done_questions = [] - category: str - question: dict = None - hints = 0 - unanswered_questions = 0 - - -class TriviaQuiz(commands.Cog): - """A cog for all quiz commands.""" - - def __init__(self, bot): - self.bot = bot - self.questions = self.load_questions() - self.games = {} # channel as key and value as instinct of dataclass GameData - self.categories = { - "retro": "Questions related to retro gaming." - } - self.inactivity_limit = 3 # Number of questions unanswered in a row after which quiz stops. - - @staticmethod - def load_questions(): - """Load the questions from json file.""" - p = Path("bot", "resources", "evergreen", "trivia_quiz.json ") - with p.open() as json_data: - questions = load(json_data) - return questions - - @commands.group(name="tquiz", invoke_without_command=False) - async def tquiz(self, ctx): - """Trivia Quiz game for fun!""" - await ctx.send_help("tquiz") - - @tquiz.command(name="start") - async def start(self, ctx, category=None): - """Start a quiz! - - Questions for the quiz can be selected from the following categories: - - Retro : questions related to retro gaming. - """ - await ctx.send("Quiz triggered! Gonna start in a couple of seconds...") - await asyncio.sleep(1) - - # Checking if there is already a game running in that channel. - if ctx.channel.id in list(self.games.keys()): - return await ctx.send("Game already running in this channel!") - - if category is None: - category = random.choice(list(self.categories.keys())) - - else: - category = category.lower() - if category not in self.categories.keys(): - embed = self.category_embed() - return await ctx.send(f"Category {category} does not exist!", embed=embed) - - self.games[ctx.channel.id] = GameData( - owner=ctx.author.id, - category=category - ) - - await self.send_question(ctx.channel) - - def category_embed(self): - """A function which returns an embed showing all avilable categories""" - embed = discord.Embed(colour=discord.Colour.blue()) - embed.title = "The available question categories are:" - embed.description = "" - for cat, description in self.categories.items(): - embed.description += f"**- {cat.capitalize()}**\n{description.capitalize()}\n" - embed.set_footer(text="If not category is chosen, then a random one will be selected.") - return embed - - async def send_question(self, channel): - """This function is to be called whenever a question needs to be sent.""" - await asyncio.sleep(2) - game = self.games[channel.id] - if game.unanswered_questions == self.inactivity_limit: - del self.games[channel.id] - return await channel.send("Game stopped due to inactivity.") - - category = game.category - category_dict = self.questions[category] - question_dict = random.choice(category_dict) - - same_question = True - - # Making sure a question is not repeated. - while same_question is True: - question_dict = random.choice(category_dict) - if question_dict["id"] not in game.done_questions: - same_question = False - else: - pass - - # Initial points for a question. - question_dict["points"] = 100 - game.question = question_dict - game.hints = 0 - - embed = discord.Embed(colour=discord.Colour.dark_gold()) - - question = question_dict["question"] - question_id = question_dict["id"] - - game.done_questions.append(question_id) - question_number = len(game.done_questions) - - embed.title = f"#{question_number} Question" - embed.description = question - embed.set_footer(text="A hint will be provided after every 10s if no one gives the right answer.Max of 2 hints") - - await channel.send(embed=embed) - await self.send_hint(channel, question_dict) - - @commands.Cog.listener() - async def on_message(self, message): - """A function triggered when a message is sent.""" - channel = message.channel - if channel.id not in list(self.games.keys()): - return - if message.author.bot: - return - - game = self.games[message.channel.id] - question_data = game.question - answer = question_data["answer"].lower() - user_answer = message.content.lower() - ratio = fuzz.ratio(answer, user_answer) - if ratio > 84: - points = question_data["points"] - game.hints*25 - if message.author in game.players: - author_index = game.players.index(message.author) - game.points[author_index] = game.points[author_index] + points - else: - game.players.append(message.author) - game.points.append(points) - - await channel.send(f"{message.author.mention} got it right! Good job :tada:" - f"You got {points} points.") - await self.score_embed(channel) - await self.send_question(channel) - elif ratio in range(75, 84): - await channel.send(f"Your close to the answer {message.author.mention}") - - async def send_hint(self, channel, question_dict): - """Function to be called whenever a hint has to be sent.""" - await asyncio.sleep(10) - try: - game = self.games[channel.id] - except KeyError: - return - - # Checking if the question is the same after 10 seconds. - if question_dict["id"] == game.question["id"]: - - # If the max number of hints is already reached, then send the answer. - if 2 - game.hints == 0: - return await self.send_answer(channel) - - hint_list = question_dict["hints"] - hint_index = game.hints - hint = hint_list[hint_index] - game.hints += 1 - message = f"**Hint {game.hints}**: {hint}\n*Number of hints remaining: {2-game.hints}*" - await channel.send(message) - await self.send_hint(channel, question_dict) - else: - pass - - async def send_answer(self, channel): - """A function to send the answer in the channel if no user have given the correct answer even after 2 hints.""" - game = self.games[channel.id] - answer = game.question["answer"] - response = random.choice(wrong_ans_responses) - expression = random.choice(annoyed_expressions) - await channel.send(f"{response} {expression}, the correct answer is **{answer}**.") - self.games[channel.id].unanswered_questions += 1 - await self.score_embed(channel) - await self.send_question(channel) - - @tquiz.command(name="score") - async def send_score(self, ctx): - """Show scoreboard of the game running in this channel.""" - await self.score_embed(ctx.channel) - - async def score_embed(self, channel): - """Show score of each player in the quiz.""" - if channel.id not in list(self.games.keys()): - return await channel.send("There are no games running in this channel!") - game = self.games[channel.id] - players = game.players - if len(players) == 0: - return - points = game.points - embed = discord.Embed(color=discord.Colour.dark_gold()) - embed.title = "Scoreboard" - embed.description = "" - for player, score in zip(players, points): - embed.description = f"{player} - {score}\n" - await channel.send(embed=embed) - - @tquiz.command(name="stop") - async def stop_quiz(self, ctx): - """Stop the quiz.""" - if ctx.channel.id not in list(self.games.keys()): - return await ctx.send("No game running, nothing to stop here -.-") - game = self.games[ctx.channel.id] - owner = game.owner - mods = Roles.moderator - if ctx.author.id == owner or mods in [role.id for role in ctx.author.roles]: - await ctx.send("Game is not running anymore!") - await self.score_embed(ctx.channel) - if game.players: - highest_points = max(game.points) - author_index = game.points.index(highest_points) - winner = game.players[author_index] - await ctx.send( - f"Congratz {winner.mention} :tada: " - f"You have won this quiz game with a grand total of {highest_points} points!!" - ) - await asyncio.sleep(2) - del self.games[ctx.channel.id] - else: - await ctx.send("You are not authorised to close this game!") - - -def setup(bot): - """Loading the cog.""" - bot.add_cog(TriviaQuiz(bot)) - logger.debug("TriviaQuiz cog loaded!") diff --git a/bot/seasons/evergreen/trivia_quiz.py b/bot/seasons/evergreen/trivia_quiz.py new file mode 100644 index 00000000..dd4008d0 --- /dev/null +++ b/bot/seasons/evergreen/trivia_quiz.py @@ -0,0 +1,266 @@ +import asyncio +import json +import logging +import random +from dataclasses import dataclass +from pathlib import Path + +import discord +from discord.ext import commands +from fuzzywuzzy import fuzz + +from bot.constants import Roles + + +logger = logging.getLogger(__name__) + + +annoyed_expressions = ["-_-", "-.-"] + +wrong_ans_responses = [ + "No one gave the correct answer", + "Losers", + "You guys really need to learn" +] + + +@dataclass +class GameData: + """A dataclass for game data.""" + + owner: int + players = [] + points = [] + done_questions = [] + category: str + question: dict = None + hints = 0 + unanswered_questions = 0 + + +class TriviaQuiz(commands.Cog): + """A cog for all quiz commands.""" + + def __init__(self, bot): + self.bot = bot + self.questions = self.load_questions() + self.running_games = {} # channel as key and value as instance of dataclass GameData + self.categories = { + "retro": "Questions related to retro gaming." + } + self.inactivity_limit = 3 # Number of questions unanswered in a row after which quiz stops. + + @staticmethod + def load_questions(): + """Load the questions from json file.""" + p = Path("bot", "resources", "evergreen", "trivia_quiz.json") + with p.open() as json_data: + questions = json.load(json_data) + return questions + + @commands.group(name="tquiz", invoke_without_command=True) + async def tquiz(self, ctx): + """Trivia Quiz game for fun!""" + await ctx.send_help("tquiz") + + @tquiz.command(name="start") + async def start(self, ctx, category=None): + """ + Start a quiz! + + Questions for the quiz can be selected from the following categories: + - Retro : questions related to retro gaming. + """ + await ctx.send("Quiz triggered! Gonna start in a couple of seconds...") + await asyncio.sleep(1) + + # Checking if there is already a game running in that channel. + if ctx.channel.id in self.running_games: + return await ctx.send("Game already running in this channel!") + + if category is None: + category = random.choice(list(self.categories.keys())) + + else: + category = category.lower() + if category not in self.categories.keys(): + embed = self.category_embed() + return await ctx.send(f"Category {category} does not exist!", embed=embed) + + self.running_games[ctx.channel.id] = GameData( + owner=ctx.author.id, + category=category + ) + + await self.send_question(ctx.channel) + + def category_embed(self): + """A function which returns an embed showing all avilable categories""" + embed = discord.Embed(colour=discord.Colour.blue()) + embed.title = "The available question categories are:" + embed.description = "" + for cat, description in self.categories.items(): + embed.description += f"**- {cat.capitalize()}**\n{description.capitalize()}\n" + embed.set_footer(text="If not category is chosen, then a random one will be selected.") + return embed + + async def send_question(self, channel): + """This function is to be called whenever a question needs to be sent.""" + await asyncio.sleep(2) + game = self.running_games[channel.id] + if game.unanswered_questions == self.inactivity_limit: + del self.running_games[channel.id] + return await channel.send("Game stopped due to inactivity.") + + category = game.category + category_dict = self.questions[category] + question_dict = random.choice(category_dict) + + same_question = True + + # Making sure a question is not repeated. + while same_question is True: + question_dict = random.choice(category_dict) + if question_dict["id"] not in game.done_questions: + same_question = False + + # Initial points for a question. + question_dict["points"] = 100 + game.question = question_dict + game.hints = 0 + + embed = discord.Embed(colour=discord.Colour.dark_gold()) + + question = question_dict["question"] + question_id = question_dict["id"] + + game.done_questions.append(question_id) + question_number = len(game.done_questions) + + embed.title = f"#{question_number} Question" + embed.description = question + embed.set_footer(text="A hint will be provided after every 10s if no one gives the right answer.Max of 2 hints") + + await channel.send(embed=embed) + await self.send_hint(channel, question_dict) + + @commands.Cog.listener() + async def on_message(self, message): + """A function triggered when a message is sent.""" + channel = message.channel + if channel.id not in self.running_games: + return + if message.author.bot: + return + + game = self.running_games[message.channel.id] + question_data = game.question + answer = question_data["answer"].lower() + user_answer = message.content.lower() + ratio = fuzz.ratio(answer, user_answer) + if ratio > 84: + points = question_data["points"] - game.hints*25 + if message.author in game.players: + author_index = game.players.index(message.author) + game.points[author_index] = game.points[author_index] + points + else: + game.players.append(message.author) + game.points.append(points) + + await channel.send(f"{message.author.mention} got it right! Good job :tada:" + f"You got {points} points.") + await self.send_score(channel) + await self.send_question(channel) + elif ratio in range(75, 84): + await channel.send(f"Your close to the answer {message.author.mention}") + + async def send_hint(self, channel, question_dict): + """Function to be called whenever a hint has to be sent.""" + await asyncio.sleep(10) + try: + game = self.running_games[channel.id] + except KeyError: + return + + # Checking if the question is the same after 10 seconds. + if question_dict["id"] == game.question["id"]: + + # If the max number of hints is already reached, then send the answer. + if 2 - game.hints == 0: + return await self.send_answer(channel) + + hint_list = question_dict["hints"] + hint_index = game.hints + hint = hint_list[hint_index] + game.hints += 1 + message = f"**Hint {game.hints}**: {hint}\n*Number of hints remaining: {2-game.hints}*" + await channel.send(message) + await self.send_hint(channel, question_dict) + + async def send_answer(self, channel): + """A function to send the answer in the channel if no user have given the correct answer even after 2 hints.""" + game = self.running_games[channel.id] + answer = game.question["answer"] + response = random.choice(wrong_ans_responses) + expression = random.choice(annoyed_expressions) + await channel.send(f"{response} {expression}, the correct answer is **{answer}**.") + self.running_games[channel.id].unanswered_questions += 1 + await self.send_score(channel) + await self.send_question(channel) + + @tquiz.command(name="score") + async def show_score(self, ctx): + """Show scoreboard of the game running in this channel.""" + await self.send_score(ctx.channel) + + async def send_score(self, channel): + """Show score of each player in the quiz.""" + if channel.id not in self.running_games: + return await channel.send("There are no games running in this channel!") + game = self.running_games[channel.id] + players = game.players + if len(players) == 0: + return + points = game.points + embed = discord.Embed(color=discord.Colour.dark_gold()) + embed.title = "Scoreboard" + embed.description = "" + for player, score in zip(players, points): + embed.description += f"{player} - {score}\n" + await channel.send(embed=embed) + + @tquiz.command(name="stop") + async def stop_quiz(self, ctx): + """Stop the quiz.""" + if ctx.channel.id not in self.running_games: + return await ctx.send("No game running, nothing to stop here -.-") + game = self.running_games[ctx.channel.id] + owner = game.owner + mods = Roles.moderator + if ctx.author.id == owner or mods in [role.id for role in ctx.author.roles]: + await ctx.send("Game is not running anymore!") + await self.send_score(ctx.channel) + if game.players: + highest_points = max(game.points) + + # Check if more than 1 player has highest points. + + if game.points.count(highest_points) > 1: + pass + else: + author_index = game.points.index(highest_points) + winner = game.players[author_index] + await ctx.send( + f"Congratz {winner.mention} :tada: " + f"You have won this quiz game with a grand total of {highest_points} points!!" + ) + await asyncio.sleep(2) + del self.running_games[ctx.channel.id] + else: + await ctx.send("You are not authorised to close this game!") + + +def setup(bot): + """Loading the cog.""" + bot.add_cog(TriviaQuiz(bot)) + logger.debug("TriviaQuiz cog loaded!") -- cgit v1.2.3 From 1d36074e7c2dd1b6e9acc52dfda96a728345f740 Mon Sep 17 00:00:00 2001 From: RohanJnr Date: Wed, 11 Sep 2019 22:28:27 +0530 Subject: using self.categories insted of list(self.categories.keys()) Pending work: - Function annotation - Announcement of multiple winners (if they have same points). --- bot/seasons/evergreen/trivia_quiz.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'bot') diff --git a/bot/seasons/evergreen/trivia_quiz.py b/bot/seasons/evergreen/trivia_quiz.py index dd4008d0..433a021d 100644 --- a/bot/seasons/evergreen/trivia_quiz.py +++ b/bot/seasons/evergreen/trivia_quiz.py @@ -79,11 +79,11 @@ class TriviaQuiz(commands.Cog): return await ctx.send("Game already running in this channel!") if category is None: - category = random.choice(list(self.categories.keys())) + category = random.choice(self.categories) else: category = category.lower() - if category not in self.categories.keys(): + if category not in self.categories: embed = self.category_embed() return await ctx.send(f"Category {category} does not exist!", embed=embed) -- cgit v1.2.3 From 207efa437e3b585250f7b36e66ab262a0acc3217 Mon Sep 17 00:00:00 2001 From: RohanJnr Date: Mon, 23 Sep 2019 19:00:32 +0530 Subject: Modified the code drastically for the quiz game: - Using a while loop to run a game rather than bunch of the functions calling each other. - using wait_for() to send hints, answers and to move to next questions. --- bot/resources/evergreen/trivia_quiz.json | 3 +- bot/seasons/evergreen/travia_quiz.py | 225 ++++++++++++++++++++++++++ bot/seasons/evergreen/trivia_quiz.py | 266 ------------------------------- 3 files changed, 227 insertions(+), 267 deletions(-) create mode 100644 bot/seasons/evergreen/travia_quiz.py delete mode 100644 bot/seasons/evergreen/trivia_quiz.py (limited to 'bot') diff --git a/bot/resources/evergreen/trivia_quiz.json b/bot/resources/evergreen/trivia_quiz.json index f884e67a..62856863 100644 --- a/bot/resources/evergreen/trivia_quiz.json +++ b/bot/resources/evergreen/trivia_quiz.json @@ -30,5 +30,6 @@ "question": "What was the first game Yoshi appeared in?", "answer": "Super Mario World" } - ] + ], + "general":[] } diff --git a/bot/seasons/evergreen/travia_quiz.py b/bot/seasons/evergreen/travia_quiz.py new file mode 100644 index 00000000..84a16654 --- /dev/null +++ b/bot/seasons/evergreen/travia_quiz.py @@ -0,0 +1,225 @@ +import asyncio +import json +import logging +import random +from pathlib import Path + +import discord +from discord.ext import commands +from fuzzywuzzy import fuzz + +from bot.constants import Roles + + +logger = logging.getLogger(__name__) + + +annoyed_expressions = ["-_-", "-.-"] + +wrong_ans_responses = [ + "No one gave the correct answer", + "Losers", + "You guys really need to learn" +] + +game_rules = [ + "No cheating!", + "Idk what rules to put in here haha." + +] + + +class TriviaQuiz(commands.Cog): + """A cog for all quiz commands.""" + + def __init__(self, bot): + self.bot = bot + self.questions = self.load_questions() + self.game_status = {} + self.game_owners = {} + self.question_limit = 3 + self.categories = { + "general": "Test your general knwoledge", + "retro": "Questions related to retro gaming." + } + + @staticmethod + def load_questions() -> dict: + """Load the questions from json file.""" + p = Path("bot", "resources", "evergreen", "trivia_quiz.json") + with p.open() as json_data: + questions = json.load(json_data) + return questions + + @commands.command(name="quiz") + async def start(self, ctx, option: str, category: str = "retro") -> None: + """ + Start/Stop a quiz! + + arguments: + option: + - start : to start a quiz in a channel + - stop : stop the quiz running in that channel. + + Questions for the quiz can be selected from the following categories: + - general : Test your general knowledge. (default) + - Retro : questions related to retro gaming. + """ + category = category.lower() + player_data = {} # a dict to store players and their points. + + if ctx.channel.id not in self.game_status: + self.game_status[ctx.channel.id] = None + + if option == "start": + if self.game_status[ctx.channel.id] is True: + return await ctx.send("Game already running.") + else: + self.game_owners[ctx.channel.id] = ctx.author + self.game_status[ctx.channel.id] = True + start_embed = discord.Embed(colour=discord.Colour.red()) + start_embed.title = "Quiz game Starting!!" + start_embed.description = "Each game consists of 5 questions.\n" + start_embed.description += "**Rules :**\n" + for rule in game_rules: + start_embed.description += f"- {rule}\n" + start_embed.set_footer(text="2 hints per question sent after every 10s") + await ctx.send(embed=start_embed) # send an embed with the rules + + elif option == "stop": + if self.game_status[ctx.channel.id] is False: + return await ctx.send("No game running, nothing to stop here.") + else: + if ( + ctx.author == self.game_owners[ctx.channel.id] or + Roles.moderator in [role.id for role in ctx.author.roles] + ): + await self.declare_winner(ctx.channel, player_data) + self.game_status[ctx.channel.id] = False + else: + await ctx.send(f"{ctx.author.mention}, you are not authorised to stop this game :ghost: !") + else: + self.game_status[ctx.channel.id] = False + return await ctx.send("start or stop only") + + unanswerd = 0 + done_question = [] + hint_no = 0 + answer = None + hints = None + while self.game_status[ctx.channel.id] is True: + if len(done_question) > self.question_limit and hint_no == 0: + await ctx.send("The round ends here.") + await self.declare_winner(ctx.channel, player_data) + break + if unanswerd > 3: + await ctx.send("Game stopped due to inactivity.") + await self.declare_winner(ctx.channel, player_data) + break + if category not in self.categories: + embed = self.category_embed + await ctx.send(embed=embed) + break + topic = self.questions[category] + if hint_no == 0: + while True: + question_dict = random.choice(topic) + if question_dict["id"] not in done_question: + done_question.append(question_dict["id"]) + break + q = question_dict["question"] + answer = question_dict["answer"] + hints = question_dict["hints"] + + embed = discord.Embed(colour=discord.Colour.gold()) + embed.title = f"Question #{len(done_question)}" + embed.description = q + await ctx.send(embed=embed) + + def check(m): + ratio = fuzz.ratio(answer.lower(), m.content) + return ratio > 80 and m.channel == ctx.channel + try: + msg = await self.bot.wait_for('message', check=check, timeout=10) + except Exception as e: + if self.game_status[ctx.channel.id] is False: + break + if isinstance(e, asyncio.TimeoutError): + if hint_no < 2: + await ctx.send(f"**Hint #{hint_no+1}\n**{hints[hint_no]}") + hint_no += 1 + else: + response = random.choice(wrong_ans_responses) + expression = random.choice(annoyed_expressions) + await ctx.send(f"{response} {expression}, the correct answer is **{answer}**.") + hint_no = 0 + unanswerd += 1 + await self.send_score(ctx.channel, player_data) + + else: + points = 100 - 25*hint_no + if msg.author in player_data: + player_data[msg.author] += points + else: + player_data[msg.author] = points + hint_no = 0 + unanswerd = 0 + await ctx.send(f"{msg.author.mention} got the correct answer :tada: {points} points for ya.") + await ctx.send(f"Correct answer is **{answer}**") + await self.send_score(ctx.channel, player_data) + + @staticmethod + async def send_score(channel, player_data): + """A function which sends the score.""" + embed = discord.Embed(colour=discord.Colour.blue()) + embed.title = "Score Board" + embed.description = "" + for k, v in player_data.items(): + embed.description += f"{k} : {v}\n" + await channel.send(embed=embed) + + @staticmethod + async def declare_winner(channel, player_data): + """A function declare the winner of the quiz.""" + + if player_data: + highest_points = max(list(player_data.values())) + no_of_winners = list(player_data.values()).count(highest_points) + + # Check if more than 1 player has highest points. + if no_of_winners > 1: + winners = [] + points_copy = list(player_data.values()).copy() + for _ in range(no_of_winners): + index = points_copy.index(highest_points) + winners.append(list(player_data.keys())[index]) + points_copy[index] = 0 + winners_mention = None + for winner in winners: + winners_mention += f"{winner.mention} " + + else: + author_index = list(player_data.values()).index(highest_points) + winner = list(player_data.keys())[author_index] + winners_mention = winner.mention + await channel.send( + f"Congratz {winners_mention} :tada: " + f"You have won this quiz game with a grand total of {highest_points} points!!" + ) + + @property + def category_embed(self) -> discord.Embed: + """A function which returns an embed showing all avilable categories.""" + embed = discord.Embed(colour=discord.Colour.blue()) + embed.title = "The available question categories are:" + embed.description = "" + for cat, description in self.categories.items(): + embed.description += f"**- {cat.capitalize()}**\n{description.capitalize()}\n" + embed.set_footer(text="If not category is chosen, then a random one will be selected.") + return embed + + +def setup(bot): + """Loading the cog.""" + bot.add_cog(TriviaQuiz(bot)) + logger.debug("TriviaQuiz cog loaded!") diff --git a/bot/seasons/evergreen/trivia_quiz.py b/bot/seasons/evergreen/trivia_quiz.py deleted file mode 100644 index 433a021d..00000000 --- a/bot/seasons/evergreen/trivia_quiz.py +++ /dev/null @@ -1,266 +0,0 @@ -import asyncio -import json -import logging -import random -from dataclasses import dataclass -from pathlib import Path - -import discord -from discord.ext import commands -from fuzzywuzzy import fuzz - -from bot.constants import Roles - - -logger = logging.getLogger(__name__) - - -annoyed_expressions = ["-_-", "-.-"] - -wrong_ans_responses = [ - "No one gave the correct answer", - "Losers", - "You guys really need to learn" -] - - -@dataclass -class GameData: - """A dataclass for game data.""" - - owner: int - players = [] - points = [] - done_questions = [] - category: str - question: dict = None - hints = 0 - unanswered_questions = 0 - - -class TriviaQuiz(commands.Cog): - """A cog for all quiz commands.""" - - def __init__(self, bot): - self.bot = bot - self.questions = self.load_questions() - self.running_games = {} # channel as key and value as instance of dataclass GameData - self.categories = { - "retro": "Questions related to retro gaming." - } - self.inactivity_limit = 3 # Number of questions unanswered in a row after which quiz stops. - - @staticmethod - def load_questions(): - """Load the questions from json file.""" - p = Path("bot", "resources", "evergreen", "trivia_quiz.json") - with p.open() as json_data: - questions = json.load(json_data) - return questions - - @commands.group(name="tquiz", invoke_without_command=True) - async def tquiz(self, ctx): - """Trivia Quiz game for fun!""" - await ctx.send_help("tquiz") - - @tquiz.command(name="start") - async def start(self, ctx, category=None): - """ - Start a quiz! - - Questions for the quiz can be selected from the following categories: - - Retro : questions related to retro gaming. - """ - await ctx.send("Quiz triggered! Gonna start in a couple of seconds...") - await asyncio.sleep(1) - - # Checking if there is already a game running in that channel. - if ctx.channel.id in self.running_games: - return await ctx.send("Game already running in this channel!") - - if category is None: - category = random.choice(self.categories) - - else: - category = category.lower() - if category not in self.categories: - embed = self.category_embed() - return await ctx.send(f"Category {category} does not exist!", embed=embed) - - self.running_games[ctx.channel.id] = GameData( - owner=ctx.author.id, - category=category - ) - - await self.send_question(ctx.channel) - - def category_embed(self): - """A function which returns an embed showing all avilable categories""" - embed = discord.Embed(colour=discord.Colour.blue()) - embed.title = "The available question categories are:" - embed.description = "" - for cat, description in self.categories.items(): - embed.description += f"**- {cat.capitalize()}**\n{description.capitalize()}\n" - embed.set_footer(text="If not category is chosen, then a random one will be selected.") - return embed - - async def send_question(self, channel): - """This function is to be called whenever a question needs to be sent.""" - await asyncio.sleep(2) - game = self.running_games[channel.id] - if game.unanswered_questions == self.inactivity_limit: - del self.running_games[channel.id] - return await channel.send("Game stopped due to inactivity.") - - category = game.category - category_dict = self.questions[category] - question_dict = random.choice(category_dict) - - same_question = True - - # Making sure a question is not repeated. - while same_question is True: - question_dict = random.choice(category_dict) - if question_dict["id"] not in game.done_questions: - same_question = False - - # Initial points for a question. - question_dict["points"] = 100 - game.question = question_dict - game.hints = 0 - - embed = discord.Embed(colour=discord.Colour.dark_gold()) - - question = question_dict["question"] - question_id = question_dict["id"] - - game.done_questions.append(question_id) - question_number = len(game.done_questions) - - embed.title = f"#{question_number} Question" - embed.description = question - embed.set_footer(text="A hint will be provided after every 10s if no one gives the right answer.Max of 2 hints") - - await channel.send(embed=embed) - await self.send_hint(channel, question_dict) - - @commands.Cog.listener() - async def on_message(self, message): - """A function triggered when a message is sent.""" - channel = message.channel - if channel.id not in self.running_games: - return - if message.author.bot: - return - - game = self.running_games[message.channel.id] - question_data = game.question - answer = question_data["answer"].lower() - user_answer = message.content.lower() - ratio = fuzz.ratio(answer, user_answer) - if ratio > 84: - points = question_data["points"] - game.hints*25 - if message.author in game.players: - author_index = game.players.index(message.author) - game.points[author_index] = game.points[author_index] + points - else: - game.players.append(message.author) - game.points.append(points) - - await channel.send(f"{message.author.mention} got it right! Good job :tada:" - f"You got {points} points.") - await self.send_score(channel) - await self.send_question(channel) - elif ratio in range(75, 84): - await channel.send(f"Your close to the answer {message.author.mention}") - - async def send_hint(self, channel, question_dict): - """Function to be called whenever a hint has to be sent.""" - await asyncio.sleep(10) - try: - game = self.running_games[channel.id] - except KeyError: - return - - # Checking if the question is the same after 10 seconds. - if question_dict["id"] == game.question["id"]: - - # If the max number of hints is already reached, then send the answer. - if 2 - game.hints == 0: - return await self.send_answer(channel) - - hint_list = question_dict["hints"] - hint_index = game.hints - hint = hint_list[hint_index] - game.hints += 1 - message = f"**Hint {game.hints}**: {hint}\n*Number of hints remaining: {2-game.hints}*" - await channel.send(message) - await self.send_hint(channel, question_dict) - - async def send_answer(self, channel): - """A function to send the answer in the channel if no user have given the correct answer even after 2 hints.""" - game = self.running_games[channel.id] - answer = game.question["answer"] - response = random.choice(wrong_ans_responses) - expression = random.choice(annoyed_expressions) - await channel.send(f"{response} {expression}, the correct answer is **{answer}**.") - self.running_games[channel.id].unanswered_questions += 1 - await self.send_score(channel) - await self.send_question(channel) - - @tquiz.command(name="score") - async def show_score(self, ctx): - """Show scoreboard of the game running in this channel.""" - await self.send_score(ctx.channel) - - async def send_score(self, channel): - """Show score of each player in the quiz.""" - if channel.id not in self.running_games: - return await channel.send("There are no games running in this channel!") - game = self.running_games[channel.id] - players = game.players - if len(players) == 0: - return - points = game.points - embed = discord.Embed(color=discord.Colour.dark_gold()) - embed.title = "Scoreboard" - embed.description = "" - for player, score in zip(players, points): - embed.description += f"{player} - {score}\n" - await channel.send(embed=embed) - - @tquiz.command(name="stop") - async def stop_quiz(self, ctx): - """Stop the quiz.""" - if ctx.channel.id not in self.running_games: - return await ctx.send("No game running, nothing to stop here -.-") - game = self.running_games[ctx.channel.id] - owner = game.owner - mods = Roles.moderator - if ctx.author.id == owner or mods in [role.id for role in ctx.author.roles]: - await ctx.send("Game is not running anymore!") - await self.send_score(ctx.channel) - if game.players: - highest_points = max(game.points) - - # Check if more than 1 player has highest points. - - if game.points.count(highest_points) > 1: - pass - else: - author_index = game.points.index(highest_points) - winner = game.players[author_index] - await ctx.send( - f"Congratz {winner.mention} :tada: " - f"You have won this quiz game with a grand total of {highest_points} points!!" - ) - await asyncio.sleep(2) - del self.running_games[ctx.channel.id] - else: - await ctx.send("You are not authorised to close this game!") - - -def setup(bot): - """Loading the cog.""" - bot.add_cog(TriviaQuiz(bot)) - logger.debug("TriviaQuiz cog loaded!") -- cgit v1.2.3 From 5a305fd588e0e07b308ad5ca68a19d25d7e1fe22 Mon Sep 17 00:00:00 2001 From: RohanJnr Date: Mon, 23 Sep 2019 19:07:08 +0530 Subject: corrected my spelling mistake on the file name --- bot/seasons/evergreen/travia_quiz.py | 225 ----------------------------------- bot/seasons/evergreen/trivia_quiz.py | 225 +++++++++++++++++++++++++++++++++++ 2 files changed, 225 insertions(+), 225 deletions(-) delete mode 100644 bot/seasons/evergreen/travia_quiz.py create mode 100644 bot/seasons/evergreen/trivia_quiz.py (limited to 'bot') diff --git a/bot/seasons/evergreen/travia_quiz.py b/bot/seasons/evergreen/travia_quiz.py deleted file mode 100644 index 84a16654..00000000 --- a/bot/seasons/evergreen/travia_quiz.py +++ /dev/null @@ -1,225 +0,0 @@ -import asyncio -import json -import logging -import random -from pathlib import Path - -import discord -from discord.ext import commands -from fuzzywuzzy import fuzz - -from bot.constants import Roles - - -logger = logging.getLogger(__name__) - - -annoyed_expressions = ["-_-", "-.-"] - -wrong_ans_responses = [ - "No one gave the correct answer", - "Losers", - "You guys really need to learn" -] - -game_rules = [ - "No cheating!", - "Idk what rules to put in here haha." - -] - - -class TriviaQuiz(commands.Cog): - """A cog for all quiz commands.""" - - def __init__(self, bot): - self.bot = bot - self.questions = self.load_questions() - self.game_status = {} - self.game_owners = {} - self.question_limit = 3 - self.categories = { - "general": "Test your general knwoledge", - "retro": "Questions related to retro gaming." - } - - @staticmethod - def load_questions() -> dict: - """Load the questions from json file.""" - p = Path("bot", "resources", "evergreen", "trivia_quiz.json") - with p.open() as json_data: - questions = json.load(json_data) - return questions - - @commands.command(name="quiz") - async def start(self, ctx, option: str, category: str = "retro") -> None: - """ - Start/Stop a quiz! - - arguments: - option: - - start : to start a quiz in a channel - - stop : stop the quiz running in that channel. - - Questions for the quiz can be selected from the following categories: - - general : Test your general knowledge. (default) - - Retro : questions related to retro gaming. - """ - category = category.lower() - player_data = {} # a dict to store players and their points. - - if ctx.channel.id not in self.game_status: - self.game_status[ctx.channel.id] = None - - if option == "start": - if self.game_status[ctx.channel.id] is True: - return await ctx.send("Game already running.") - else: - self.game_owners[ctx.channel.id] = ctx.author - self.game_status[ctx.channel.id] = True - start_embed = discord.Embed(colour=discord.Colour.red()) - start_embed.title = "Quiz game Starting!!" - start_embed.description = "Each game consists of 5 questions.\n" - start_embed.description += "**Rules :**\n" - for rule in game_rules: - start_embed.description += f"- {rule}\n" - start_embed.set_footer(text="2 hints per question sent after every 10s") - await ctx.send(embed=start_embed) # send an embed with the rules - - elif option == "stop": - if self.game_status[ctx.channel.id] is False: - return await ctx.send("No game running, nothing to stop here.") - else: - if ( - ctx.author == self.game_owners[ctx.channel.id] or - Roles.moderator in [role.id for role in ctx.author.roles] - ): - await self.declare_winner(ctx.channel, player_data) - self.game_status[ctx.channel.id] = False - else: - await ctx.send(f"{ctx.author.mention}, you are not authorised to stop this game :ghost: !") - else: - self.game_status[ctx.channel.id] = False - return await ctx.send("start or stop only") - - unanswerd = 0 - done_question = [] - hint_no = 0 - answer = None - hints = None - while self.game_status[ctx.channel.id] is True: - if len(done_question) > self.question_limit and hint_no == 0: - await ctx.send("The round ends here.") - await self.declare_winner(ctx.channel, player_data) - break - if unanswerd > 3: - await ctx.send("Game stopped due to inactivity.") - await self.declare_winner(ctx.channel, player_data) - break - if category not in self.categories: - embed = self.category_embed - await ctx.send(embed=embed) - break - topic = self.questions[category] - if hint_no == 0: - while True: - question_dict = random.choice(topic) - if question_dict["id"] not in done_question: - done_question.append(question_dict["id"]) - break - q = question_dict["question"] - answer = question_dict["answer"] - hints = question_dict["hints"] - - embed = discord.Embed(colour=discord.Colour.gold()) - embed.title = f"Question #{len(done_question)}" - embed.description = q - await ctx.send(embed=embed) - - def check(m): - ratio = fuzz.ratio(answer.lower(), m.content) - return ratio > 80 and m.channel == ctx.channel - try: - msg = await self.bot.wait_for('message', check=check, timeout=10) - except Exception as e: - if self.game_status[ctx.channel.id] is False: - break - if isinstance(e, asyncio.TimeoutError): - if hint_no < 2: - await ctx.send(f"**Hint #{hint_no+1}\n**{hints[hint_no]}") - hint_no += 1 - else: - response = random.choice(wrong_ans_responses) - expression = random.choice(annoyed_expressions) - await ctx.send(f"{response} {expression}, the correct answer is **{answer}**.") - hint_no = 0 - unanswerd += 1 - await self.send_score(ctx.channel, player_data) - - else: - points = 100 - 25*hint_no - if msg.author in player_data: - player_data[msg.author] += points - else: - player_data[msg.author] = points - hint_no = 0 - unanswerd = 0 - await ctx.send(f"{msg.author.mention} got the correct answer :tada: {points} points for ya.") - await ctx.send(f"Correct answer is **{answer}**") - await self.send_score(ctx.channel, player_data) - - @staticmethod - async def send_score(channel, player_data): - """A function which sends the score.""" - embed = discord.Embed(colour=discord.Colour.blue()) - embed.title = "Score Board" - embed.description = "" - for k, v in player_data.items(): - embed.description += f"{k} : {v}\n" - await channel.send(embed=embed) - - @staticmethod - async def declare_winner(channel, player_data): - """A function declare the winner of the quiz.""" - - if player_data: - highest_points = max(list(player_data.values())) - no_of_winners = list(player_data.values()).count(highest_points) - - # Check if more than 1 player has highest points. - if no_of_winners > 1: - winners = [] - points_copy = list(player_data.values()).copy() - for _ in range(no_of_winners): - index = points_copy.index(highest_points) - winners.append(list(player_data.keys())[index]) - points_copy[index] = 0 - winners_mention = None - for winner in winners: - winners_mention += f"{winner.mention} " - - else: - author_index = list(player_data.values()).index(highest_points) - winner = list(player_data.keys())[author_index] - winners_mention = winner.mention - await channel.send( - f"Congratz {winners_mention} :tada: " - f"You have won this quiz game with a grand total of {highest_points} points!!" - ) - - @property - def category_embed(self) -> discord.Embed: - """A function which returns an embed showing all avilable categories.""" - embed = discord.Embed(colour=discord.Colour.blue()) - embed.title = "The available question categories are:" - embed.description = "" - for cat, description in self.categories.items(): - embed.description += f"**- {cat.capitalize()}**\n{description.capitalize()}\n" - embed.set_footer(text="If not category is chosen, then a random one will be selected.") - return embed - - -def setup(bot): - """Loading the cog.""" - bot.add_cog(TriviaQuiz(bot)) - logger.debug("TriviaQuiz cog loaded!") diff --git a/bot/seasons/evergreen/trivia_quiz.py b/bot/seasons/evergreen/trivia_quiz.py new file mode 100644 index 00000000..84a16654 --- /dev/null +++ b/bot/seasons/evergreen/trivia_quiz.py @@ -0,0 +1,225 @@ +import asyncio +import json +import logging +import random +from pathlib import Path + +import discord +from discord.ext import commands +from fuzzywuzzy import fuzz + +from bot.constants import Roles + + +logger = logging.getLogger(__name__) + + +annoyed_expressions = ["-_-", "-.-"] + +wrong_ans_responses = [ + "No one gave the correct answer", + "Losers", + "You guys really need to learn" +] + +game_rules = [ + "No cheating!", + "Idk what rules to put in here haha." + +] + + +class TriviaQuiz(commands.Cog): + """A cog for all quiz commands.""" + + def __init__(self, bot): + self.bot = bot + self.questions = self.load_questions() + self.game_status = {} + self.game_owners = {} + self.question_limit = 3 + self.categories = { + "general": "Test your general knwoledge", + "retro": "Questions related to retro gaming." + } + + @staticmethod + def load_questions() -> dict: + """Load the questions from json file.""" + p = Path("bot", "resources", "evergreen", "trivia_quiz.json") + with p.open() as json_data: + questions = json.load(json_data) + return questions + + @commands.command(name="quiz") + async def start(self, ctx, option: str, category: str = "retro") -> None: + """ + Start/Stop a quiz! + + arguments: + option: + - start : to start a quiz in a channel + - stop : stop the quiz running in that channel. + + Questions for the quiz can be selected from the following categories: + - general : Test your general knowledge. (default) + - Retro : questions related to retro gaming. + """ + category = category.lower() + player_data = {} # a dict to store players and their points. + + if ctx.channel.id not in self.game_status: + self.game_status[ctx.channel.id] = None + + if option == "start": + if self.game_status[ctx.channel.id] is True: + return await ctx.send("Game already running.") + else: + self.game_owners[ctx.channel.id] = ctx.author + self.game_status[ctx.channel.id] = True + start_embed = discord.Embed(colour=discord.Colour.red()) + start_embed.title = "Quiz game Starting!!" + start_embed.description = "Each game consists of 5 questions.\n" + start_embed.description += "**Rules :**\n" + for rule in game_rules: + start_embed.description += f"- {rule}\n" + start_embed.set_footer(text="2 hints per question sent after every 10s") + await ctx.send(embed=start_embed) # send an embed with the rules + + elif option == "stop": + if self.game_status[ctx.channel.id] is False: + return await ctx.send("No game running, nothing to stop here.") + else: + if ( + ctx.author == self.game_owners[ctx.channel.id] or + Roles.moderator in [role.id for role in ctx.author.roles] + ): + await self.declare_winner(ctx.channel, player_data) + self.game_status[ctx.channel.id] = False + else: + await ctx.send(f"{ctx.author.mention}, you are not authorised to stop this game :ghost: !") + else: + self.game_status[ctx.channel.id] = False + return await ctx.send("start or stop only") + + unanswerd = 0 + done_question = [] + hint_no = 0 + answer = None + hints = None + while self.game_status[ctx.channel.id] is True: + if len(done_question) > self.question_limit and hint_no == 0: + await ctx.send("The round ends here.") + await self.declare_winner(ctx.channel, player_data) + break + if unanswerd > 3: + await ctx.send("Game stopped due to inactivity.") + await self.declare_winner(ctx.channel, player_data) + break + if category not in self.categories: + embed = self.category_embed + await ctx.send(embed=embed) + break + topic = self.questions[category] + if hint_no == 0: + while True: + question_dict = random.choice(topic) + if question_dict["id"] not in done_question: + done_question.append(question_dict["id"]) + break + q = question_dict["question"] + answer = question_dict["answer"] + hints = question_dict["hints"] + + embed = discord.Embed(colour=discord.Colour.gold()) + embed.title = f"Question #{len(done_question)}" + embed.description = q + await ctx.send(embed=embed) + + def check(m): + ratio = fuzz.ratio(answer.lower(), m.content) + return ratio > 80 and m.channel == ctx.channel + try: + msg = await self.bot.wait_for('message', check=check, timeout=10) + except Exception as e: + if self.game_status[ctx.channel.id] is False: + break + if isinstance(e, asyncio.TimeoutError): + if hint_no < 2: + await ctx.send(f"**Hint #{hint_no+1}\n**{hints[hint_no]}") + hint_no += 1 + else: + response = random.choice(wrong_ans_responses) + expression = random.choice(annoyed_expressions) + await ctx.send(f"{response} {expression}, the correct answer is **{answer}**.") + hint_no = 0 + unanswerd += 1 + await self.send_score(ctx.channel, player_data) + + else: + points = 100 - 25*hint_no + if msg.author in player_data: + player_data[msg.author] += points + else: + player_data[msg.author] = points + hint_no = 0 + unanswerd = 0 + await ctx.send(f"{msg.author.mention} got the correct answer :tada: {points} points for ya.") + await ctx.send(f"Correct answer is **{answer}**") + await self.send_score(ctx.channel, player_data) + + @staticmethod + async def send_score(channel, player_data): + """A function which sends the score.""" + embed = discord.Embed(colour=discord.Colour.blue()) + embed.title = "Score Board" + embed.description = "" + for k, v in player_data.items(): + embed.description += f"{k} : {v}\n" + await channel.send(embed=embed) + + @staticmethod + async def declare_winner(channel, player_data): + """A function declare the winner of the quiz.""" + + if player_data: + highest_points = max(list(player_data.values())) + no_of_winners = list(player_data.values()).count(highest_points) + + # Check if more than 1 player has highest points. + if no_of_winners > 1: + winners = [] + points_copy = list(player_data.values()).copy() + for _ in range(no_of_winners): + index = points_copy.index(highest_points) + winners.append(list(player_data.keys())[index]) + points_copy[index] = 0 + winners_mention = None + for winner in winners: + winners_mention += f"{winner.mention} " + + else: + author_index = list(player_data.values()).index(highest_points) + winner = list(player_data.keys())[author_index] + winners_mention = winner.mention + await channel.send( + f"Congratz {winners_mention} :tada: " + f"You have won this quiz game with a grand total of {highest_points} points!!" + ) + + @property + def category_embed(self) -> discord.Embed: + """A function which returns an embed showing all avilable categories.""" + embed = discord.Embed(colour=discord.Colour.blue()) + embed.title = "The available question categories are:" + embed.description = "" + for cat, description in self.categories.items(): + embed.description += f"**- {cat.capitalize()}**\n{description.capitalize()}\n" + embed.set_footer(text="If not category is chosen, then a random one will be selected.") + return embed + + +def setup(bot): + """Loading the cog.""" + bot.add_cog(TriviaQuiz(bot)) + logger.debug("TriviaQuiz cog loaded!") -- cgit v1.2.3 From 2fef382043c174d1d816f6b01be2c21bcc3a1ee3 Mon Sep 17 00:00:00 2001 From: RohanJnr Date: Mon, 23 Sep 2019 19:17:26 +0530 Subject: fixed linting errors --- bot/seasons/evergreen/trivia_quiz.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'bot') diff --git a/bot/seasons/evergreen/trivia_quiz.py b/bot/seasons/evergreen/trivia_quiz.py index 84a16654..5add953f 100644 --- a/bot/seasons/evergreen/trivia_quiz.py +++ b/bot/seasons/evergreen/trivia_quiz.py @@ -91,8 +91,8 @@ class TriviaQuiz(commands.Cog): return await ctx.send("No game running, nothing to stop here.") else: if ( - ctx.author == self.game_owners[ctx.channel.id] or - Roles.moderator in [role.id for role in ctx.author.roles] + ctx.author == self.game_owners[ctx.channel.id] + or Roles.moderator in [role.id for role in ctx.author.roles] ): await self.declare_winner(ctx.channel, player_data) self.game_status[ctx.channel.id] = False @@ -101,7 +101,7 @@ class TriviaQuiz(commands.Cog): else: self.game_status[ctx.channel.id] = False return await ctx.send("start or stop only") - + unanswerd = 0 done_question = [] hint_no = 0 @@ -181,7 +181,6 @@ class TriviaQuiz(commands.Cog): @staticmethod async def declare_winner(channel, player_data): """A function declare the winner of the quiz.""" - if player_data: highest_points = max(list(player_data.values())) no_of_winners = list(player_data.values()).count(highest_points) -- cgit v1.2.3 From 996218ff75c7ad3c9d0cef4541bbaba21c972646 Mon Sep 17 00:00:00 2001 From: RohanJnr Date: Mon, 23 Sep 2019 19:26:03 +0530 Subject: added function annotations --- bot/seasons/evergreen/trivia_quiz.py | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) (limited to 'bot') diff --git a/bot/seasons/evergreen/trivia_quiz.py b/bot/seasons/evergreen/trivia_quiz.py index 5add953f..0463947f 100644 --- a/bot/seasons/evergreen/trivia_quiz.py +++ b/bot/seasons/evergreen/trivia_quiz.py @@ -32,7 +32,8 @@ game_rules = [ class TriviaQuiz(commands.Cog): """A cog for all quiz commands.""" - def __init__(self, bot): + def __init__(self, bot: commands.Bot) -> None: + print(type(bot)) self.bot = bot self.questions = self.load_questions() self.game_status = {} @@ -52,7 +53,7 @@ class TriviaQuiz(commands.Cog): return questions @commands.command(name="quiz") - async def start(self, ctx, option: str, category: str = "retro") -> None: + async def start(self, ctx: commands.Context, option: str, category: str = "retro") -> None: """ Start/Stop a quiz! @@ -73,7 +74,8 @@ class TriviaQuiz(commands.Cog): if option == "start": if self.game_status[ctx.channel.id] is True: - return await ctx.send("Game already running.") + await ctx.send("Game already running.") + return else: self.game_owners[ctx.channel.id] = ctx.author self.game_status[ctx.channel.id] = True @@ -88,7 +90,8 @@ class TriviaQuiz(commands.Cog): elif option == "stop": if self.game_status[ctx.channel.id] is False: - return await ctx.send("No game running, nothing to stop here.") + await ctx.send("No game running, nothing to stop here.") + return else: if ( ctx.author == self.game_owners[ctx.channel.id] @@ -100,7 +103,8 @@ class TriviaQuiz(commands.Cog): await ctx.send(f"{ctx.author.mention}, you are not authorised to stop this game :ghost: !") else: self.game_status[ctx.channel.id] = False - return await ctx.send("start or stop only") + await ctx.send("start or stop only") + return unanswerd = 0 done_question = [] @@ -169,7 +173,7 @@ class TriviaQuiz(commands.Cog): await self.send_score(ctx.channel, player_data) @staticmethod - async def send_score(channel, player_data): + async def send_score(channel: discord.TextChannel, player_data: dict) -> None: """A function which sends the score.""" embed = discord.Embed(colour=discord.Colour.blue()) embed.title = "Score Board" @@ -179,7 +183,7 @@ class TriviaQuiz(commands.Cog): await channel.send(embed=embed) @staticmethod - async def declare_winner(channel, player_data): + async def declare_winner(channel: discord.TextChannel, player_data: dict) -> None: """A function declare the winner of the quiz.""" if player_data: highest_points = max(list(player_data.values())) @@ -218,7 +222,7 @@ class TriviaQuiz(commands.Cog): return embed -def setup(bot): +def setup(bot: commands.Bot) -> None: """Loading the cog.""" bot.add_cog(TriviaQuiz(bot)) logger.debug("TriviaQuiz cog loaded!") -- cgit v1.2.3 From 5ab692def42e065b6f82c9cf759c79d20f42a289 Mon Sep 17 00:00:00 2001 From: RohanJnr Date: Mon, 23 Sep 2019 22:36:33 +0530 Subject: made the request changes which involves fixing some grammer, following PEP8 format, removed a debug statement and also some minor stuff. --- bot/seasons/evergreen/trivia_quiz.py | 46 +++++++++++++----------------------- 1 file changed, 17 insertions(+), 29 deletions(-) (limited to 'bot') diff --git a/bot/seasons/evergreen/trivia_quiz.py b/bot/seasons/evergreen/trivia_quiz.py index 0463947f..6bae97e0 100644 --- a/bot/seasons/evergreen/trivia_quiz.py +++ b/bot/seasons/evergreen/trivia_quiz.py @@ -14,18 +14,11 @@ from bot.constants import Roles logger = logging.getLogger(__name__) -annoyed_expressions = ["-_-", "-.-"] +ANNOYED_EXPRESSIONS = ["-_-", "-.-"] -wrong_ans_responses = [ +WRONG_ANS_RESPONSE = [ "No one gave the correct answer", - "Losers", - "You guys really need to learn" -] - -game_rules = [ - "No cheating!", - "Idk what rules to put in here haha." - + "Better luck next time" ] @@ -33,7 +26,6 @@ class TriviaQuiz(commands.Cog): """A cog for all quiz commands.""" def __init__(self, bot: commands.Bot) -> None: - print(type(bot)) self.bot = bot self.questions = self.load_questions() self.game_status = {} @@ -53,7 +45,7 @@ class TriviaQuiz(commands.Cog): return questions @commands.command(name="quiz") - async def start(self, ctx: commands.Context, option: str, category: str = "retro") -> None: + async def start(self, ctx: commands.Context, option: str, category: str = "general") -> None: """ Start/Stop a quiz! @@ -82,9 +74,7 @@ class TriviaQuiz(commands.Cog): start_embed = discord.Embed(colour=discord.Colour.red()) start_embed.title = "Quiz game Starting!!" start_embed.description = "Each game consists of 5 questions.\n" - start_embed.description += "**Rules :**\n" - for rule in game_rules: - start_embed.description += f"- {rule}\n" + start_embed.description += "**Rules :**\nNo cheating and have fun!" start_embed.set_footer(text="2 hints per question sent after every 10s") await ctx.send(embed=start_embed) # send an embed with the rules @@ -99,14 +89,17 @@ class TriviaQuiz(commands.Cog): ): await self.declare_winner(ctx.channel, player_data) self.game_status[ctx.channel.id] = False + del self.game_owners[ctx.channel.id] else: await ctx.send(f"{ctx.author.mention}, you are not authorised to stop this game :ghost: !") - else: - self.game_status[ctx.channel.id] = False - await ctx.send("start or stop only") + + if category not in self.categories: + embed = self.category_embed + await ctx.send(embed=embed) return + topic = self.questions[category] - unanswerd = 0 + unanswered = 0 done_question = [] hint_no = 0 answer = None @@ -116,15 +109,10 @@ class TriviaQuiz(commands.Cog): await ctx.send("The round ends here.") await self.declare_winner(ctx.channel, player_data) break - if unanswerd > 3: + if unanswered > 3: await ctx.send("Game stopped due to inactivity.") await self.declare_winner(ctx.channel, player_data) break - if category not in self.categories: - embed = self.category_embed - await ctx.send(embed=embed) - break - topic = self.questions[category] if hint_no == 0: while True: question_dict = random.choice(topic) @@ -153,11 +141,11 @@ class TriviaQuiz(commands.Cog): await ctx.send(f"**Hint #{hint_no+1}\n**{hints[hint_no]}") hint_no += 1 else: - response = random.choice(wrong_ans_responses) - expression = random.choice(annoyed_expressions) + response = random.choice(WRONG_ANS_RESPONSE) + expression = random.choice(ANNOYED_EXPRESSIONS) await ctx.send(f"{response} {expression}, the correct answer is **{answer}**.") hint_no = 0 - unanswerd += 1 + unanswered += 1 await self.send_score(ctx.channel, player_data) else: @@ -167,7 +155,7 @@ class TriviaQuiz(commands.Cog): else: player_data[msg.author] = points hint_no = 0 - unanswerd = 0 + unanswered = 0 await ctx.send(f"{msg.author.mention} got the correct answer :tada: {points} points for ya.") await ctx.send(f"Correct answer is **{answer}**") await self.send_score(ctx.channel, player_data) -- cgit v1.2.3 From ec6c749ba9334c39b6ad78de048f9020379e64d0 Mon Sep 17 00:00:00 2001 From: RohanJnr Date: Mon, 30 Sep 2019 00:07:16 +0530 Subject: added some questions to general, for now users can only access general category questions.I have disabled hints for general(cant make up any hints).The score is now calculated on time based answer.I am also sending information about the topic/thing on which the question has been asked.Will add more questions in a couple of days --- bot/resources/evergreen/trivia_quiz.json | 130 ++++++++++++++++++++++++++++++- bot/seasons/evergreen/trivia_quiz.py | 42 +++++++--- 2 files changed, 161 insertions(+), 11 deletions(-) (limited to 'bot') diff --git a/bot/resources/evergreen/trivia_quiz.json b/bot/resources/evergreen/trivia_quiz.json index 62856863..ac74c09b 100644 --- a/bot/resources/evergreen/trivia_quiz.json +++ b/bot/resources/evergreen/trivia_quiz.json @@ -31,5 +31,133 @@ "answer": "Super Mario World" } ], - "general":[] + "general":[ + { + "id": 100, + "question": "Name the land of thousand lakes", + "answer": "Finland", + "info": "Finland is a country in Northern Europe. Sweden borders it to the northwest, Estonia to the south, Russia to the east, and Norway to the north. Finland is part of the European Union with its capital city being Helsinki. With a population of 5.5 million people, it has over 187,000 lakes. The thousands of lakes in Finland are the reason why the country's nickname is “the land of a thousand lakes." + }, + { + "id": 101, + "question": "Winner of FIFA 2018", + "answer": "France", + "info": "France 4 - 2 Croatia" + }, + { + "id": 102, + "question": "Remind me the largest Ocean in the world.", + "answer": "Pacific", + "info": "The Pacific Ocean is the largest and deepest of the world ocean basins. Covering approximately 63 million square miles and containing more than half of the free water on Earth, the Pacific is by far the largest of the world's ocean basins." + }, + { + "id": 103, + "question": "Have you heard of The Statue Of Liberty ? Who gifted it?", + "answer": "French", + "info": "The Statue of Liberty was a gift from the French people commemorating the alliance of France and the United States during the American Revolution. Yet, it represented much more to those individuals who proposed the gift. A photograph of Edouard de Laboulaye from the Galerie Contemporaine collection." + }, + { + "id": 104, + "question": "Land Of The Rising Sun?", + "answer": "Japan", + "info": "According to the words of the Japanese envoy himself, that name was chosen because the country was so close to where the sun rises. In any event, the name stuck, and for the last 1400 years or so, the world has referred to Japan as Nippon, the land of the rising sun." + }, + { + "id": 105, + "question": "Is there a play ground in Europe ?Name the Play Ground of Europe", + "answer": "SWITZERLAND", + "info": "It comes from the title of a book written in 1870 by Leslie Stephen (father of Virginia Woolf) detailing his exploits of mountain climbing (not skiing) of which sport he was one of the pioneers and trekking or walking." + }, + { + "id": 106, + "question": "Have you been struck by Thunder ? If not your very lucky but this place has gone through lot of large violent thunderstorms, called the Land Of Thunderbolt, name it.", + "answer": "Bhutan", + "info": "Bhutan is called Land of Thunder Dragon. Because of the violent and large thunderstorms that whip down through the valleys from the Himalayas, Bhutan is known as the Land of Thunderbolt. The sparkling light of thunderbolts were believed to be red fire of a dragon." + }, + { + "id": 107, + "question": "Largest producer of tea in the world?", + "answer": "China", + "info": "Tea is mainly grown in Asia, Africa, South America, and around the Black and Caspian Seas. The four biggest tea-producing countries today are China, India, Sri Lanka and Kenya. Together they represent 75% of world production." + }, + { + "id": 108, + "question": "Remind me the largest producer of Coffee ?", + "answer": "Brazil", + "info": "Brazil is the world's largest coffee producer. In 2016, Brazil produced a staggering 2,595,000 metric tons of coffee beans. It is not a new development, as Brazil has been the highest global producer of coffee beans for over 150 years." + }, + { + "id": 109, + "question": "Mount Etna, one of the active volcano, where is it located?", + "answer": "Italy", + "info": "Mount Etna is the highest and most active volcano in Europe. Towering above the city of Catania on the island of Sicily, it has been growing for about 500,000 years and is in the midst of a series of eruptions that began in 2001.It is also possible to visit Mount Etna independently, but the advantages of a guided excursion are very numerous. Mount Etna is on of the highest volcano in Europe and on of the most active in the world. The volcano shaped the Sicilian history and landscape and still affects the island today." + }, + { + "id": 110, + "question": "Which country is called Battleground of Europe?", + "answer": "Belgium", + "info": "Belgium has been the battleground of Europe since the Roman Empire… Belgium was the battleground of Europe for centuries as it had no natural protection from its big neighboring countries. ... The battles of Oudenaarde, Ramillies, Waterloo, Ypres and Bastogne were all fought on Belgian soil." + }, + { + "id": 111, + "question": "Largest tropical rain forest in the world?", + "answer": "Amazon", + "info": "The Amazon is regarded as vital in the fight against global warming due to its ability to absorb carbon from the air. It's often referred to as the “lungs of the Earth,” as more than 20 per cent of the world's oxygen is produced there." + }, + { + "id": 112, + "question": "Do you know the biggest Island in the World ?", + "answer": "Greenland", + "info": "" + }, + { + "id": 113, + "question": "Give me the name of the tallest waterfall in the world.", + "answer": "Angel", + "info": "Angel Falls (Salto Ángel) in Venezuela is the highest waterfall in the world. The falls are 3230 feet in height, with an uninterrupted drop of 2647 feet. Angel Falls is located on a tributary of the Rio Caroni." + }, + { + "id": 114, + "question": "Have you seen white elephants? If not then there is a place called Land of White Elephants, does anyone know the place?", + "answer": "Thailand", + "info": "White elephants were regarded to be holy creatures in ancient Thailand and some other countries. Today, white elephants are still used as a symbol of divine and royal power in the country. Ownership of a white elephant symbolizes wealth, success, royalty, political power, wisdom, and prosperity." + }, + { + "id": 115, + "question": "How many continents have you been to? Maybe you can visit 2 at once, name the city of two continents.", + "answer": "Istanbul", + "info": "Istanbul embraces two continents, one arm reaching out to Asia, the other to Europe." + }, + { + "id": 116, + "question": "the Vally Of The Kings is located in the country...?", + "answer": "Egypt", + "info": "The Valley of the Kings, also known as the Valley of the Gates of the Kings, is a valley in Egypt where, for a period of nearly 500 years from the 16th to 11th century BC, rock cut tombs were excavated for the pharaohs and powerful nobles of the New Kingdom (the Eighteenth to the Twentieth Dynasties of Ancient Egypt)." + }, + { + "id": 117, + "question": "Diamonds are always nice in Minecraft, but did you know that there is a \"Diamond Capital in the World?\" can anyone name it?", + "answer": "Antwerp", + "info": "Antwerp, Belgium is where 60-80% of the world's diamonds are cut and traded, and is known as the \"Diamond Capital of the World.\"" + }, + { + "id": 118, + "question": "Where is the \"International Court Of Justice\" located at?", + "answer": "Hague", + "info": "" + }, + { + "id": 119, + "question": "In which country is Bali located in?", + "answer": "Indonesia", + "info": "" + }, + { + "id": 120, + "question": "The world's largest coral reef system \"Great Barrier Reef\" is located in?", + "answer": "Australia", + "info": "The Great Barrier Reef is the world's largest coral reef system composed of over 2,900 individual reefs and 900 islands stretching for over 2,300 kilometres (1,400 mi) over an area of approximately 344,400 square kilometres (133,000 sq mi). The reef is located in the Coral Sea, off the coast of Queensland, Australia." + } + + ] } diff --git a/bot/seasons/evergreen/trivia_quiz.py b/bot/seasons/evergreen/trivia_quiz.py index 6bae97e0..b4f47482 100644 --- a/bot/seasons/evergreen/trivia_quiz.py +++ b/bot/seasons/evergreen/trivia_quiz.py @@ -32,8 +32,8 @@ class TriviaQuiz(commands.Cog): self.game_owners = {} self.question_limit = 3 self.categories = { - "general": "Test your general knwoledge", - "retro": "Questions related to retro gaming." + "general": "Test your general knwoledge" + # "retro": "Questions related to retro gaming." } @staticmethod @@ -45,7 +45,7 @@ class TriviaQuiz(commands.Cog): return questions @commands.command(name="quiz") - async def start(self, ctx: commands.Context, option: str, category: str = "general") -> None: + async def quiz_game(self, ctx: commands.Context, option: str, category: str = "general") -> None: """ Start/Stop a quiz! @@ -56,7 +56,7 @@ class TriviaQuiz(commands.Cog): Questions for the quiz can be selected from the following categories: - general : Test your general knowledge. (default) - - Retro : questions related to retro gaming. + (we wil be adding more later) """ category = category.lower() player_data = {} # a dict to store players and their points. @@ -75,8 +75,11 @@ class TriviaQuiz(commands.Cog): start_embed.title = "Quiz game Starting!!" start_embed.description = "Each game consists of 5 questions.\n" start_embed.description += "**Rules :**\nNo cheating and have fun!" - start_embed.set_footer(text="2 hints per question sent after every 10s") + start_embed.set_footer( + text="Points for that question reduces by 25 after 10s.Total time is 30s per question" + ) await ctx.send(embed=start_embed) # send an embed with the rules + await asyncio.sleep(1) elif option == "stop": if self.game_status[ctx.channel.id] is False: @@ -121,7 +124,6 @@ class TriviaQuiz(commands.Cog): break q = question_dict["question"] answer = question_dict["answer"] - hints = question_dict["hints"] embed = discord.Embed(colour=discord.Colour.gold()) embed.title = f"Question #{len(done_question)}" @@ -129,7 +131,7 @@ class TriviaQuiz(commands.Cog): await ctx.send(embed=embed) def check(m): - ratio = fuzz.ratio(answer.lower(), m.content) + ratio = fuzz.ratio(answer.lower(), m.content.lower()) return ratio > 80 and m.channel == ctx.channel try: msg = await self.bot.wait_for('message', check=check, timeout=10) @@ -138,12 +140,19 @@ class TriviaQuiz(commands.Cog): break if isinstance(e, asyncio.TimeoutError): if hint_no < 2: - await ctx.send(f"**Hint #{hint_no+1}\n**{hints[hint_no]}") hint_no += 1 + if "hints" in question_dict: + hints = question_dict["hints"] + await ctx.send(f"**Hint #{hint_no+1}\n**{hints[hint_no]}") + else: + await ctx.send(f"Cmon guys, {30-hint_no*10}s left!") + else: response = random.choice(WRONG_ANS_RESPONSE) expression = random.choice(ANNOYED_EXPRESSIONS) - await ctx.send(f"{response} {expression}, the correct answer is **{answer}**.") + await ctx.send(f"{response} {expression}") + await self.send_answer(ctx.channel, question_dict) + await asyncio.sleep(1) hint_no = 0 unanswered += 1 await self.send_score(ctx.channel, player_data) @@ -157,7 +166,7 @@ class TriviaQuiz(commands.Cog): hint_no = 0 unanswered = 0 await ctx.send(f"{msg.author.mention} got the correct answer :tada: {points} points for ya.") - await ctx.send(f"Correct answer is **{answer}**") + await self.send_answer(ctx.channel, question_dict) await self.send_score(ctx.channel, player_data) @staticmethod @@ -209,6 +218,19 @@ class TriviaQuiz(commands.Cog): embed.set_footer(text="If not category is chosen, then a random one will be selected.") return embed + @staticmethod + async def send_answer(channel: discord.TextChannel, question_dict: dict) -> None: + """A function that sends the answer.""" + answer = question_dict["answer"] + info = question_dict["info"] + embed = discord.Embed(color=discord.Colour.red()) + embed.title = f"The correct answer is **{answer}**\n" + embed.description = "" + if info != "": + embed.description += f"**Information**\n{info}\n" + embed.description += "Lets move to the next question." + await channel.send(embed=embed) + def setup(bot: commands.Bot) -> None: """Loading the cog.""" -- cgit v1.2.3 From 8c82fd5c03b62f2d35cf6b0e2945e332a5b02bc3 Mon Sep 17 00:00:00 2001 From: vivax3794 <51753506+vivax3794@users.noreply.github.com> Date: Tue, 1 Oct 2019 01:16:01 +0200 Subject: added hacktober-issue-finder cog. --- bot/seasons/halloween/hacktober-issue-finder.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 bot/seasons/halloween/hacktober-issue-finder.py (limited to 'bot') diff --git a/bot/seasons/halloween/hacktober-issue-finder.py b/bot/seasons/halloween/hacktober-issue-finder.py new file mode 100644 index 00000000..ce0993d3 --- /dev/null +++ b/bot/seasons/halloween/hacktober-issue-finder.py @@ -0,0 +1,18 @@ +import logging + +from discord.ext import commands + +log = logging.getLogger(__name__) + + +class SpookyEightBall(commands.Cog): + """Find a random hacktober python issue on GitHub.""" + + def __init__(self, bot: commands.Bot): + self.bot = bot + + +def setup(bot: commands.Bot) -> None: + """Hacktober issue finder Cog Load.""" + bot.add_cog(SpookyEightBall(bot)) + log.info("hacktober-issue-finder cog loaded") -- cgit v1.2.3 From ae4eb13f93c9b7e5465fe9b3a91f093f1c6d1bac Mon Sep 17 00:00:00 2001 From: vivax3794 <51753506+vivax3794@users.noreply.github.com> Date: Tue, 1 Oct 2019 02:45:48 +0200 Subject: get issue data --- bot/seasons/halloween/hacktober-issue-finder.py | 39 +++++++++++++++++++++++-- 1 file changed, 37 insertions(+), 2 deletions(-) (limited to 'bot') diff --git a/bot/seasons/halloween/hacktober-issue-finder.py b/bot/seasons/halloween/hacktober-issue-finder.py index ce0993d3..17eec95a 100644 --- a/bot/seasons/halloween/hacktober-issue-finder.py +++ b/bot/seasons/halloween/hacktober-issue-finder.py @@ -1,18 +1,53 @@ +import datetime import logging +from typing import Dict, List +import aiohttp from discord.ext import commands log = logging.getLogger(__name__) +URL = "https://api.github.com/search/issues" +HEADERS = {"Accept": "application / vnd.github.v3 + json"} +SEARCH = "label:hacktoberfest+language:python+state:open" -class SpookyEightBall(commands.Cog): + +class HacktoberIssues(commands.Cog): """Find a random hacktober python issue on GitHub.""" def __init__(self, bot: commands.Bot): self.bot = bot + self.cache = None + self.cache_timer = datetime.datetime(1, 1, 1) + + @commands.command() + async def hacktoberissues(self, ctx: commands.Context) -> None: + """Get a random python hacktober issue from Github.""" + with ctx.typing(): + data = await self.get_issues(ctx) + print("need to use data somehow to commit...", data) + + async def get_issues(self, ctx: commands.Context) -> List[Dict]: + """Get a list of the python issues with the label 'hacktoberfest' from the Github api.""" + if (ctx.message.created_at - self.cache_timer).seconds <= 60: + return self.cache + + async with aiohttp.ClientSession() as session: + # text = TEXT # + "+label:hacktober" + params = { + "q": SEARCH + } + async with session.get(URL, headers=HEADERS, params=params) as response: + if response.status != 200: + await ctx.send(f"ERROR: expected 200 status (got {response.status}) from the GitHub api.") + await ctx.send(await response.text()) + data = (await response.json())["items"] + self.cache = data + self.cache_timer = ctx.message.created_at + return data def setup(bot: commands.Bot) -> None: """Hacktober issue finder Cog Load.""" - bot.add_cog(SpookyEightBall(bot)) + bot.add_cog(HacktoberIssues(bot)) log.info("hacktober-issue-finder cog loaded") -- cgit v1.2.3 From 3b6183a51ceba9f8475760e4bcd921206181bd64 Mon Sep 17 00:00:00 2001 From: RohanJnr Date: Tue, 1 Oct 2019 10:43:15 +0530 Subject: added 10 more questions --- bot/resources/evergreen/trivia_quiz.json | 90 ++++++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) (limited to 'bot') diff --git a/bot/resources/evergreen/trivia_quiz.json b/bot/resources/evergreen/trivia_quiz.json index ac74c09b..9c3259cd 100644 --- a/bot/resources/evergreen/trivia_quiz.json +++ b/bot/resources/evergreen/trivia_quiz.json @@ -157,6 +157,96 @@ "question": "The world's largest coral reef system \"Great Barrier Reef\" is located in?", "answer": "Australia", "info": "The Great Barrier Reef is the world's largest coral reef system composed of over 2,900 individual reefs and 900 islands stretching for over 2,300 kilometres (1,400 mi) over an area of approximately 344,400 square kilometres (133,000 sq mi). The reef is located in the Coral Sea, off the coast of Queensland, Australia." + }, + { + "id": 121, + "question": "When did the First World War start?", + "answer": "1914", + "info": "The first world war began in August 1914. It was directly triggered by the assassination of the Austrian archduke, Franz Ferdinand and his wife, on 28th June 1914 by Bosnian revolutionary, Gavrilo Princip. This event was, however, simply the trigger that set off declarations of war." + }, + { + "id": 122, + "question": "Which is the only mammal that can’t jump?", + "answer": "elephant", + "info": "It is true that adult elephants can't jump. But there are other mammals that can't either, like sloths, hippos and rhinos. Although, unlike elephants, hippos and rhinos can have all four feet off the ground at the same time when they run." + + }, + { + "id": 123, + "question": "Who lived at 221B, Baker Street, London?", + "answer": "Sherlock Holmes", + "info": "You guys know this very well, xD." + + }, + { + "id": 124, + "question": "When did the Second World War end?", + "answer": "1945", + "info": "World War 2 ended with the unconditional surrender of the Axis powers. On 8 May 1945, the Allies accepted Germany's surrender, about a week after Adolf Hitler had committed suicide. VE Day – Victory in Europe celebrates the end of the Second World War on 8 May 1945." + + }, + { + "id": 125, + "question": "Name the largest Dam in the World", + "answer": "Three Gorges Dam", + "info": "At 1.4 miles wide (2.3 kilometers) and 630 feet (192 meters) high, Three Gorges Dam is the largest hydroelectric dam in the world, according to International Water Power & Dam Construction magazine. Three Gorges impounds the Yangtze River about 1,000 miles (1,610 km) west of Shanghai." + + }, + { + "id": 126, + "question": "Name the largest river in the World.", + "answer": "Nile", + "info": "The Nile, which is about 6,650 km (4,130 mi) long, is an \"international\" river as its drainage basin covers eleven countries, namely, Tanzania, Uganda, Rwanda, Burundi, the Democratic Republic of the Congo, Kenya, Ethiopia, Eritrea, South Sudan, Republic of the Sudan and Egypt." + + }, + { + "id": 127, + "question": "Which is the smallest planet in the Solar System? Earth?", + "answer": "Mercury", + "info": "Mercury is the smallest planet in our solar system. It's just a little bigger than Earth's moon. It is the closest planet to the sun, but it's actually not the hottest. Venus is hotter." + + }, + { + "id": 128, + "question": "Is your country the smallest? Well it is if it is this perticular place, name the smallest country.", + "answer": "Vatican city", + "info": "With an area of 0.17 square miles (0.44 km2) and a population right around 1,000, Vatican City is the smallest country in the world, both in terms of size and population." + + }, + { + "id": 129, + "question": "Have you seen the largest bird? If so then name it.", + "answer": "Ostrich", + "info": "The largest living bird, a member of the Struthioniformes, is the ostrich (Struthio camelus), from the plains of Africa and Arabia. A large male ostrich can reach a height of 2.8 metres (9.2 feet) and weigh over 156 kilograms (344 pounds)." + + }, + { + "id": 130, + "question": "Expand GPRS", + "answer": "General Packet Radio Service", + "info": "General Packet Radio Service (GPRS) is a packet-based mobile data service on the global system for mobile communications (GSM) of 3G and 2G cellular communication systems. It is a non-voice, high-speed and useful packet-switching technology intended for GSM networks." + + }, + { + "id": 120, + "question": "", + "answer": "", + "info": "" + + }, + { + "id": 120, + "question": "", + "answer": "", + "info": "" + + }, + { + "id": 120, + "question": "", + "answer": "", + "info": "" + } ] -- cgit v1.2.3 From 47995d3c233c1203c26e75571cdf0cc914821d14 Mon Sep 17 00:00:00 2001 From: RohanJnr Date: Tue, 1 Oct 2019 10:49:21 +0530 Subject: added function annotations to the check method --- bot/seasons/evergreen/trivia_quiz.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'bot') diff --git a/bot/seasons/evergreen/trivia_quiz.py b/bot/seasons/evergreen/trivia_quiz.py index b4f47482..ac72ed95 100644 --- a/bot/seasons/evergreen/trivia_quiz.py +++ b/bot/seasons/evergreen/trivia_quiz.py @@ -130,7 +130,7 @@ class TriviaQuiz(commands.Cog): embed.description = q await ctx.send(embed=embed) - def check(m): + def check(m: discord.Message) -> bool: ratio = fuzz.ratio(answer.lower(), m.content.lower()) return ratio > 80 and m.channel == ctx.channel try: -- cgit v1.2.3 From dce5b70e15b089ea661c12db120223f50f83ad74 Mon Sep 17 00:00:00 2001 From: Will Da Silva Date: Tue, 1 Oct 2019 15:02:21 -0400 Subject: Add drag queen names The names are stored in a text file, since they're basically just a list, and json seems like overkill for this case. In any case switching over to json later would be easy. The names could be separated into first and last names in order to generate more combinations, but that would break the wordplay that many of the names have. The names were taken from https://www.fantasynamegenerators.com/drag-queen-names.php as permitted by the footnote on the page. --- bot/resources/pride/drag_queen_names.txt | 248 +++++++++++++++++++++++++++++++ 1 file changed, 248 insertions(+) create mode 100644 bot/resources/pride/drag_queen_names.txt (limited to 'bot') diff --git a/bot/resources/pride/drag_queen_names.txt b/bot/resources/pride/drag_queen_names.txt new file mode 100644 index 00000000..1701b760 --- /dev/null +++ b/bot/resources/pride/drag_queen_names.txt @@ -0,0 +1,248 @@ +Adelle Lectible +Adelle Light +Adelle Lirious +Alison Wonder +Amie Thyst +Amie Zonite +Angela Develle +Anna Conda +Anne Amaley +Annie Nigma +Aria Hymn +Aria Viderci +Aroa Mattic +Aster Starr +Aura Aurora +Aura Ley +Aurora Dorea +Barba Rouse +Bea Constrictor +Bella Lush +Belle Icoza +Belle Ligerrente +Betty Brilliance +Bo Deysious +Carol Chorale +Cecil Clouds +Cecil Sunshine +Celeste Booday +Chichi Swank +Claire Geeman +Claire Rickal +Claire Voyance +Cleo Patrix +Connie Fidence +Corra Rageous +Daye Light +Deedee Cation +Deedee Sign +Dianne Gerous +Didi Divine +Diemme Monds +Dorothy Doughty +Dutches Dauntless +Ella Gance +Ella Gants +Ella Menterry +Ella Stique +Elle Lectrick +Elle Lure +Emma Geddon +Emma Phasis +Emma Rald +Emme Plosion +Emme Pulse +Emme Vention +Enna Fincible +Enne Phinite +Enne Treppide +Etha Nitty +Etha Reyal +Euphoria Bliss +Eva Nessent +Eve Forric +Eve Ningowne +Eve Ville +Faith Lesse +Faschia Nation +Faye Boulous +Faye Lacious +Faye Minine +Faye Nixx +Felicity Spice +Freya Domme +Gal Gallant +Gal Galore +Gal Lante +Gemma Safir +Gena Rocity +Genna Russ +Gigi Lamour +Gigi Rand +Glemma Rouss +Grace Iyus +Haye Light +Hazel Nutt +Hella Billy +Hella Centrique +Hella Cious +Hella Riouss +Hella Whole +Hellen Back +Herra Zee +Ina Creddeble +Ina Fernalle +Jo Nee +Jo Phial +Joye Ryde +Jue Cee +Jue Wells +Juju Bee +Kaia Cayenne +Kaye Bye +Kitsch Kitsch Bang Bang +Lady Lace +Lavish Lazuli +Lea Ness +Leye Berty +Lisse Truss +Liv Lee +Lola Lavish +Lolo Yaltie +Lucy Fur +Lucy Luck +Lulu LaBye +Lulu Xuri +Lunaye Clipse +Lyra Kall +Maggie Magma +Mara Bells +Marry Golds +Marry Nayde +Marry Sipan +Marve Vellus +Mary Ganal +Mary Malade +May Jestic +May Lancholly +May Licious +May Lodi +May Morable +May Stirius +May Varlous +Melody Gale +Melody Toune +Miss Adora +Miss Alure +Miss Chieff +Miss Fortune +Miss Mash +Miss Mood +Miss Nomer +Miss Sanguine +Miss Sublime +Mistress Galore +Monique Mystique +Morgan Fatana +Nashay Kitt +Nicole Lorful +Noë Stalgia +Ora Kelle +Ora Nate +Patty Siyens +Penny Laized +Penny Ramma +Penny Rammic +Penny Talloons +Percey Ferance +Perry Fomance +Phara Waye +Phata Morgana +Pho Latyle +Pho Lume +Phoebe Rant +Phoenix Bright +Pippa Pepper +Pippa Pizazz +Polly Tickle +Poppy Corn +Poppy Cox +Poppy Domm +Poppy Larr +Poppy Lerry +Poppy Sickles +Portia Bella +Portia Nette +Pria Steegious +Pria Steen +Prissa Teen +Raye Bitt +Raye Diante +Raye Nessance +Raye Storm +Remi Nissent +Rey Mantique +Rey Markeble +Rey Moorse +Rey Torric +Rococo Jazz +Roma Ence +Rose Budd +Ruby Redd +Ruby Ree +Ruth Lezz +Sall Laikeen +Sall Lay +Sally Ness +Sam Armie +Sam Ooth +Sara Castique +Sara Donique +Sara Penth +Sarah Pentine +Sarah Reen +Sasha Sass +Satty Phection +Sella Fish +Sella Stice +Selly Foxx +Senna Guinne +Senna Seer +Shia Mirring +Sia Dellic +Sia Dowe +Siam Pathy +Silver Foxx +Siri Price +Sofie Moore +Sofie Stication +Su Blime +Sue Burben +Sue Missif +Sue Pernova +Sue Preem +Super Nova +Suse Pense +Suzu Blime +Temma Tation +Tempest Wilde +Terra Gique +Thea Terre +Tina Cious +Tina Scious +Tira Mendus +Tira Quoise +Trinity Quart +Trixie Foxx +Tye Gress +Tye Phun +Vall Canno +Vall Iant +Vall Orous +Vanity Fairchild +Vicki Tory +Vivi Venus +Vivian Foxx +Vye Vacius +Zahara Dessert + -- cgit v1.2.3 From a1c9078e69ddaec24c632bd1bd85826d6abe2d65 Mon Sep 17 00:00:00 2001 From: Will Da Silva Date: Tue, 1 Oct 2019 15:44:40 -0400 Subject: Add drag queen name generator Could be improved by writing a message that says: "@command_invoker's drag queen name is " --- bot/seasons/pride/drag_queen_name.py | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 bot/seasons/pride/drag_queen_name.py (limited to 'bot') diff --git a/bot/seasons/pride/drag_queen_name.py b/bot/seasons/pride/drag_queen_name.py new file mode 100644 index 00000000..f34da00e --- /dev/null +++ b/bot/seasons/pride/drag_queen_name.py @@ -0,0 +1,32 @@ +import logging +import random +from pathlib import Path + +from discord.ext import commands + +log = logging.getLogger(__name__) + + +class DragNames(commands.Cog): + """Gives a random drag queen name""" + + def __init__(self, bot: commands.Bot): + self.bot = bot + self.names = self.load_names() + + @staticmethod + def load_names() -> list: + """Loads a list of drag queen names.""" + with open(Path("bot/resources/pride/drag_queen_names.txt"), "r", encoding="utf-8") as f: + return f.readlines() + + @commands.command(name="dragname", aliases=["dragqueenname", "queenme"]) + async def dragname(self, ctx: commands.Context) -> None: + """Sends a message with a drag queen name.""" + await ctx.send(random.choice(self.names)) + + +def setup(bot: commands.Bot) -> None: + """Cog loader for drag queen name generator.""" + bot.add_cog(DragNames(bot)) + log.info("Drag queen name generator cog loaded!") -- cgit v1.2.3 From 63e98827e44d3049922c14fd32ca104548c44b60 Mon Sep 17 00:00:00 2001 From: Will Da Silva Date: Tue, 1 Oct 2019 21:25:50 -0400 Subject: Fix linter issue --- bot/seasons/pride/drag_queen_name.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'bot') diff --git a/bot/seasons/pride/drag_queen_name.py b/bot/seasons/pride/drag_queen_name.py index f34da00e..8f0219f3 100644 --- a/bot/seasons/pride/drag_queen_name.py +++ b/bot/seasons/pride/drag_queen_name.py @@ -8,7 +8,7 @@ log = logging.getLogger(__name__) class DragNames(commands.Cog): - """Gives a random drag queen name""" + """Gives a random drag queen name!""" def __init__(self, bot: commands.Bot): self.bot = bot -- cgit v1.2.3 From abce0ecc6a072d6d25035c6b55d45f2f85327c22 Mon Sep 17 00:00:00 2001 From: RohanJnr Date: Wed, 2 Oct 2019 09:38:20 +0530 Subject: Worked on the requested changes and also made a few other changes: - when the user uses the command to stop the game, the bot fails to reply back with the winners list. This is because the varibale player_data is being initialised to {} at the start of the command. I solved this by making a player_data variable in the cog __init__() with the channel id being the key and dict as value --- bot/resources/evergreen/trivia_quiz.json | 120 ++++++++++---------------- bot/seasons/evergreen/trivia_quiz.py | 139 +++++++++++++++---------------- 2 files changed, 112 insertions(+), 147 deletions(-) (limited to 'bot') diff --git a/bot/resources/evergreen/trivia_quiz.json b/bot/resources/evergreen/trivia_quiz.json index 9c3259cd..69a834f8 100644 --- a/bot/resources/evergreen/trivia_quiz.json +++ b/bot/resources/evergreen/trivia_quiz.json @@ -2,13 +2,13 @@ "retro": [ { "id": 1, - "hints": ["It was not a mainline Mario Game, although the plumber was present.", "It was not a mainline Zelda Game, although Link was present."], - "question": "What was the best selling game on the Nintendo Gamecube?", + "hints": ["It is not a mainline Mario Game, although the plumber is present.", "It is not a mainline Zelda Game, although Link is present."], + "question": "What is the best selling game on the Nintendo GameCube?", "answer": "Super Smash Bros" }, { "id": 2, - "hints": ["It was released before the 90s.", "It was released after 1980."], + "hints": ["It was released before the 90's.", "It was released after 1980."], "question": "What year was Tetris released?", "answer": "1984" }, @@ -20,8 +20,8 @@ }, { "id": 4, - "hints": ["It was revelead in the Nintendo Character Guide in 1993.", "His last name has to do with eating Mario's enemies."], - "question": "What is Yoshi's(from Mario Bros) full name?", + "hints": ["It was revealed in the Nintendo Character Guide in 1993.", "His last name has to do with eating Mario's enemies."], + "question": "What is Yoshi's (from Mario Bros.) full name?", "answer": "Yoshisaur Munchakoopas" }, { @@ -34,109 +34,108 @@ "general":[ { "id": 100, - "question": "Name the land of thousand lakes", + "question": "Name \"the land of a thousand lakes\"", "answer": "Finland", - "info": "Finland is a country in Northern Europe. Sweden borders it to the northwest, Estonia to the south, Russia to the east, and Norway to the north. Finland is part of the European Union with its capital city being Helsinki. With a population of 5.5 million people, it has over 187,000 lakes. The thousands of lakes in Finland are the reason why the country's nickname is “the land of a thousand lakes." + "info": "Finland is a country in Northern Europe. Sweden borders it to the northwest, Estonia to the south, Russia to the east, and Norway to the north. Finland is part of the European Union with its capital city being Helsinki. With a population of 5.5 million people, it has over 187,000 lakes. The thousands of lakes in Finland are the reason why the country's nickname is \"the land of a thousand lakes.\"" }, { "id": 101, - "question": "Winner of FIFA 2018", + "question": "Who was the winner of FIFA 2018?", "answer": "France", "info": "France 4 - 2 Croatia" }, { "id": 102, - "question": "Remind me the largest Ocean in the world.", + "question": "What is the largest ocean in the world?", "answer": "Pacific", "info": "The Pacific Ocean is the largest and deepest of the world ocean basins. Covering approximately 63 million square miles and containing more than half of the free water on Earth, the Pacific is by far the largest of the world's ocean basins." }, { "id": 103, - "question": "Have you heard of The Statue Of Liberty ? Who gifted it?", - "answer": "French", - "info": "The Statue of Liberty was a gift from the French people commemorating the alliance of France and the United States during the American Revolution. Yet, it represented much more to those individuals who proposed the gift. A photograph of Edouard de Laboulaye from the Galerie Contemporaine collection." + "question": "Who gifted the Statue Of Liberty?", + "answer": "France", + "info": "The Statue of Liberty was a gift from the French people commemorating the alliance of France and the United States during the American Revolution. Yet, it represented much more to those individuals who proposed the gift." }, { "id": 104, - "question": "Land Of The Rising Sun?", + "question": "Which country is known as the \"Land Of The Rising Sun\"?", "answer": "Japan", - "info": "According to the words of the Japanese envoy himself, that name was chosen because the country was so close to where the sun rises. In any event, the name stuck, and for the last 1400 years or so, the world has referred to Japan as Nippon, the land of the rising sun." + "info": "The title stems from the Japanese names for Japan, Nippon/Nihon, both literally translating to \"the suns origin\"." }, { "id": 105, - "question": "Is there a play ground in Europe ?Name the Play Ground of Europe", - "answer": "SWITZERLAND", + "question": "What's known as the \"Playground of Europe\"?", + "answer": "Switzerland", "info": "It comes from the title of a book written in 1870 by Leslie Stephen (father of Virginia Woolf) detailing his exploits of mountain climbing (not skiing) of which sport he was one of the pioneers and trekking or walking." }, { "id": 106, - "question": "Have you been struck by Thunder ? If not your very lucky but this place has gone through lot of large violent thunderstorms, called the Land Of Thunderbolt, name it.", - "answer": "Bhutan", - "info": "Bhutan is called Land of Thunder Dragon. Because of the violent and large thunderstorms that whip down through the valleys from the Himalayas, Bhutan is known as the Land of Thunderbolt. The sparkling light of thunderbolts were believed to be red fire of a dragon." + "question": "Which country is known as the \"Land of Thunderbolt\"?", + "info": "\"Bhutan is known as the \\\"Land of Thunder Dragon\\\" or \\\"Land of Thunderbolt\\\" due to the violent and large thunderstorms that whip down through the valleys from the Himalayas. The dragon reference was due to people thinking the sparkling light of thunderbolts was the red fire of a dragon.\"" }, { "id": 107, - "question": "Largest producer of tea in the world?", + "question": "Which country is the largest producer of coffee?", "answer": "China", "info": "Tea is mainly grown in Asia, Africa, South America, and around the Black and Caspian Seas. The four biggest tea-producing countries today are China, India, Sri Lanka and Kenya. Together they represent 75% of world production." }, { "id": 108, - "question": "Remind me the largest producer of Coffee ?", + "question": "Which country is the largest producer of tea in the world?", "answer": "Brazil", "info": "Brazil is the world's largest coffee producer. In 2016, Brazil produced a staggering 2,595,000 metric tons of coffee beans. It is not a new development, as Brazil has been the highest global producer of coffee beans for over 150 years." }, { "id": 109, - "question": "Mount Etna, one of the active volcano, where is it located?", + "question": "Which country is Mount Etna, one of the most active volcanoes in the world, located?", "answer": "Italy", - "info": "Mount Etna is the highest and most active volcano in Europe. Towering above the city of Catania on the island of Sicily, it has been growing for about 500,000 years and is in the midst of a series of eruptions that began in 2001.It is also possible to visit Mount Etna independently, but the advantages of a guided excursion are very numerous. Mount Etna is on of the highest volcano in Europe and on of the most active in the world. The volcano shaped the Sicilian history and landscape and still affects the island today." + "info": "Mount Etna is the highest volcano in Europe. Towering above the city of Catania on the island of Sicily, it has been growing for about 500,000 years and is in the midst of a series of eruptions that began in 2001." }, { "id": 110, - "question": "Which country is called Battleground of Europe?", + "question": "Which country is called \"Battleground of Europe?\"", "answer": "Belgium", - "info": "Belgium has been the battleground of Europe since the Roman Empire… Belgium was the battleground of Europe for centuries as it had no natural protection from its big neighboring countries. ... The battles of Oudenaarde, Ramillies, Waterloo, Ypres and Bastogne were all fought on Belgian soil." + "info": "Belgium has been the \"Battleground of Europe\" since the Roman Empire as it had no natural protection from its larger neighbouring countries. The battles of Oudenaarde, Ramillies, Waterloo, Ypres and Bastogne were all fought on Belgian soil." }, { "id": 111, - "question": "Largest tropical rain forest in the world?", + "question": "Which is the largest tropical rain forest in the world?", "answer": "Amazon", - "info": "The Amazon is regarded as vital in the fight against global warming due to its ability to absorb carbon from the air. It's often referred to as the “lungs of the Earth,” as more than 20 per cent of the world's oxygen is produced there." + "info": "The Amazon is regarded as vital in the fight against global warming due to its ability to absorb carbon from the air. It's often referred to as the \"lungs of the Earth,\" as more than 20 per cent of the world's oxygen is produced there." }, { "id": 112, - "question": "Do you know the biggest Island in the World ?", + "question": "Which is the largest island in the world?", "answer": "Greenland", - "info": "" + "info": "Commonly thought to be Australia, but as it's actually a continental landmass, it doesn't get to make it in the list." }, { "id": 113, - "question": "Give me the name of the tallest waterfall in the world.", + "question": "What's the name of the tallest waterfall in the world.", "answer": "Angel", "info": "Angel Falls (Salto Ángel) in Venezuela is the highest waterfall in the world. The falls are 3230 feet in height, with an uninterrupted drop of 2647 feet. Angel Falls is located on a tributary of the Rio Caroni." }, { "id": 114, - "question": "Have you seen white elephants? If not then there is a place called Land of White Elephants, does anyone know the place?", + "question": "What country is called \"Land of White Elephants\"?", "answer": "Thailand", "info": "White elephants were regarded to be holy creatures in ancient Thailand and some other countries. Today, white elephants are still used as a symbol of divine and royal power in the country. Ownership of a white elephant symbolizes wealth, success, royalty, political power, wisdom, and prosperity." }, { "id": 115, - "question": "How many continents have you been to? Maybe you can visit 2 at once, name the city of two continents.", + "question": "Which city is in two continents?", "answer": "Istanbul", "info": "Istanbul embraces two continents, one arm reaching out to Asia, the other to Europe." }, { "id": 116, - "question": "the Vally Of The Kings is located in the country...?", + "question": "The Vally Of The Kings is located in which country?", "answer": "Egypt", "info": "The Valley of the Kings, also known as the Valley of the Gates of the Kings, is a valley in Egypt where, for a period of nearly 500 years from the 16th to 11th century BC, rock cut tombs were excavated for the pharaohs and powerful nobles of the New Kingdom (the Eighteenth to the Twentieth Dynasties of Ancient Egypt)." }, { "id": 117, - "question": "Diamonds are always nice in Minecraft, but did you know that there is a \"Diamond Capital in the World?\" can anyone name it?", + "question": "Diamonds are always nice in Minecraft, but can you name the \"Diamond Capital in the World\"?", "answer": "Antwerp", "info": "Antwerp, Belgium is where 60-80% of the world's diamonds are cut and traded, and is known as the \"Diamond Capital of the World.\"" }, @@ -154,7 +153,7 @@ }, { "id": 120, - "question": "The world's largest coral reef system \"Great Barrier Reef\" is located in?", + "question": "What country is the world's largest coral reef system, the \"Great Barrier Reef\", located in?", "answer": "Australia", "info": "The Great Barrier Reef is the world's largest coral reef system composed of over 2,900 individual reefs and 900 islands stretching for over 2,300 kilometres (1,400 mi) over an area of approximately 344,400 square kilometres (133,000 sq mi). The reef is located in the Coral Sea, off the coast of Queensland, Australia." }, @@ -166,88 +165,57 @@ }, { "id": 122, - "question": "Which is the only mammal that can’t jump?", - "answer": "elephant", - "info": "It is true that adult elephants can't jump. But there are other mammals that can't either, like sloths, hippos and rhinos. Although, unlike elephants, hippos and rhinos can have all four feet off the ground at the same time when they run." - + "question": "Which is the largest desert in the world (exclude cold deserts.) ?", + "answer": "Sahara", + "info": "The Sahara Desert covers 3.6 million square miles. It is almost the same size as the United States or China. There are sand dunes in the Sahara as tall as 590 feet." }, { "id": 123, "question": "Who lived at 221B, Baker Street, London?", "answer": "Sherlock Holmes", - "info": "You guys know this very well, xD." - + "info": "" }, { "id": 124, "question": "When did the Second World War end?", "answer": "1945", "info": "World War 2 ended with the unconditional surrender of the Axis powers. On 8 May 1945, the Allies accepted Germany's surrender, about a week after Adolf Hitler had committed suicide. VE Day – Victory in Europe celebrates the end of the Second World War on 8 May 1945." - }, { "id": 125, - "question": "Name the largest Dam in the World", + "question": "What is the name of the largest Dam in the world?", "answer": "Three Gorges Dam", "info": "At 1.4 miles wide (2.3 kilometers) and 630 feet (192 meters) high, Three Gorges Dam is the largest hydroelectric dam in the world, according to International Water Power & Dam Construction magazine. Three Gorges impounds the Yangtze River about 1,000 miles (1,610 km) west of Shanghai." - }, { "id": 126, - "question": "Name the largest river in the World.", + "question": "What's the name of the largest river in the world?", "answer": "Nile", "info": "The Nile, which is about 6,650 km (4,130 mi) long, is an \"international\" river as its drainage basin covers eleven countries, namely, Tanzania, Uganda, Rwanda, Burundi, the Democratic Republic of the Congo, Kenya, Ethiopia, Eritrea, South Sudan, Republic of the Sudan and Egypt." - }, { "id": 127, - "question": "Which is the smallest planet in the Solar System? Earth?", + "question": "Which is the smallest planet in the Solar System?", "answer": "Mercury", "info": "Mercury is the smallest planet in our solar system. It's just a little bigger than Earth's moon. It is the closest planet to the sun, but it's actually not the hottest. Venus is hotter." - }, { "id": 128, - "question": "Is your country the smallest? Well it is if it is this perticular place, name the smallest country.", - "answer": "Vatican city", + "question": "What is the smallest country?", + "answer": "Vatican City", "info": "With an area of 0.17 square miles (0.44 km2) and a population right around 1,000, Vatican City is the smallest country in the world, both in terms of size and population." - }, { "id": 129, - "question": "Have you seen the largest bird? If so then name it.", + "question": "What's the name of the largest bird?", "answer": "Ostrich", "info": "The largest living bird, a member of the Struthioniformes, is the ostrich (Struthio camelus), from the plains of Africa and Arabia. A large male ostrich can reach a height of 2.8 metres (9.2 feet) and weigh over 156 kilograms (344 pounds)." - }, { "id": 130, "question": "Expand GPRS", "answer": "General Packet Radio Service", "info": "General Packet Radio Service (GPRS) is a packet-based mobile data service on the global system for mobile communications (GSM) of 3G and 2G cellular communication systems. It is a non-voice, high-speed and useful packet-switching technology intended for GSM networks." - - }, - { - "id": 120, - "question": "", - "answer": "", - "info": "" - - }, - { - "id": 120, - "question": "", - "answer": "", - "info": "" - - }, - { - "id": 120, - "question": "", - "answer": "", - "info": "" - } - ] } diff --git a/bot/seasons/evergreen/trivia_quiz.py b/bot/seasons/evergreen/trivia_quiz.py index ac72ed95..c7778c88 100644 --- a/bot/seasons/evergreen/trivia_quiz.py +++ b/bot/seasons/evergreen/trivia_quiz.py @@ -30,9 +30,10 @@ class TriviaQuiz(commands.Cog): self.questions = self.load_questions() self.game_status = {} self.game_owners = {} - self.question_limit = 3 + self.question_limit = 4 + self.player_dict = {} self.categories = { - "general": "Test your general knwoledge" + "general": "Test your general knowledge" # "retro": "Questions related to retro gaming." } @@ -44,8 +45,8 @@ class TriviaQuiz(commands.Cog): questions = json.load(json_data) return questions - @commands.command(name="quiz") - async def quiz_game(self, ctx: commands.Context, option: str, category: str = "general") -> None: + @commands.command(name="quiz", aliases=["trivia", "tquiz"]) + async def quiz_game(self, ctx: commands.Context, category: str = "general") -> None: """ Start/Stop a quiz! @@ -59,42 +60,36 @@ class TriviaQuiz(commands.Cog): (we wil be adding more later) """ category = category.lower() - player_data = {} # a dict to store players and their points. + # player_data = {} # a dict to store players and their points. if ctx.channel.id not in self.game_status: - self.game_status[ctx.channel.id] = None - - if option == "start": - if self.game_status[ctx.channel.id] is True: - await ctx.send("Game already running.") - return - else: - self.game_owners[ctx.channel.id] = ctx.author - self.game_status[ctx.channel.id] = True - start_embed = discord.Embed(colour=discord.Colour.red()) - start_embed.title = "Quiz game Starting!!" - start_embed.description = "Each game consists of 5 questions.\n" - start_embed.description += "**Rules :**\nNo cheating and have fun!" - start_embed.set_footer( - text="Points for that question reduces by 25 after 10s.Total time is 30s per question" - ) - await ctx.send(embed=start_embed) # send an embed with the rules - await asyncio.sleep(1) - - elif option == "stop": - if self.game_status[ctx.channel.id] is False: - await ctx.send("No game running, nothing to stop here.") - return + self.game_status[ctx.channel.id] = False + self.player_dict[ctx.channel.id] = {} + + if not self.game_status[ctx.channel.id]: + self.game_owners[ctx.channel.id] = ctx.author + self.game_status[ctx.channel.id] = True + start_embed = discord.Embed(colour=discord.Colour.red()) + start_embed.title = "Quiz game Starting!!" + start_embed.description = "Each game consists of 5 questions.\n" + start_embed.description += "**Rules :**\nNo cheating and have fun!" + start_embed.set_footer( + text="Points for a question reduces by 25 after 10s or after a hint.Total time is 30s per question" + ) + await ctx.send(embed=start_embed) # send an embed with the rules + await asyncio.sleep(1) + + else: + if ( + ctx.author == self.game_owners[ctx.channel.id] + or Roles.moderator in [role.id for role in ctx.author.roles] + ): + await ctx.send("Quiz is no longer running.") + await self.declare_winner(ctx.channel, self.player_dict[ctx.channel.id]) + self.game_status[ctx.channel.id] = False + del self.game_owners[ctx.channel.id] else: - if ( - ctx.author == self.game_owners[ctx.channel.id] - or Roles.moderator in [role.id for role in ctx.author.roles] - ): - await self.declare_winner(ctx.channel, player_data) - self.game_status[ctx.channel.id] = False - del self.game_owners[ctx.channel.id] - else: - await ctx.send(f"{ctx.author.mention}, you are not authorised to stop this game :ghost: !") + await ctx.send(f"{ctx.author.mention}, you are not authorised to stop this game :ghost: !") if category not in self.categories: embed = self.category_embed @@ -106,15 +101,14 @@ class TriviaQuiz(commands.Cog): done_question = [] hint_no = 0 answer = None - hints = None - while self.game_status[ctx.channel.id] is True: + while self.game_status[ctx.channel.id]: if len(done_question) > self.question_limit and hint_no == 0: await ctx.send("The round ends here.") - await self.declare_winner(ctx.channel, player_data) + await self.declare_winner(ctx.channel, self.player_dict[ctx.channel.id]) break if unanswered > 3: await ctx.send("Game stopped due to inactivity.") - await self.declare_winner(ctx.channel, player_data) + await self.declare_winner(ctx.channel, self.player_dict[ctx.channel.id]) break if hint_no == 0: while True: @@ -132,42 +126,43 @@ class TriviaQuiz(commands.Cog): def check(m: discord.Message) -> bool: ratio = fuzz.ratio(answer.lower(), m.content.lower()) - return ratio > 80 and m.channel == ctx.channel + return ratio > 85 and m.channel == ctx.channel try: msg = await self.bot.wait_for('message', check=check, timeout=10) - except Exception as e: + except asyncio.TimeoutError: if self.game_status[ctx.channel.id] is False: break - if isinstance(e, asyncio.TimeoutError): - if hint_no < 2: - hint_no += 1 - if "hints" in question_dict: - hints = question_dict["hints"] - await ctx.send(f"**Hint #{hint_no+1}\n**{hints[hint_no]}") - else: - await ctx.send(f"Cmon guys, {30-hint_no*10}s left!") - + if hint_no < 2: + hint_no += 1 + if "hints" in question_dict: + hints = question_dict["hints"] + await ctx.send(f"**Hint #{hint_no+1}\n**{hints[hint_no]}") else: - response = random.choice(WRONG_ANS_RESPONSE) - expression = random.choice(ANNOYED_EXPRESSIONS) - await ctx.send(f"{response} {expression}") - await self.send_answer(ctx.channel, question_dict) - await asyncio.sleep(1) - hint_no = 0 - unanswered += 1 - await self.send_score(ctx.channel, player_data) + await ctx.send(f"Cmon guys, {30-hint_no*10}s left!") + + else: + response = random.choice(WRONG_ANS_RESPONSE) + expression = random.choice(ANNOYED_EXPRESSIONS) + await ctx.send(f"{response} {expression}") + await self.send_answer(ctx.channel, question_dict) + await asyncio.sleep(1) + hint_no = 0 + unanswered += 1 + await self.send_score(ctx.channel, self.player_dict[ctx.channel.id]) + await asyncio.sleep(2) else: points = 100 - 25*hint_no - if msg.author in player_data: - player_data[msg.author] += points + if msg.author in self.player_dict[ctx.channel.id]: + self.player_dict[ctx.channel.id][msg.author] += points else: - player_data[msg.author] = points + self.player_dict[ctx.channel.id][msg.author] = points hint_no = 0 unanswered = 0 await ctx.send(f"{msg.author.mention} got the correct answer :tada: {points} points for ya.") await self.send_answer(ctx.channel, question_dict) - await self.send_score(ctx.channel, player_data) + await self.send_score(ctx.channel, self.player_dict[ctx.channel.id]) + await asyncio.sleep(2) @staticmethod async def send_score(channel: discord.TextChannel, player_data: dict) -> None: @@ -181,13 +176,14 @@ class TriviaQuiz(commands.Cog): @staticmethod async def declare_winner(channel: discord.TextChannel, player_data: dict) -> None: - """A function declare the winner of the quiz.""" + """Announce the winner of the quiz in the game channel.""" if player_data: highest_points = max(list(player_data.values())) no_of_winners = list(player_data.values()).count(highest_points) # Check if more than 1 player has highest points. if no_of_winners > 1: + word = "You guys" winners = [] points_copy = list(player_data.values()).copy() for _ in range(no_of_winners): @@ -199,17 +195,18 @@ class TriviaQuiz(commands.Cog): winners_mention += f"{winner.mention} " else: + word = "You" author_index = list(player_data.values()).index(highest_points) winner = list(player_data.keys())[author_index] winners_mention = winner.mention await channel.send( f"Congratz {winners_mention} :tada: " - f"You have won this quiz game with a grand total of {highest_points} points!!" + f"{word} have won this quiz game with a grand total of {highest_points} points!!" ) @property def category_embed(self) -> discord.Embed: - """A function which returns an embed showing all avilable categories.""" + """Build an embed showing all available trivia categories.""" embed = discord.Embed(colour=discord.Colour.blue()) embed.title = "The available question categories are:" embed.description = "" @@ -220,19 +217,19 @@ class TriviaQuiz(commands.Cog): @staticmethod async def send_answer(channel: discord.TextChannel, question_dict: dict) -> None: - """A function that sends the answer.""" + """Send the correct the answer of a question to the game channel.""" answer = question_dict["answer"] info = question_dict["info"] embed = discord.Embed(color=discord.Colour.red()) embed.title = f"The correct answer is **{answer}**\n" embed.description = "" if info != "": - embed.description += f"**Information**\n{info}\n" - embed.description += "Lets move to the next question." + embed.description += f"**Information**\n{info}\n\n" + embed.description += "Lets move to the next question.\nRemaining questions: " await channel.send(embed=embed) def setup(bot: commands.Bot) -> None: """Loading the cog.""" bot.add_cog(TriviaQuiz(bot)) - logger.debug("TriviaQuiz cog loaded!") + logger.debug("TriviaQuiz cog loaded") -- cgit v1.2.3 From 196fda75de5437dbc95091fee81cecfb8e2c0b48 Mon Sep 17 00:00:00 2001 From: RohanJnr Date: Wed, 2 Oct 2019 09:40:41 +0530 Subject: removed commented out code --- bot/seasons/evergreen/trivia_quiz.py | 1 - 1 file changed, 1 deletion(-) (limited to 'bot') diff --git a/bot/seasons/evergreen/trivia_quiz.py b/bot/seasons/evergreen/trivia_quiz.py index c7778c88..4b937035 100644 --- a/bot/seasons/evergreen/trivia_quiz.py +++ b/bot/seasons/evergreen/trivia_quiz.py @@ -60,7 +60,6 @@ class TriviaQuiz(commands.Cog): (we wil be adding more later) """ category = category.lower() - # player_data = {} # a dict to store players and their points. if ctx.channel.id not in self.game_status: self.game_status[ctx.channel.id] = False -- cgit v1.2.3 From b377d1e7edba11e90382c9c68d6836b3d5b4329a Mon Sep 17 00:00:00 2001 From: Rohan_Iceman Date: Wed, 2 Oct 2019 21:36:37 +0530 Subject: Applied suggestions from code review Co-Authored-By: scragly <29337040+scragly@users.noreply.github.com> --- bot/resources/evergreen/trivia_quiz.json | 12 ++++++------ bot/seasons/evergreen/trivia_quiz.py | 6 +++--- 2 files changed, 9 insertions(+), 9 deletions(-) (limited to 'bot') diff --git a/bot/resources/evergreen/trivia_quiz.json b/bot/resources/evergreen/trivia_quiz.json index 69a834f8..1ad2a1e1 100644 --- a/bot/resources/evergreen/trivia_quiz.json +++ b/bot/resources/evergreen/trivia_quiz.json @@ -71,17 +71,17 @@ { "id": 106, "question": "Which country is known as the \"Land of Thunderbolt\"?", - "info": "\"Bhutan is known as the \\\"Land of Thunder Dragon\\\" or \\\"Land of Thunderbolt\\\" due to the violent and large thunderstorms that whip down through the valleys from the Himalayas. The dragon reference was due to people thinking the sparkling light of thunderbolts was the red fire of a dragon.\"" + "info": "Bhutan is known as the \"Land of Thunder Dragon\" or \"Land of Thunderbolt\" due to the violent and large thunderstorms that whip down through the valleys from the Himalayas. The dragon reference was due to people thinking the sparkling light of thunderbolts was the red fire of a dragon." }, { "id": 107, - "question": "Which country is the largest producer of coffee?", + "question": "Which country is the largest producer of tea in the world?", "answer": "China", "info": "Tea is mainly grown in Asia, Africa, South America, and around the Black and Caspian Seas. The four biggest tea-producing countries today are China, India, Sri Lanka and Kenya. Together they represent 75% of world production." }, { "id": 108, - "question": "Which country is the largest producer of tea in the world?", + "question": "Which country is the largest producer of coffee?", "answer": "Brazil", "info": "Brazil is the world's largest coffee producer. In 2016, Brazil produced a staggering 2,595,000 metric tons of coffee beans. It is not a new development, as Brazil has been the highest global producer of coffee beans for over 150 years." }, @@ -165,7 +165,7 @@ }, { "id": 122, - "question": "Which is the largest desert in the world (exclude cold deserts.) ?", + "question": "Which is the largest hot desert in the world?", "answer": "Sahara", "info": "The Sahara Desert covers 3.6 million square miles. It is almost the same size as the United States or China. There are sand dunes in the Sahara as tall as 590 feet." }, @@ -183,7 +183,7 @@ }, { "id": 125, - "question": "What is the name of the largest Dam in the world?", + "question": "What is the name of the largest dam in the world?", "answer": "Three Gorges Dam", "info": "At 1.4 miles wide (2.3 kilometers) and 630 feet (192 meters) high, Three Gorges Dam is the largest hydroelectric dam in the world, according to International Water Power & Dam Construction magazine. Three Gorges impounds the Yangtze River about 1,000 miles (1,610 km) west of Shanghai." }, @@ -213,7 +213,7 @@ }, { "id": 130, - "question": "Expand GPRS", + "question": "What does the acronym GPRS stand for?", "answer": "General Packet Radio Service", "info": "General Packet Radio Service (GPRS) is a packet-based mobile data service on the global system for mobile communications (GSM) of 3G and 2G cellular communication systems. It is a non-voice, high-speed and useful packet-switching technology intended for GSM networks." } diff --git a/bot/seasons/evergreen/trivia_quiz.py b/bot/seasons/evergreen/trivia_quiz.py index 4b937035..798523e6 100644 --- a/bot/seasons/evergreen/trivia_quiz.py +++ b/bot/seasons/evergreen/trivia_quiz.py @@ -45,7 +45,7 @@ class TriviaQuiz(commands.Cog): questions = json.load(json_data) return questions - @commands.command(name="quiz", aliases=["trivia", "tquiz"]) + @commands.command(name="quiz", aliases=["trivia"]) async def quiz_game(self, ctx: commands.Context, category: str = "general") -> None: """ Start/Stop a quiz! @@ -73,7 +73,7 @@ class TriviaQuiz(commands.Cog): start_embed.description = "Each game consists of 5 questions.\n" start_embed.description += "**Rules :**\nNo cheating and have fun!" start_embed.set_footer( - text="Points for a question reduces by 25 after 10s or after a hint.Total time is 30s per question" + text="Points for a question reduces by 25 after 10s or after a hint. Total time is 30s per question" ) await ctx.send(embed=start_embed) # send an embed with the rules await asyncio.sleep(1) @@ -216,7 +216,7 @@ class TriviaQuiz(commands.Cog): @staticmethod async def send_answer(channel: discord.TextChannel, question_dict: dict) -> None: - """Send the correct the answer of a question to the game channel.""" + """Send the correct answer of a question to the game channel.""" answer = question_dict["answer"] info = question_dict["info"] embed = discord.Embed(color=discord.Colour.red()) -- cgit v1.2.3 From c06ec338c1e6d955c4244ed60d08bbeccb90c359 Mon Sep 17 00:00:00 2001 From: vivax3794 <51753506+vivax3794@users.noreply.github.com> Date: Wed, 2 Oct 2019 22:05:23 +0200 Subject: added embed. --- bot/seasons/halloween/hacktober-issue-finder.py | 39 ++++++++++++++++++------- 1 file changed, 28 insertions(+), 11 deletions(-) (limited to 'bot') diff --git a/bot/seasons/halloween/hacktober-issue-finder.py b/bot/seasons/halloween/hacktober-issue-finder.py index 17eec95a..54f205cf 100644 --- a/bot/seasons/halloween/hacktober-issue-finder.py +++ b/bot/seasons/halloween/hacktober-issue-finder.py @@ -1,15 +1,16 @@ import datetime import logging +import random from typing import Dict, List import aiohttp +import discord from discord.ext import commands log = logging.getLogger(__name__) -URL = "https://api.github.com/search/issues" +URL = "https://api.github.com/search/issues?q=label:hacktoberfest+language:python+state:open&per_page=100" HEADERS = {"Accept": "application / vnd.github.v3 + json"} -SEARCH = "label:hacktoberfest+language:python+state:open" class HacktoberIssues(commands.Cog): @@ -24,8 +25,10 @@ class HacktoberIssues(commands.Cog): async def hacktoberissues(self, ctx: commands.Context) -> None: """Get a random python hacktober issue from Github.""" with ctx.typing(): - data = await self.get_issues(ctx) - print("need to use data somehow to commit...", data) + issues = await self.get_issues(ctx) + issue = random.choice(issues) + embed = self.format_embed(issue) + await ctx.send(embed=embed) async def get_issues(self, ctx: commands.Context) -> List[Dict]: """Get a list of the python issues with the label 'hacktoberfest' from the Github api.""" @@ -34,17 +37,31 @@ class HacktoberIssues(commands.Cog): async with aiohttp.ClientSession() as session: # text = TEXT # + "+label:hacktober" - params = { - "q": SEARCH - } - async with session.get(URL, headers=HEADERS, params=params) as response: + + async with session.get(URL, headers=HEADERS) as response: if response.status != 200: await ctx.send(f"ERROR: expected 200 status (got {response.status}) from the GitHub api.") await ctx.send(await response.text()) - data = (await response.json())["items"] - self.cache = data + data = await response.json() + issues = data["items"] + self.cache = issues self.cache_timer = ctx.message.created_at - return data + return issues + + @staticmethod + def format_embed(issue: Dict) -> discord.Embed: + """Format the issue data into a embed.""" + title = issue["title"] + issue_url = issue["url"].replace("api.", "").replace("/repos/", "/") + body = issue["body"] + labels = [label["name"] for label in issue["labels"]] + + embed = discord.Embed(title=title) + embed.description = body + embed.add_field(name="labels", value="\n".join(labels)) + embed.url = issue_url + + return embed def setup(bot: commands.Bot) -> None: -- cgit v1.2.3 From 9fab6ec2d5762d6d25f232efd419e62622270eff Mon Sep 17 00:00:00 2001 From: Will Da Silva Date: Wed, 2 Oct 2019 22:59:24 -0400 Subject: Change drag queen name list to JSON --- bot/resources/pride/drag_queen_names.json | 249 ++++++++++++++++++++++++++++++ bot/resources/pride/drag_queen_names.txt | 248 ----------------------------- bot/seasons/pride/drag_queen_name.py | 5 +- 3 files changed, 252 insertions(+), 250 deletions(-) create mode 100644 bot/resources/pride/drag_queen_names.json delete mode 100644 bot/resources/pride/drag_queen_names.txt (limited to 'bot') diff --git a/bot/resources/pride/drag_queen_names.json b/bot/resources/pride/drag_queen_names.json new file mode 100644 index 00000000..f63cdec3 --- /dev/null +++ b/bot/resources/pride/drag_queen_names.json @@ -0,0 +1,249 @@ +[ + "Adelle Lectible", + "Adelle Light", + "Adelle Lirious", + "Alison Wonder", + "Amie Thyst", + "Amie Zonite", + "Angela Develle", + "Anna Conda", + "Anne Amaley", + "Annie Nigma", + "Aria Hymn", + "Aria Viderci", + "Aroa Mattic", + "Aster Starr", + "Aura Aurora", + "Aura Ley", + "Aurora Dorea", + "Barba Rouse", + "Bea Constrictor", + "Bella Lush", + "Belle Icoza", + "Belle Ligerrente", + "Betty Brilliance", + "Bo Deysious", + "Carol Chorale", + "Cecil Clouds", + "Cecil Sunshine", + "Celeste Booday", + "Chichi Swank", + "Claire Geeman", + "Claire Rickal", + "Claire Voyance", + "Cleo Patrix", + "Connie Fidence", + "Corra Rageous", + "Daye Light", + "Deedee Cation", + "Deedee Sign", + "Dianne Gerous", + "Didi Divine", + "Diemme Monds", + "Dorothy Doughty", + "Dutches Dauntless", + "Ella Gance", + "Ella Gants", + "Ella Menterry", + "Ella Stique", + "Elle Lectrick", + "Elle Lure", + "Emma Geddon", + "Emma Phasis", + "Emma Rald", + "Emme Plosion", + "Emme Pulse", + "Emme Vention", + "Enna Fincible", + "Enne Phinite", + "Enne Treppide", + "Etha Nitty", + "Etha Reyal", + "Euphoria Bliss", + "Eva Nessent", + "Eve Forric", + "Eve Ningowne", + "Eve Ville", + "Faith Lesse", + "Faschia Nation", + "Faye Boulous", + "Faye Lacious", + "Faye Minine", + "Faye Nixx", + "Felicity Spice", + "Freya Domme", + "Gal Gallant", + "Gal Galore", + "Gal Lante", + "Gemma Safir", + "Gena Rocity", + "Genna Russ", + "Gigi Lamour", + "Gigi Rand", + "Glemma Rouss", + "Grace Iyus", + "Haye Light", + "Hazel Nutt", + "Hella Billy", + "Hella Centrique", + "Hella Cious", + "Hella Riouss", + "Hella Whole", + "Hellen Back", + "Herra Zee", + "Ina Creddeble", + "Ina Fernalle", + "Jo Nee", + "Jo Phial", + "Joye Ryde", + "Jue Cee", + "Jue Wells", + "Juju Bee", + "Kaia Cayenne", + "Kaye Bye", + "Kitsch Kitsch Bang Bang", + "Lady Lace", + "Lavish Lazuli", + "Lea Ness", + "Leye Berty", + "Lisse Truss", + "Liv Lee", + "Lola Lavish", + "Lolo Yaltie", + "Lucy Fur", + "Lucy Luck", + "Lulu LaBye", + "Lulu Xuri", + "Lunaye Clipse", + "Lyra Kall", + "Maggie Magma", + "Mara Bells", + "Marry Golds", + "Marry Nayde", + "Marry Sipan", + "Marve Vellus", + "Mary Ganal", + "Mary Malade", + "May Jestic", + "May Lancholly", + "May Licious", + "May Lodi", + "May Morable", + "May Stirius", + "May Varlous", + "Melody Gale", + "Melody Toune", + "Miss Adora", + "Miss Alure", + "Miss Chieff", + "Miss Fortune", + "Miss Mash", + "Miss Mood", + "Miss Nomer", + "Miss Sanguine", + "Miss Sublime", + "Mistress Galore", + "Monique Mystique", + "Morgan Fatana", + "Nashay Kitt", + "Nicole Lorful", + "Noë Stalgia", + "Ora Kelle", + "Ora Nate", + "Patty Siyens", + "Penny Laized", + "Penny Ramma", + "Penny Rammic", + "Penny Talloons", + "Percey Ferance", + "Perry Fomance", + "Phara Waye", + "Phata Morgana", + "Pho Latyle", + "Pho Lume", + "Phoebe Rant", + "Phoenix Bright", + "Pippa Pepper", + "Pippa Pizazz", + "Polly Tickle", + "Poppy Corn", + "Poppy Cox", + "Poppy Domm", + "Poppy Larr", + "Poppy Lerry", + "Poppy Sickles", + "Portia Bella", + "Portia Nette", + "Pria Steegious", + "Pria Steen", + "Prissa Teen", + "Raye Bitt", + "Raye Diante", + "Raye Nessance", + "Raye Storm", + "Remi Nissent", + "Rey Mantique", + "Rey Markeble", + "Rey Moorse", + "Rey Torric", + "Rococo Jazz", + "Roma Ence", + "Rose Budd", + "Ruby Redd", + "Ruby Ree", + "Ruth Lezz", + "Sall Laikeen", + "Sall Lay", + "Sally Ness", + "Sam Armie", + "Sam Ooth", + "Sara Castique", + "Sara Donique", + "Sara Penth", + "Sarah Pentine", + "Sarah Reen", + "Sasha Sass", + "Satty Phection", + "Sella Fish", + "Sella Stice", + "Selly Foxx", + "Senna Guinne", + "Senna Seer", + "Shia Mirring", + "Sia Dellic", + "Sia Dowe", + "Siam Pathy", + "Silver Foxx", + "Siri Price", + "Sofie Moore", + "Sofie Stication", + "Su Blime", + "Sue Burben", + "Sue Missif", + "Sue Pernova", + "Sue Preem", + "Super Nova", + "Suse Pense", + "Suzu Blime", + "Temma Tation", + "Tempest Wilde", + "Terra Gique", + "Thea Terre", + "Tina Cious", + "Tina Scious", + "Tira Mendus", + "Tira Quoise", + "Trinity Quart", + "Trixie Foxx", + "Tye Gress", + "Tye Phun", + "Vall Canno", + "Vall Iant", + "Vall Orous", + "Vanity Fairchild", + "Vicki Tory", + "Vivi Venus", + "Vivian Foxx", + "Vye Vacius", + "Zahara Dessert" +] \ No newline at end of file diff --git a/bot/resources/pride/drag_queen_names.txt b/bot/resources/pride/drag_queen_names.txt deleted file mode 100644 index 1701b760..00000000 --- a/bot/resources/pride/drag_queen_names.txt +++ /dev/null @@ -1,248 +0,0 @@ -Adelle Lectible -Adelle Light -Adelle Lirious -Alison Wonder -Amie Thyst -Amie Zonite -Angela Develle -Anna Conda -Anne Amaley -Annie Nigma -Aria Hymn -Aria Viderci -Aroa Mattic -Aster Starr -Aura Aurora -Aura Ley -Aurora Dorea -Barba Rouse -Bea Constrictor -Bella Lush -Belle Icoza -Belle Ligerrente -Betty Brilliance -Bo Deysious -Carol Chorale -Cecil Clouds -Cecil Sunshine -Celeste Booday -Chichi Swank -Claire Geeman -Claire Rickal -Claire Voyance -Cleo Patrix -Connie Fidence -Corra Rageous -Daye Light -Deedee Cation -Deedee Sign -Dianne Gerous -Didi Divine -Diemme Monds -Dorothy Doughty -Dutches Dauntless -Ella Gance -Ella Gants -Ella Menterry -Ella Stique -Elle Lectrick -Elle Lure -Emma Geddon -Emma Phasis -Emma Rald -Emme Plosion -Emme Pulse -Emme Vention -Enna Fincible -Enne Phinite -Enne Treppide -Etha Nitty -Etha Reyal -Euphoria Bliss -Eva Nessent -Eve Forric -Eve Ningowne -Eve Ville -Faith Lesse -Faschia Nation -Faye Boulous -Faye Lacious -Faye Minine -Faye Nixx -Felicity Spice -Freya Domme -Gal Gallant -Gal Galore -Gal Lante -Gemma Safir -Gena Rocity -Genna Russ -Gigi Lamour -Gigi Rand -Glemma Rouss -Grace Iyus -Haye Light -Hazel Nutt -Hella Billy -Hella Centrique -Hella Cious -Hella Riouss -Hella Whole -Hellen Back -Herra Zee -Ina Creddeble -Ina Fernalle -Jo Nee -Jo Phial -Joye Ryde -Jue Cee -Jue Wells -Juju Bee -Kaia Cayenne -Kaye Bye -Kitsch Kitsch Bang Bang -Lady Lace -Lavish Lazuli -Lea Ness -Leye Berty -Lisse Truss -Liv Lee -Lola Lavish -Lolo Yaltie -Lucy Fur -Lucy Luck -Lulu LaBye -Lulu Xuri -Lunaye Clipse -Lyra Kall -Maggie Magma -Mara Bells -Marry Golds -Marry Nayde -Marry Sipan -Marve Vellus -Mary Ganal -Mary Malade -May Jestic -May Lancholly -May Licious -May Lodi -May Morable -May Stirius -May Varlous -Melody Gale -Melody Toune -Miss Adora -Miss Alure -Miss Chieff -Miss Fortune -Miss Mash -Miss Mood -Miss Nomer -Miss Sanguine -Miss Sublime -Mistress Galore -Monique Mystique -Morgan Fatana -Nashay Kitt -Nicole Lorful -Noë Stalgia -Ora Kelle -Ora Nate -Patty Siyens -Penny Laized -Penny Ramma -Penny Rammic -Penny Talloons -Percey Ferance -Perry Fomance -Phara Waye -Phata Morgana -Pho Latyle -Pho Lume -Phoebe Rant -Phoenix Bright -Pippa Pepper -Pippa Pizazz -Polly Tickle -Poppy Corn -Poppy Cox -Poppy Domm -Poppy Larr -Poppy Lerry -Poppy Sickles -Portia Bella -Portia Nette -Pria Steegious -Pria Steen -Prissa Teen -Raye Bitt -Raye Diante -Raye Nessance -Raye Storm -Remi Nissent -Rey Mantique -Rey Markeble -Rey Moorse -Rey Torric -Rococo Jazz -Roma Ence -Rose Budd -Ruby Redd -Ruby Ree -Ruth Lezz -Sall Laikeen -Sall Lay -Sally Ness -Sam Armie -Sam Ooth -Sara Castique -Sara Donique -Sara Penth -Sarah Pentine -Sarah Reen -Sasha Sass -Satty Phection -Sella Fish -Sella Stice -Selly Foxx -Senna Guinne -Senna Seer -Shia Mirring -Sia Dellic -Sia Dowe -Siam Pathy -Silver Foxx -Siri Price -Sofie Moore -Sofie Stication -Su Blime -Sue Burben -Sue Missif -Sue Pernova -Sue Preem -Super Nova -Suse Pense -Suzu Blime -Temma Tation -Tempest Wilde -Terra Gique -Thea Terre -Tina Cious -Tina Scious -Tira Mendus -Tira Quoise -Trinity Quart -Trixie Foxx -Tye Gress -Tye Phun -Vall Canno -Vall Iant -Vall Orous -Vanity Fairchild -Vicki Tory -Vivi Venus -Vivian Foxx -Vye Vacius -Zahara Dessert - diff --git a/bot/seasons/pride/drag_queen_name.py b/bot/seasons/pride/drag_queen_name.py index 8f0219f3..43813fbd 100644 --- a/bot/seasons/pride/drag_queen_name.py +++ b/bot/seasons/pride/drag_queen_name.py @@ -1,3 +1,4 @@ +import json import logging import random from pathlib import Path @@ -17,8 +18,8 @@ class DragNames(commands.Cog): @staticmethod def load_names() -> list: """Loads a list of drag queen names.""" - with open(Path("bot/resources/pride/drag_queen_names.txt"), "r", encoding="utf-8") as f: - return f.readlines() + with open(Path("bot/resources/pride/drag_queen_names.json"), "r", encoding="utf-8") as f: + return json.load(f) @commands.command(name="dragname", aliases=["dragqueenname", "queenme"]) async def dragname(self, ctx: commands.Context) -> None: -- cgit v1.2.3 From 15ad5e5e689f5769ff8419466c96207cd5efec0d Mon Sep 17 00:00:00 2001 From: Will Da Silva Date: Thu, 3 Oct 2019 00:18:57 -0400 Subject: Add pride facts for 2020 --- bot/resources/pride/facts.json | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 bot/resources/pride/facts.json (limited to 'bot') diff --git a/bot/resources/pride/facts.json b/bot/resources/pride/facts.json new file mode 100644 index 00000000..0b7a4358 --- /dev/null +++ b/bot/resources/pride/facts.json @@ -0,0 +1,34 @@ +{ + "2020": [ + "No research has conclusively proven what causes homosexuality, heterosexuality, or bisexuality.", + "Records of same-sex relationships have been found in nearly every culture throughout history with varying degrees of acceptance.", + "Various slurs targeting queer people have been reappropriated by them, notably \"dyke\", and \"queer\".", + "October 8th is lesbian pride day!", + "Historians note that in some cultures, some homosexual behavior was not viewed as effeminate but as evidence of a man's masculinity. Examples include the Celtic and Greek cultures.", + "Every year for the past few decades, a greater percentage of people have identified as being homosexual or bisexual.", + "A large proportion of people, both in and out of the LGBTQ+ communities, do not believe bisexuality exists. This is known as bisexual erasure.", + "Queer people commit suicide are much more common in politically conservative regions, and also more common than non-queer people in general.", + "Stormé DeLarverie, a lesbian drag king, had a \"scuffle\" with the police which many claim is what kicked off the Stonewall Riots.", + "Gilbert Baker, also known as the “Gay Betsy Ross,” designed the rainbow flag, or Pride Flag, in San Francisco in 1978.", + "The rainbow pride flag is well-known, but there are flags for most labeled gender/sexual minorities.", + "In 1968, Dr. John Money performed the first complete male-to-female sex-change operation in the United States at Johns Hopkins University.", + "At the age of 24, Leonardo Da Vinci was arrested for having sex with a man. He was eventually acquitted.", + "Alfred Kinsey, the creator of the Kinsey scale, is known as \"the father of the sexual revolution\". The Kinsey scale was created in order to demonstrate that sexuality does not fit into two strict categories: homosexual and heterosexual. Instead, Kinsey believed that sexuality is fluid and subject to change over time.", + "The Kinsey scale ranges from 0, which is exclusively heterosexual, to 6, which is exclusively homosexual.", + "November 20th is the Transgender Day of Remembrance, which is a day to memorialize those who have been murdered as a result of transphobia.", + "The pink triangle was the symbol that queer people were required to wear in Nazi concentration camps during WWII. The symbol has since been reclaimed as a positive symbol of self-identity.", + "The term \"AC/DC\" has been used to refer to bisexuals.", + "September 23rd is bisexual pride day!", + "Pride Day refers to celebrations that typically take place in June that commemorate the Stonewall Inn riots of June 28, 1969. These riots are considered the birth of the modern gay civil rights movement.", + "A \"beard\" is someone of the opposite sex who knowingly dates a closeted lesbian or gay man to provide that person with a heterosexual \"disguise\", usually for family or career purposes.", + "In Nigeria, where homosexuality is punishable by death by stoning, a post-grad student claimed he had proved being gay was wrong by using magnets. He hoped to win a Nobel Prize for his research. He has not received one.", + "In 1982, the Gay Related Immune Disorder (GRID) was renamed Acquired Immune Deficiency Syndrome (AIDS).", + "The word \"lesbian\" is derived from the Greek island Lesbos, home of Greek poet Sappho. Her poetry proclaimed her love for women, and their beauty.", + "Nearly all bonobos (a kind of chimpanzee) appear to be bisexual.", + "Homosexual behavior has been observed in 1,500 animal species and is most widespread among animals with a complex herd life.", + "Many queer people identify their sexual orientation independently from their romantic orientation. For instance, it is possible to be sexually attracted to both women and men, but only be romantically attracted to one of them.", + "In 2005, Swedish researchers found that when straight men smelled a female urine compound, their hypothalamus lit up in brain images. In gay men, it did not. Instead, homosexual men's hypothalamus lit up when they smelled the male-sweat compound, which was the same way straight women responded.", + "As of 2019-10-02, there are 17 states in the United States of America where queer people can be fired for being queer. In most other states, there is minimal protection offered, often only for public employees.", + "In 1985, an official Star Trek novel was published with scenes depicting Kirk and Spock as lovers. These parts were largely removed, which made the original into a collector's item." + ] +} \ No newline at end of file -- cgit v1.2.3 From 1ef715bd24a08abb6b2c9b9a23edb46ac9838787 Mon Sep 17 00:00:00 2001 From: Will Da Silva Date: Thu, 3 Oct 2019 03:08:36 -0400 Subject: Add pride facts cog --- bot/seasons/pride/pride_facts.py | 83 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) create mode 100644 bot/seasons/pride/pride_facts.py (limited to 'bot') diff --git a/bot/seasons/pride/pride_facts.py b/bot/seasons/pride/pride_facts.py new file mode 100644 index 00000000..90804d65 --- /dev/null +++ b/bot/seasons/pride/pride_facts.py @@ -0,0 +1,83 @@ +from datetime import datetime +import json +import logging +from typing import Union +import random +from pathlib import Path + +import dateutil.parser +from discord.ext import commands + +log = logging.getLogger(__name__) + + +class PrideFacts(commands.Cog): + """Provides a new fact every day during the Pride season!""" + + def __init__(self, bot: commands.Bot): + self.bot = bot + self.facts = self.load_facts() + + @staticmethod + def load_facts() -> dict: + """Loads a dictionary of years mapping to lists of facts.""" + with open(Path("bot/resources/pride/facts.json"), "r", encoding="utf-8") as f: + return json.load(f) + + async def random_fact(self, ctx: commands.Context): + """Provides a fact from any valid day.""" + now = datetime.utcnow() + previous_years_facts = (self.facts[x] for x in self.facts.keys() if int(x) < now.year) + current_year_facts = self.facts.get(str(now.year), [])[:now.day] + previous_facts = current_year_facts + [x for y in previous_years_facts for x in y] + try: + await ctx.send(random.choice(previous_facts)) + except IndexError: + await ctx.send("No facts available") + + async def select_fact(self, ctx: commands.Context, _date: Union[str, datetime]): + """Provides the fact for the specified day, if valid.""" + now = datetime.utcnow() + if isinstance(_date, str): + try: + date = dateutil.parser.parse(_date, dayfirst=True, fuzzy=True) + except (ValueError, OverflowError) as err: + await ctx.send(f"Error parsing date: {err}") + return + else: + date = _date + if date.year < now.year or (date.year == now.year and date.day <= now.day): + try: + await ctx.send(self.facts[str(date.year)][date.day - 1]) + except KeyError: + await ctx.send(f"The year {date.year} is not yet supported") + return + except IndexError: + await ctx.send(f"Day {date.day} of {date.year} is not yet support") + return + else: + await ctx.send("The fact for the selected day is not yet available.") + + @commands.command(name="pridefact", aliases=["pridefacts"]) + async def pridefact(self, ctx: commands.Context) -> None: + """ + Sends a message with a pride fact of the day. + + If "random" is given as an argument, a random previous fact will be provided. + + If a date is given as an argument, and the date is in the past, the fact from that day + will be provided. + """ + message_body = ctx.message.content[len(ctx.invoked_with) + 2:] + if message_body == "": + await self.select_fact(ctx, datetime.utcnow()) + elif message_body.lower().startswith("rand"): + await self.random_fact(ctx) + else: + await self.select_fact(ctx, message_body) + + +def setup(bot: commands.Bot) -> None: + """Cog loader for pride facts.""" + bot.add_cog(PrideFacts(bot)) + log.info("Pride facts cog loaded!") -- cgit v1.2.3 From 000110847972c6d74f57830737f599e0efe9bd3e Mon Sep 17 00:00:00 2001 From: Will Da Silva Date: Thu, 3 Oct 2019 03:28:22 -0400 Subject: Minor improvements for pride facts cog --- bot/resources/pride/facts.json | 6 +++--- bot/seasons/pride/pride_facts.py | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'bot') diff --git a/bot/resources/pride/facts.json b/bot/resources/pride/facts.json index 0b7a4358..f6597201 100644 --- a/bot/resources/pride/facts.json +++ b/bot/resources/pride/facts.json @@ -3,11 +3,11 @@ "No research has conclusively proven what causes homosexuality, heterosexuality, or bisexuality.", "Records of same-sex relationships have been found in nearly every culture throughout history with varying degrees of acceptance.", "Various slurs targeting queer people have been reappropriated by them, notably \"dyke\", and \"queer\".", - "October 8th is lesbian pride day!", - "Historians note that in some cultures, some homosexual behavior was not viewed as effeminate but as evidence of a man's masculinity. Examples include the Celtic and Greek cultures.", - "Every year for the past few decades, a greater percentage of people have identified as being homosexual or bisexual.", + "Historians note that in some cultures, some homosexual behavior was not viewed as effeminate, but as evidence of a man's masculinity. Examples include the Celtic and Greek cultures.", + "Over time, the proportion of people who identify as homosexual or bisexual appears to be increasing. It is not know if this is because they feel it is safer to come out, or if the actual numbers of homosexual/bisexual people are increasing.", "A large proportion of people, both in and out of the LGBTQ+ communities, do not believe bisexuality exists. This is known as bisexual erasure.", "Queer people commit suicide are much more common in politically conservative regions, and also more common than non-queer people in general.", + "October 8th is lesbian pride day!", "Stormé DeLarverie, a lesbian drag king, had a \"scuffle\" with the police which many claim is what kicked off the Stonewall Riots.", "Gilbert Baker, also known as the “Gay Betsy Ross,” designed the rainbow flag, or Pride Flag, in San Francisco in 1978.", "The rainbow pride flag is well-known, but there are flags for most labeled gender/sexual minorities.", diff --git a/bot/seasons/pride/pride_facts.py b/bot/seasons/pride/pride_facts.py index 90804d65..d691b7e7 100644 --- a/bot/seasons/pride/pride_facts.py +++ b/bot/seasons/pride/pride_facts.py @@ -40,7 +40,7 @@ class PrideFacts(commands.Cog): now = datetime.utcnow() if isinstance(_date, str): try: - date = dateutil.parser.parse(_date, dayfirst=True, fuzzy=True) + date = dateutil.parser.parse(_date, dayfirst=False, yearfirst=False, fuzzy=True) except (ValueError, OverflowError) as err: await ctx.send(f"Error parsing date: {err}") return -- cgit v1.2.3 From 76caa7577230a9a5617c9ea9ba28190b2082b571 Mon Sep 17 00:00:00 2001 From: Will Da Silva Date: Thu, 3 Oct 2019 03:46:29 -0400 Subject: Fix linter issues I don't understand why these linter issues don't come up when I run flake8 myself --- bot/seasons/pride/pride_facts.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'bot') diff --git a/bot/seasons/pride/pride_facts.py b/bot/seasons/pride/pride_facts.py index d691b7e7..3673fa95 100644 --- a/bot/seasons/pride/pride_facts.py +++ b/bot/seasons/pride/pride_facts.py @@ -1,8 +1,8 @@ -from datetime import datetime import json +from datetime import datetime import logging -from typing import Union import random +from typing import Union from pathlib import Path import dateutil.parser @@ -24,7 +24,7 @@ class PrideFacts(commands.Cog): with open(Path("bot/resources/pride/facts.json"), "r", encoding="utf-8") as f: return json.load(f) - async def random_fact(self, ctx: commands.Context): + async def random_fact(self, ctx: commands.Context) -> None: """Provides a fact from any valid day.""" now = datetime.utcnow() previous_years_facts = (self.facts[x] for x in self.facts.keys() if int(x) < now.year) @@ -35,7 +35,7 @@ class PrideFacts(commands.Cog): except IndexError: await ctx.send("No facts available") - async def select_fact(self, ctx: commands.Context, _date: Union[str, datetime]): + async def select_fact(self, ctx: commands.Context, _date: Union[str, datetime]) -> None: """Provides the fact for the specified day, if valid.""" now = datetime.utcnow() if isinstance(_date, str): -- cgit v1.2.3 From c03db25cfda6e5bf302c1fcd8ad682422ad144bf Mon Sep 17 00:00:00 2001 From: Will Da Silva Date: Thu, 3 Oct 2019 03:49:40 -0400 Subject: Fix linter issues --- bot/seasons/pride/pride_facts.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'bot') diff --git a/bot/seasons/pride/pride_facts.py b/bot/seasons/pride/pride_facts.py index 3673fa95..95ca4d24 100644 --- a/bot/seasons/pride/pride_facts.py +++ b/bot/seasons/pride/pride_facts.py @@ -1,9 +1,9 @@ import json -from datetime import datetime import logging import random -from typing import Union +from datetime import datetime from pathlib import Path +from typing import Union import dateutil.parser from discord.ext import commands -- cgit v1.2.3 From 3492e0871d08523755ecc62c3e1559617d5360d4 Mon Sep 17 00:00:00 2001 From: Will Da Silva Date: Thu, 3 Oct 2019 13:17:21 -0400 Subject: Add task to post daily pride fact Also, pride facts are posted as embeds now --- bot/seasons/pride/pride_facts.py | 49 +++++++++++++++++++++++++++++----------- 1 file changed, 36 insertions(+), 13 deletions(-) (limited to 'bot') diff --git a/bot/seasons/pride/pride_facts.py b/bot/seasons/pride/pride_facts.py index 95ca4d24..d2ea0461 100644 --- a/bot/seasons/pride/pride_facts.py +++ b/bot/seasons/pride/pride_facts.py @@ -1,3 +1,4 @@ +import asyncio import json import logging import random @@ -6,10 +7,16 @@ from pathlib import Path from typing import Union import dateutil.parser +import discord from discord.ext import commands +from bot.constants import Channels +from bot.constants import Colours + log = logging.getLogger(__name__) +Sendable = Union[commands.Context, discord.TextChannel] + class PrideFacts(commands.Cog): """Provides a new fact every day during the Pride season!""" @@ -24,39 +31,46 @@ class PrideFacts(commands.Cog): with open(Path("bot/resources/pride/facts.json"), "r", encoding="utf-8") as f: return json.load(f) - async def random_fact(self, ctx: commands.Context) -> None: - """Provides a fact from any valid day.""" + async def send_pride_fact_daily(self) -> None: + """Background task to post the daily pride fact every day.""" + channel = self.bot.get_channel(Channels.seasonalbot_chat) + while True: + await self.send_select_fact(channel, datetime.utcnow()) + await asyncio.sleep(24 * 60 * 60) + + async def send_random_fact(self, ctx: commands.Context) -> None: + """Provides a fact from any previous day, or today.""" now = datetime.utcnow() previous_years_facts = (self.facts[x] for x in self.facts.keys() if int(x) < now.year) current_year_facts = self.facts.get(str(now.year), [])[:now.day] previous_facts = current_year_facts + [x for y in previous_years_facts for x in y] try: - await ctx.send(random.choice(previous_facts)) + await ctx.send(embed=self.make_embed(random.choice(previous_facts))) except IndexError: await ctx.send("No facts available") - async def select_fact(self, ctx: commands.Context, _date: Union[str, datetime]) -> None: - """Provides the fact for the specified day, if valid.""" + async def send_select_fact(self, target: Sendable, _date: Union[str, datetime]) -> None: + """Provides the fact for the specified day, if the day is today, or is in the past.""" now = datetime.utcnow() if isinstance(_date, str): try: date = dateutil.parser.parse(_date, dayfirst=False, yearfirst=False, fuzzy=True) except (ValueError, OverflowError) as err: - await ctx.send(f"Error parsing date: {err}") + await target.send(f"Error parsing date: {err}") return else: date = _date if date.year < now.year or (date.year == now.year and date.day <= now.day): try: - await ctx.send(self.facts[str(date.year)][date.day - 1]) + await target.send(embed=self.make_embed(self.facts[str(date.year)][date.day - 1])) except KeyError: - await ctx.send(f"The year {date.year} is not yet supported") + await target.send(f"The year {date.year} is not yet supported") return except IndexError: - await ctx.send(f"Day {date.day} of {date.year} is not yet support") + await target.send(f"Day {date.day} of {date.year} is not yet support") return else: - await ctx.send("The fact for the selected day is not yet available.") + await target.send("The fact for the selected day is not yet available.") @commands.command(name="pridefact", aliases=["pridefacts"]) async def pridefact(self, ctx: commands.Context) -> None: @@ -70,14 +84,23 @@ class PrideFacts(commands.Cog): """ message_body = ctx.message.content[len(ctx.invoked_with) + 2:] if message_body == "": - await self.select_fact(ctx, datetime.utcnow()) + await self.send_select_fact(ctx, datetime.utcnow()) elif message_body.lower().startswith("rand"): - await self.random_fact(ctx) + await self.send_random_fact(ctx) else: - await self.select_fact(ctx, message_body) + await self.send_select_fact(ctx, message_body) + + def make_embed(self, fact) -> discord.Embed: + """Makes a nice embed for the fact to be sent.""" + return discord.Embed( + colour=Colours.pink, + title="Pride Fact!", + description=fact + ) def setup(bot: commands.Bot) -> None: """Cog loader for pride facts.""" + bot.loop.create_task(PrideFacts(bot).send_pride_fact_daily()) bot.add_cog(PrideFacts(bot)) log.info("Pride facts cog loaded!") -- cgit v1.2.3 From bcfe86418da57a0c66fc077c1607171b29448aca Mon Sep 17 00:00:00 2001 From: Will Da Silva Date: Thu, 3 Oct 2019 13:34:11 -0400 Subject: Fix linter issue --- bot/seasons/pride/pride_facts.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'bot') diff --git a/bot/seasons/pride/pride_facts.py b/bot/seasons/pride/pride_facts.py index d2ea0461..b705bfb4 100644 --- a/bot/seasons/pride/pride_facts.py +++ b/bot/seasons/pride/pride_facts.py @@ -90,7 +90,7 @@ class PrideFacts(commands.Cog): else: await self.send_select_fact(ctx, message_body) - def make_embed(self, fact) -> discord.Embed: + def make_embed(self, fact: str) -> discord.Embed: """Makes a nice embed for the fact to be sent.""" return discord.Embed( colour=Colours.pink, -- cgit v1.2.3 From a7c7fb7aacc477eb498c3872adf71d10cb798f67 Mon Sep 17 00:00:00 2001 From: vivax3794 <51753506+vivax3794@users.noreply.github.com> Date: Sat, 5 Oct 2019 06:30:48 +0200 Subject: added beginner --- bot/seasons/halloween/hacktober-issue-finder.py | 50 ++++++++++++++++++------- 1 file changed, 36 insertions(+), 14 deletions(-) (limited to 'bot') diff --git a/bot/seasons/halloween/hacktober-issue-finder.py b/bot/seasons/halloween/hacktober-issue-finder.py index 54f205cf..3c4780a9 100644 --- a/bot/seasons/halloween/hacktober-issue-finder.py +++ b/bot/seasons/halloween/hacktober-issue-finder.py @@ -1,7 +1,7 @@ import datetime import logging import random -from typing import Dict, List +from typing import Dict, List, Optional import aiohttp import discord @@ -9,7 +9,7 @@ from discord.ext import commands log = logging.getLogger(__name__) -URL = "https://api.github.com/search/issues?q=label:hacktoberfest+language:python+state:open&per_page=100" +URL = "https://api.github.com/search/issues?per_page=100&q=is:issue+label:hacktoberfest+language:python+state:open" HEADERS = {"Accept": "application / vnd.github.v3 + json"} @@ -18,34 +18,55 @@ class HacktoberIssues(commands.Cog): def __init__(self, bot: commands.Bot): self.bot = bot - self.cache = None - self.cache_timer = datetime.datetime(1, 1, 1) + self.cache_normal = None + self.cache_timer_normal = datetime.datetime(1, 1, 1) + self.cache_beginner = None + self.cache_timer_beginner = datetime.datetime(1, 1, 1) @commands.command() - async def hacktoberissues(self, ctx: commands.Context) -> None: + async def hacktoberissues(self, ctx: commands.Context, option: str = "") -> None: """Get a random python hacktober issue from Github.""" with ctx.typing(): - issues = await self.get_issues(ctx) + issues = await self.get_issues(ctx, option) + if issues is None: + return issue = random.choice(issues) embed = self.format_embed(issue) - await ctx.send(embed=embed) + await ctx.send(embed=embed) - async def get_issues(self, ctx: commands.Context) -> List[Dict]: + async def get_issues(self, ctx: commands.Context, option: str) -> Optional[List[Dict]]: """Get a list of the python issues with the label 'hacktoberfest' from the Github api.""" - if (ctx.message.created_at - self.cache_timer).seconds <= 60: - return self.cache + if option == "beginner": + if (ctx.message.created_at - self.cache_timer_beginner).seconds <= 60: + return self.cache_beginner + elif (ctx.message.created_at - self.cache_timer_normal).seconds <= 60: + return self.cache_normal async with aiohttp.ClientSession() as session: - # text = TEXT # + "+label:hacktober" + if option == "beginner": + url = URL + '+label:"good first issue"' + else: + url = URL - async with session.get(URL, headers=HEADERS) as response: + async with session.get(url, headers=HEADERS) as response: if response.status != 200: await ctx.send(f"ERROR: expected 200 status (got {response.status}) from the GitHub api.") await ctx.send(await response.text()) + return None data = await response.json() issues = data["items"] - self.cache = issues - self.cache_timer = ctx.message.created_at + + if len(issues) == 0: + await ctx.send(f"ERROR: no issues returned from GitHub api. with url: {response.url}") + return None + + if option == "beginner": + self.cache_beginner = issues + self.cache_timer_beginner = ctx.message.created_at + else: + self.cache_normal = issues + self.cache_timer_normal = ctx.message.created_at + return issues @staticmethod @@ -60,6 +81,7 @@ class HacktoberIssues(commands.Cog): embed.description = body embed.add_field(name="labels", value="\n".join(labels)) embed.url = issue_url + embed.set_footer(text=issue_url) return embed -- cgit v1.2.3 From cb90d1269dbad0a29fe0a03a7219428ff5a38f51 Mon Sep 17 00:00:00 2001 From: vivax3794 <51753506+vivax3794@users.noreply.github.com> Date: Sat, 5 Oct 2019 07:29:53 +0200 Subject: bug fixes --- bot/seasons/halloween/hacktober-issue-finder.py | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) (limited to 'bot') diff --git a/bot/seasons/halloween/hacktober-issue-finder.py b/bot/seasons/halloween/hacktober-issue-finder.py index 3c4780a9..a9cff610 100644 --- a/bot/seasons/halloween/hacktober-issue-finder.py +++ b/bot/seasons/halloween/hacktober-issue-finder.py @@ -1,7 +1,7 @@ import datetime import logging import random -from typing import Dict, List, Optional +from typing import Dict, Optional import aiohttp import discord @@ -27,14 +27,14 @@ class HacktoberIssues(commands.Cog): async def hacktoberissues(self, ctx: commands.Context, option: str = "") -> None: """Get a random python hacktober issue from Github.""" with ctx.typing(): - issues = await self.get_issues(ctx, option) + issues = (await self.get_issues(ctx, option))["items"] if issues is None: return issue = random.choice(issues) embed = self.format_embed(issue) await ctx.send(embed=embed) - async def get_issues(self, ctx: commands.Context, option: str) -> Optional[List[Dict]]: + async def get_issues(self, ctx: commands.Context, option: str) -> Optional[Dict]: """Get a list of the python issues with the label 'hacktoberfest' from the Github api.""" if option == "beginner": if (ctx.message.created_at - self.cache_timer_beginner).seconds <= 60: @@ -45,8 +45,14 @@ class HacktoberIssues(commands.Cog): async with aiohttp.ClientSession() as session: if option == "beginner": url = URL + '+label:"good first issue"' + if self.cache_beginner is not None: + page = random.randint(1, min(1000, self.cache_beginner["total_count"]) // 100) + url += f"&page={page}" else: url = URL + if self.cache_normal is not None: + page = random.randint(1, min(1000, self.cache_normal["total_count"])) + url += f"&page={page}" async with session.get(url, headers=HEADERS) as response: if response.status != 200: @@ -54,20 +60,19 @@ class HacktoberIssues(commands.Cog): await ctx.send(await response.text()) return None data = await response.json() - issues = data["items"] - if len(issues) == 0: + if len(data["items"]) == 0: await ctx.send(f"ERROR: no issues returned from GitHub api. with url: {response.url}") return None if option == "beginner": - self.cache_beginner = issues + self.cache_beginner = data self.cache_timer_beginner = ctx.message.created_at else: - self.cache_normal = issues + self.cache_normal = data self.cache_timer_normal = ctx.message.created_at - return issues + return data @staticmethod def format_embed(issue: Dict) -> discord.Embed: -- cgit v1.2.3 From 3e7f5904aed66ab753e5d186cfcd5f63adc58ede Mon Sep 17 00:00:00 2001 From: vivax3794 <51753506+vivax3794@users.noreply.github.com> Date: Mon, 7 Oct 2019 15:03:29 +0200 Subject: Added logging to "get_issues". --- bot/seasons/halloween/hacktober-issue-finder.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'bot') diff --git a/bot/seasons/halloween/hacktober-issue-finder.py b/bot/seasons/halloween/hacktober-issue-finder.py index a9cff610..57273ee7 100644 --- a/bot/seasons/halloween/hacktober-issue-finder.py +++ b/bot/seasons/halloween/hacktober-issue-finder.py @@ -27,10 +27,10 @@ class HacktoberIssues(commands.Cog): async def hacktoberissues(self, ctx: commands.Context, option: str = "") -> None: """Get a random python hacktober issue from Github.""" with ctx.typing(): - issues = (await self.get_issues(ctx, option))["items"] + issues = await self.get_issues(ctx, option) if issues is None: return - issue = random.choice(issues) + issue = random.choice(issues["items"]) embed = self.format_embed(issue) await ctx.send(embed=embed) @@ -38,8 +38,10 @@ class HacktoberIssues(commands.Cog): """Get a list of the python issues with the label 'hacktoberfest' from the Github api.""" if option == "beginner": if (ctx.message.created_at - self.cache_timer_beginner).seconds <= 60: + log.debug("using cache") return self.cache_beginner elif (ctx.message.created_at - self.cache_timer_normal).seconds <= 60: + log.debug("using cache") return self.cache_normal async with aiohttp.ClientSession() as session: @@ -54,14 +56,17 @@ class HacktoberIssues(commands.Cog): page = random.randint(1, min(1000, self.cache_normal["total_count"])) url += f"&page={page}" + log.debug(f"making api request to url: {url}") async with session.get(url, headers=HEADERS) as response: if response.status != 200: + log.error(f"expected 200 status (got {response.status}) from the GitHub api.") await ctx.send(f"ERROR: expected 200 status (got {response.status}) from the GitHub api.") await ctx.send(await response.text()) return None data = await response.json() if len(data["items"]) == 0: + log.error(f"no issues returned from GitHub api. with url: {response.url}") await ctx.send(f"ERROR: no issues returned from GitHub api. with url: {response.url}") return None -- cgit v1.2.3 From d38f7c384487c5ee3da9fca1cff8df5dfb84ec21 Mon Sep 17 00:00:00 2001 From: vivax3794 <51753506+vivax3794@users.noreply.github.com> Date: Sat, 12 Oct 2019 02:18:32 +0200 Subject: Added Beginner to docstring. --- bot/seasons/halloween/hacktober-issue-finder.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'bot') diff --git a/bot/seasons/halloween/hacktober-issue-finder.py b/bot/seasons/halloween/hacktober-issue-finder.py index 57273ee7..5978eb95 100644 --- a/bot/seasons/halloween/hacktober-issue-finder.py +++ b/bot/seasons/halloween/hacktober-issue-finder.py @@ -25,7 +25,12 @@ class HacktoberIssues(commands.Cog): @commands.command() async def hacktoberissues(self, ctx: commands.Context, option: str = "") -> None: - """Get a random python hacktober issue from Github.""" + """ + Get a random python hacktober issue from Github. + + If the command is run with beginner (`!hacktoberissues beginner`): + It will also narrow it down to the "first good issue label". + """ with ctx.typing(): issues = await self.get_issues(ctx, option) if issues is None: -- cgit v1.2.3 From 2ed67377928c55ab766e08c17e392eae5667f0e9 Mon Sep 17 00:00:00 2001 From: vivax3794 <51753506+vivax3794@users.noreply.github.com> Date: Sat, 12 Oct 2019 02:19:14 +0200 Subject: fixed " misplace meant. --- bot/seasons/halloween/hacktober-issue-finder.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'bot') diff --git a/bot/seasons/halloween/hacktober-issue-finder.py b/bot/seasons/halloween/hacktober-issue-finder.py index 5978eb95..8b8ea41d 100644 --- a/bot/seasons/halloween/hacktober-issue-finder.py +++ b/bot/seasons/halloween/hacktober-issue-finder.py @@ -29,7 +29,7 @@ class HacktoberIssues(commands.Cog): Get a random python hacktober issue from Github. If the command is run with beginner (`!hacktoberissues beginner`): - It will also narrow it down to the "first good issue label". + It will also narrow it down to the "first good issue" label. """ with ctx.typing(): issues = await self.get_issues(ctx, option) -- cgit v1.2.3 From fd1a2a68139f83a2313e18ec42cba1b4f9220e7c Mon Sep 17 00:00:00 2001 From: vivax3794 <51753506+vivax3794@users.noreply.github.com> Date: Sat, 12 Oct 2019 02:22:45 +0200 Subject: had the wrong prefix in docstring xD --- bot/seasons/halloween/hacktober-issue-finder.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'bot') diff --git a/bot/seasons/halloween/hacktober-issue-finder.py b/bot/seasons/halloween/hacktober-issue-finder.py index 8b8ea41d..2f1d6ac7 100644 --- a/bot/seasons/halloween/hacktober-issue-finder.py +++ b/bot/seasons/halloween/hacktober-issue-finder.py @@ -28,7 +28,7 @@ class HacktoberIssues(commands.Cog): """ Get a random python hacktober issue from Github. - If the command is run with beginner (`!hacktoberissues beginner`): + If the command is run with beginner (`.hacktoberissues beginner`): It will also narrow it down to the "first good issue" label. """ with ctx.typing(): -- cgit v1.2.3