diff --git a/commands/admin.py b/commands/admin.py new file mode 100644 index 0000000..e69de29 diff --git a/commands/help.py b/commands/help.py new file mode 100644 index 0000000..31067f7 --- /dev/null +++ b/commands/help.py @@ -0,0 +1,41 @@ +from telegram import Update, InlineKeyboardButton, InlineKeyboardMarkup +from telegram.ext import ContextTypes, Application, CommandHandler, CallbackQueryHandler +from settings import VARIOS, INTERACCION, MATEMATICAS +from util.messages import delete_user_message + +PAGES = [VARIOS, INTERACCION, MATEMATICAS] +ITEMS_PER_PAGE = 1 + +class Help: + def __init__(self, app: Application): + self.app = app + app.add_handler(CommandHandler("help", self.help)) + app.add_handler(CallbackQueryHandler(self.callback, pattern="^help_")) + + @delete_user_message + async def help(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: + await self.send_help(update, page=0) + + async def send_help(self, update: Update, page: int): + start_idx = page * ITEMS_PER_PAGE + end_idx = start_idx + ITEMS_PER_PAGE + text = "\n".join(PAGES[start_idx:end_idx]) + + keyboard = [] + if page > 0: + keyboard.append(InlineKeyboardButton("⬅️ Anterior", callback_data=f"help_{page-1}")) + if end_idx < len(PAGES): + keyboard.append(InlineKeyboardButton("➡️ Siguiente", callback_data=f"help_{page+1}")) + + reply_markup = InlineKeyboardMarkup([keyboard]) if keyboard else None + + if update.message: + await update.message.reply_text(f"**Ayuda {page+1}/{(len(PAGES)-1)//ITEMS_PER_PAGE + 1}**\n\n{text}", parse_mode="Markdown", reply_markup=reply_markup) + elif update.callback_query: + await update.callback_query.edit_message_text(f"**Ayuda {page+1}/{(len(PAGES)-1)//ITEMS_PER_PAGE + 1}**\n\n{text}", parse_mode="Markdown", reply_markup=reply_markup) + await update.callback_query.answer() + + async def callback(self, update: Update, context: ContextTypes.DEFAULT_TYPE): + query = update.callback_query + page = int(query.data.split("_")[1]) + await self.send_help(update, page=page) \ No newline at end of file diff --git a/commands/interaction.py b/commands/interaction.py new file mode 100644 index 0000000..80fa935 --- /dev/null +++ b/commands/interaction.py @@ -0,0 +1,553 @@ +from telegram import Update +from telegram.ext import ContextTypes, Application, CommandHandler +from time import time +from settings import BOT_OWNER, BOT_NAME, BOT_VERSION, BOT_LANG, BOT_TYPE, BOT_OWNER_ID +from random import randint, choice +from util.messages import delete_user_message +from util.anime import Anime + +class Interaction: + def __init__(self, app: Application): + self.app = app + self.anime = Anime() + + app.add_handler(CommandHandler("waifu", self.waifu)) + app.add_handler(CommandHandler("neko", self.neko)) + app.add_handler(CommandHandler("shinobu", self.shinobu)) + app.add_handler(CommandHandler("megumin", self.megumin)) + app.add_handler(CommandHandler("bully", self.bully)) + app.add_handler(CommandHandler("cuddle", self.cuddle)) + app.add_handler(CommandHandler("cry", self.cry)) + app.add_handler(CommandHandler("hug", self.hug)) + app.add_handler(CommandHandler("awoo", self.awoo)) + app.add_handler(CommandHandler("kiss", self.kiss)) + app.add_handler(CommandHandler("lick", self.lick)) + app.add_handler(CommandHandler("pat", self.pat)) + app.add_handler(CommandHandler("smug", self.smug)) + app.add_handler(CommandHandler("bonk", self.bonk)) + app.add_handler(CommandHandler("yeet", self.yeet)) + app.add_handler(CommandHandler("blush", self.blush)) + app.add_handler(CommandHandler("smile", self.smile)) + app.add_handler(CommandHandler("wave", self.wave)) + app.add_handler(CommandHandler("highfive", self.highfive)) + app.add_handler(CommandHandler("handhold", self.handhold)) + app.add_handler(CommandHandler("nom", self.nom)) + app.add_handler(CommandHandler("bite", self.bite)) + app.add_handler(CommandHandler("glomp", self.glomp)) + app.add_handler(CommandHandler("slap", self.slap)) + app.add_handler(CommandHandler("kill", self.kill)) + app.add_handler(CommandHandler("kick", self.kick)) + app.add_handler(CommandHandler("happy", self.happy)) + app.add_handler(CommandHandler("wink", self.wink)) + app.add_handler(CommandHandler("poke", self.poke)) + app.add_handler(CommandHandler("dance", self.dance)) + app.add_handler(CommandHandler("cringe", self.cringe)) + app.add_handler(CommandHandler("run", self.run)) + app.add_handler(CommandHandler("fbi", self.fbi)) + app.add_handler(CommandHandler("spank", self.spank)) + app.add_handler(CommandHandler("ship", self.ship)) + app.add_handler(CommandHandler("moan", self.moan)) + app.add_handler(CommandHandler("femboize", self.femboize)) + + @delete_user_message + async def waifu(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: + url = self.anime.sfw("waifu") + await update.effective_chat.send_animation( + animation=url, + caption=f"{update.effective_sender.first_name} ha pedido una waifu" + ) + + @delete_user_message + async def neko(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: + url = self.anime.sfw("neko") + await update.effective_chat.send_animation( + animation=url, + caption=f"{update.effective_sender.first_name} ha pedido un neko" + ) + + @delete_user_message + async def shinobu(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: + url = self.anime.sfw("shinobu") + await update.effective_chat.send_animation( + animation=url, + caption=f"{update.effective_sender.first_name} ha pedido una shinobu" + ) + + @delete_user_message + async def megumin(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: + url = self.anime.sfw("megumin") + await update.effective_chat.send_animation( + animation=url, + caption=f"{update.effective_sender.first_name} ha pedido una megumin" + ) + + @delete_user_message + async def bully(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: + if not context.args: + await update.effective_chat.send_message( + text=f"Debes especificar un usuario" + ) + return + + + user = context.args[0] + url = self.anime.sfw("bully") + await update.effective_chat.send_animation( + animation=url, + caption=f"{update.effective_sender.first_name} le ha hecho bullying a {user}" + ) + + @delete_user_message + async def cuddle(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: + if not context.args: + await update.effective_chat.send_message( + text=f"Debes especificar un usuario" + ) + return + + + user = context.args[0] + url = self.anime.sfw("cuddle") + await update.effective_chat.send_animation( + animation=url, + caption=f"{update.effective_sender.first_name} se ha acurrucado con {user} uwu" + ) + + @delete_user_message + async def cry(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: + url = self.anime.sfw("cry") + await update.effective_chat.send_animation( + animation=url, + caption=f"{update.effective_sender.first_name} se ha puesto a llorar :(" + ) + + @delete_user_message + async def hug(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: + if not context.args: + await update.effective_chat.send_message( + text=f"Debes especificar un usuario" + ) + return + + + user = context.args[0] + url = self.anime.sfw("hug") + await update.effective_chat.send_animation( + animation=url, + caption=f"{update.effective_sender.first_name} ha abrazado a {user}" + ) + + @delete_user_message + async def awoo(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: + url = self.anime.sfw("awoo") + await update.effective_chat.send_animation( + animation=url, + caption=f"{update.effective_sender.first_name} es un puto furro y ha pedido una foto de un furro" + ) + + @delete_user_message + async def kiss(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: + if not context.args: + await update.effective_chat.send_message( + text=f"Debes especificar un usuario" + ) + return + + + user = context.args[0] + url = self.anime.sfw("kiss") + await update.effective_chat.send_animation( + animation=url, + caption=f"{update.effective_sender.first_name} ha besado a {user} >///<" + ) + + @delete_user_message + async def lick(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: + if not context.args: + await update.effective_chat.send_message( + text=f"Debes especificar un usuario" + ) + return + + + user = context.args[0] + url = self.anime.sfw("lick") + await update.effective_chat.send_animation( + animation=url, + caption=f"{update.effective_sender.first_name} ha lamido a {user} OwO" + ) + + @delete_user_message + async def pat(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: + if not context.args: + await update.effective_chat.send_message( + text=f"Debes especificar un usuario" + ) + return + + + user = context.args[0] + url = self.anime.sfw("pat") + await update.effective_chat.send_animation( + animation=url, + caption=f"{update.effective_sender.first_name} ha acariciado a {user} >.<" + ) + + @delete_user_message + async def smug(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: + if not context.args: + await update.effective_chat.send_message( + text=f"Debes especificar un usuario" + ) + return + + + user = context.args[0] + url = self.anime.sfw("smug") + await update.effective_chat.send_animation( + animation=url, + caption=f"{update.effective_sender.first_name} se ha chuleado de {user}" + ) + + @delete_user_message + async def bonk(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: + if not context.args: + await update.effective_chat.send_message( + text=f"Debes especificar un usuario" + ) + return + + + user = context.args[0] + url = self.anime.sfw("bonk") + await update.effective_chat.send_animation( + animation=url, + caption=f"{update.effective_sender.first_name} le ha hecho bonk a {user}" + ) + + @delete_user_message + async def yeet(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: + if not context.args: + await update.effective_chat.send_message( + text=f"Debes especificar un usuario" + ) + return + + + user = context.args[0] + url = self.anime.sfw("yeet") + await update.effective_chat.send_animation( + animation=url, + caption=f"{update.effective_sender.first_name} ha lanzado a {user} a chuparla XD" + ) + + @delete_user_message + async def blush(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: + url = self.anime.sfw("blush") + await update.effective_chat.send_animation( + animation=url, + caption=f"{update.effective_sender.first_name} se ha sonrojado >///<" + ) + + @delete_user_message + async def smile(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: + url = self.anime.sfw("smile") + await update.effective_chat.send_animation( + animation=url, + caption=f"{update.effective_sender.first_name} ha sonreido" + ) + + @delete_user_message + async def wave(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: + if not context.args: + await update.effective_chat.send_message( + text=f"Debes especificar un usuario" + ) + return + + + user = context.args[0] + url = self.anime.sfw("wave") + await update.effective_chat.send_animation( + animation=url, + caption=f"{update.effective_sender.first_name} ha saludado a {user}" + ) + + @delete_user_message + async def highfive(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: + if not context.args: + await update.effective_chat.send_message( + text=f"Debes especificar un usuario" + ) + return + + + user = context.args[0] + url = self.anime.sfw("highfive") + await update.effective_chat.send_animation( + animation=url, + caption=f"{update.effective_sender.first_name} a chocado a {user} ;D" + ) + + @delete_user_message + async def handhold(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: + if not context.args: + await update.effective_chat.send_message( + text=f"Debes especificar un usuario" + ) + return + + + user = context.args[0] + url = self.anime.sfw("handhold") + await update.effective_chat.send_animation( + animation=url, + caption=f"{update.effective_sender.first_name} le ha cogido la manita a {user} u.u" + ) + + @delete_user_message + async def nom(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: + url = self.anime.sfw("nom") + await update.effective_chat.send_animation( + animation=url, + caption=f"{update.effective_sender.first_name} se ha puesto a comer algo rico" + ) + + @delete_user_message + async def bite(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: + if not context.args: + await update.effective_chat.send_message( + text=f"Debes especificar un usuario" + ) + return + + + user = context.args[0] + url = self.anime.sfw("bite") + await update.effective_chat.send_animation( + animation=url, + caption=f"{update.effective_sender.first_name} ha mordido a {user} ùwú" + ) + + @delete_user_message + async def glomp(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: + if not context.args: + await update.effective_chat.send_message( + text=f"Debes especificar un usuario" + ) + return + + + user = context.args[0] + url = self.anime.sfw("glomp") + await update.effective_chat.send_animation( + animation=url, + caption=f"{update.effective_sender.first_name} se ha abalanzado sobre {user}" + ) + + @delete_user_message + async def slap(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: + if not context.args: + await update.effective_chat.send_message( + text=f"Debes especificar un usuario" + ) + return + + + user = context.args[0] + url = self.anime.sfw("slap") + await update.effective_chat.send_animation( + animation=url, + caption=f"{update.effective_sender.first_name} le ha dado una bofetada a {user}" + ) + + @delete_user_message + async def kill(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: + if not context.args: + await update.effective_chat.send_message( + text=f"Debes especificar un usuario" + ) + return + + + user = context.args[0] + url = self.anime.sfw("kill") + await update.effective_chat.send_animation( + animation=url, + caption=f"{update.effective_sender.first_name} ha matado a {user} 💀" + ) + + @delete_user_message + async def kick(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: + if not context.args: + await update.effective_chat.send_message( + text=f"Debes especificar un usuario" + ) + return + + + user = context.args[0] + url = self.anime.sfw("kick") + await update.effective_chat.send_animation( + animation=url, + caption=f"{update.effective_sender.first_name} le ha pegado una patada a {user}" + ) + + @delete_user_message + async def happy(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: + url = self.anime.sfw("happy") + await update.effective_chat.send_animation( + animation=url, + caption=f"{update.effective_sender.first_name} está feliz :D" + ) + + @delete_user_message + async def wink(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: + if not context.args: + await update.effective_chat.send_message( + text=f"Debes especificar un usuario" + ) + return + + + user = context.args[0] + url = self.anime.sfw("wink") + await update.effective_chat.send_animation( + animation=url, + caption=f"{update.effective_sender.first_name} le ha guiñado el ojo a {user} ;)" + ) + + @delete_user_message + async def poke(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: + if not context.args: + await update.effective_chat.send_message( + text=f"Debes especificar un usuario" + ) + return + + + user = context.args[0] + url = self.anime.sfw("poke") + await update.effective_chat.send_animation( + animation=url, + caption=f"{update.effective_sender.first_name} está molestando a {user} ù.ú" + ) + + @delete_user_message + async def dance(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: + url = self.anime.sfw("dance") + await update.effective_chat.send_animation( + animation=url, + caption=f"{update.effective_sender.first_name} se ha puesto a bailar" + ) + + @delete_user_message + async def cringe(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: + if not context.args: + await update.effective_chat.send_message( + text=f"Debes especificar un usuario" + ) + return + + + user = context.args[0] + caption=f"{update.effective_sender.first_name} le ha dado cringe lo que ha dicho {user}" + with open("data/images/interaction/cringe.gif", "rb") as gif: + await update.effective_chat.send_animation( + animation=gif, + caption=caption, + disable_notification=True + ) + + + @delete_user_message + async def run(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: + caption = f"{update.effective_sender.first_name} ha huido" + with open("data/images/interaction/run.gif", "rb") as gif: + await update.effective_chat.send_animation( + animation=gif, + caption=caption, + disable_notification=True + ) + + @delete_user_message + async def fbi(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: + if not context.args: + await update.effective_chat.send_message( + text=f"Debes especificar un usuario" + ) + return + + + user = context.args[0] + caption = f"{update.effective_sender.first_name} ha llamado al FBI! Corre {user}!!!!" + with open("data/images/interaction/fbi.gif", "rb") as gif: + await update.effective_chat.send_animation( + animation=gif, + caption=caption, + disable_notification=True + ) + + @delete_user_message + async def spank(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: + if not context.args: + await update.effective_chat.send_message( + text=f"Debes especificar un usuario" + ) + return + + + user = context.args[0] + caption = f"{update.effective_sender.first_name} le ha dado una nalgada a {user}" + with open("data/images/interaction/spank.gif", "rb") as gif: + await update.effective_chat.send_animation( + animation=gif, + caption=caption, + disable_notification=True + ) + + @delete_user_message + async def ship(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: + if not context.args: + await update.effective_chat.send_message( + text=f"Debes especificar dos usuarios" + ) + return + + user1 = context.args[0] + user2 = context.args[1] + caption = f"{user1} x {user2} tienen una compatibilidad del {randint(0,100)}%" + with open("data/images/interaction/ship.gif", "rb") as gif: + await update.effective_chat.send_animation( + animation=gif, + caption=caption, + disable_notification=True + ) + + @delete_user_message + async def moan(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: + caption = f"{update.effective_sender.first_name} ha gemido como una perra" + with open("data/images/interaction/moan.gif", "rb") as gif: + await update.effective_chat.send_animation( + animation=gif, + caption=caption, + disable_notification=True + ) + + @delete_user_message + async def femboize(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: + if not context.args: + await update.effective_chat.send_message( + text=f"Debes especificar un usuario" + ) + return + + + user = context.args[0] + caption = f"{update.effective_sender.first_name} ha convertido en femboy a {user}" + with open("data/images/interaction/femboy.png", "rb") as png: + await update.effective_chat.send_photo( + photo=png, + caption=caption, + disable_notification=True + ) \ No newline at end of file diff --git a/commands/math.py b/commands/math.py new file mode 100644 index 0000000..61b4808 --- /dev/null +++ b/commands/math.py @@ -0,0 +1,175 @@ +from telegram import Update +from telegram.ext import ContextTypes, Application, CommandHandler +from random import randint, choice +from util.messages import delete_user_message +import matplotlib.pyplot as plt +import numpy as np +from util.numbers import is_even, is_prime +from settings import GRAPH_PATH +from matplotlib.patches import Circle + +class Math: + def __init__(self, app: Application): + self.app = app + app.add_handler(CommandHandler("calcular", self.calculate)) + app.add_handler(CommandHandler("par", self.even)) + app.add_handler(CommandHandler("primo", self.prime)) + app.add_handler(CommandHandler("seno", self.sine)) + app.add_handler(CommandHandler("coseno", self.cosine)) + app.add_handler(CommandHandler("recta", self.rect)) + app.add_handler(CommandHandler("parabola", self.parable)) + app.add_handler(CommandHandler("circunferencia", self.circle)) + app.add_handler(CommandHandler("log", self.log)) + app.add_handler(CommandHandler("exp", self.exp)) + + @delete_user_message + async def calculate(self, update:Update, context: ContextTypes.DEFAULT_TYPE) -> None: + if not context.args: + await update.effective_chat.send_message( + text="Debes especificar una expresión matemática", + disable_notification=True + ) + return + + expression = " ".join(context.args) + try: + result = eval(expression) + await update.effective_chat.send_message( + text=f"El resultado de {expression} es {result}", + disable_notification=True + ) + except Exception as e: + await update.effective_chat.send_message( + text=f"Error al calcular la expresión: {e}", + disable_notification=True + ) + + @delete_user_message + async def even(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: + if not context.args: + await update.effective_chat.send_message( + text="Debes especificar un número", + disable_notification=True + ) + return + + number = int(context.args[0]) + await update.effective_chat.send_message( + text=f"{number} es un número par." if is_even(number) else f"{number} es un número impar.", + disable_notification=True + ) + + @delete_user_message + async def prime(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: + if not context.args: + await update.effective_chat.send_message( + text="Debes especificar un número", + disable_notification=True + ) + return + + number = int(context.args[0]) + await update.effective_chat.send_message( + text=f"{number} es un número primo." if is_prime(number) else f"{number} es un número compuesto.", + disable_notification=True + ) + + async def send_graph(self, update: Update): + await update.effective_chat.send_photo(open(GRAPH_PATH, "rb")) + plt.clf() + + @delete_user_message + async def sine(self, update: Update, context: ContextTypes.DEFAULT_TYPE): + if len(context.args) < 2: + await update.effective_chat.send_message("Debes dar a y k: /grafseno a k") + return + a, k = map(int, context.args[:2]) + x = np.linspace(0, 2*np.pi, 400) + y = a * np.sin(k*x) + plt.axhline(0, color="black") + plt.plot(x, y, color="#b2122f") + plt.savefig(GRAPH_PATH) + await self.send_graph(update) + + @delete_user_message + async def cosine(self, update: Update, context: ContextTypes.DEFAULT_TYPE): + if len(context.args) < 2: + await update.effective_chat.send_message("Debes dar a y k: /grafcoseno a k") + return + a, k = map(int, context.args[:2]) + x = np.linspace(0, 2*np.pi, 400) + y = a * np.cos(k*x) + plt.axhline(0, color="black") + plt.plot(x, y, color="#b2122f") + plt.savefig(GRAPH_PATH) + await self.send_graph(update) + + @delete_user_message + async def rect(self, update: Update, context: ContextTypes.DEFAULT_TYPE): + if len(context.args) < 2: + await update.effective_chat.send_message("Debes dar m y n: /grafrecta m n") + return + m, n = map(int, context.args[:2]) + x = np.linspace(-10, 10, 400) + y = m*x + n + plt.axhline(0, color="black") + plt.axvline(0, color="black") + plt.plot(x, y, color="#b2122f") + plt.savefig(GRAPH_PATH) + await self.send_graph(update) + + @delete_user_message + async def parable(self, update: Update, context: ContextTypes.DEFAULT_TYPE): + if len(context.args) < 3: + await update.effective_chat.send_message("Debes dar a, b, c: /grafparabola a b c") + return + a, b, c = map(int, context.args[:3]) + x = np.linspace(-10, 10, 400) + y = a*x**2 + b*x + c + plt.axhline(0, color="black") + plt.axvline(0, color="black") + plt.plot(x, y, color="#b2122f") + plt.savefig(GRAPH_PATH) + await self.send_graph(update) + + @delete_user_message + async def circle(self, update: Update, context: ContextTypes.DEFAULT_TYPE): + if not context.args: + await update.effective_chat.send_message("Debes dar el radio: /grafcircunferencia r") + return + r = int(context.args[0]) + fig, ax = plt.subplots() + ax.set_aspect('equal') + ax.add_artist(Circle((0, 0), r, color='r')) + plt.xlim(-10, 10) + plt.ylim(-10, 10) + plt.savefig(GRAPH_PATH) + await self.send_graph(update) + + @delete_user_message + async def log(self, update: Update, context: ContextTypes.DEFAULT_TYPE): + if len(context.args) < 2: + await update.effective_chat.send_message("Debes dar a y b: /graflog a b") + return + a, b = map(int, context.args[:2]) + x = np.linspace(0.01, 10, 400) + y = a*np.log(x) + b + plt.axhline(0, color="black") + plt.axvline(0, color="black") + plt.plot(x, y, color="#b2122f") + plt.savefig(GRAPH_PATH) + await self.send_graph(update) + + @delete_user_message + async def exp(self, update: Update, context: ContextTypes.DEFAULT_TYPE): + if len(context.args) < 2: + await update.effective_chat.send_message("Debes dar a y b: /grafexp a b") + return + a, b = map(int, context.args[:2]) + x = np.linspace(-10, 10, 400) + y = a*np.exp(b*x) + plt.axhline(0, color="black") + plt.axvline(0, color="black") + plt.plot(x, y, color="#b2122f") + plt.savefig(GRAPH_PATH) + await self.send_graph(update) \ No newline at end of file diff --git a/commands/misc.py b/commands/misc.py new file mode 100644 index 0000000..8ec891c --- /dev/null +++ b/commands/misc.py @@ -0,0 +1,162 @@ +from telegram import Update +from telegram.ext import ContextTypes, Application, CommandHandler +from time import time +from settings import BOT_OWNER, BOT_NAME, BOT_VERSION, BOT_LANG, BOT_TYPE, BOT_OWNER_ID +from random import randint, choice +from util.messages import delete_user_message + +class Misc: + def __init__(self, app: Application): + self.app = app + app.add_handler(CommandHandler("ping", self.ping)) + app.add_handler(CommandHandler("info", self.info)) + app.add_handler(CommandHandler("say", self.say)) + app.add_handler(CommandHandler("banana", self.banana)) + app.add_handler(CommandHandler("dado", self.dice)) + app.add_handler(CommandHandler("moneda", self.coin)) + app.add_handler(CommandHandler("paredes", self.walls)) + app.add_handler(CommandHandler("oooh", self.oooh)) + app.add_handler(CommandHandler("beber", self.drink)) + app.add_handler(CommandHandler("bombardeen", self.bomb)) + + @delete_user_message + async def ping(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: + before = update.message.date.timestamp() + now = time() + await update.effective_chat.send_message( + text=f"🏓 Pong! Latency is {round((now - before) * 1000, 2)} ms", + parse_mode="HTML", + disable_notification=True + ) + + @delete_user_message + async def info(self, update:Update, context: ContextTypes.DEFAULT_TYPE) -> None: + group = update.effective_chat.title + chat_id = update.effective_chat.id + member_count = await context.bot.get_chat_member_count(chat_id) + command_count = sum(1 for c in context.application.handlers[0] if isinstance(c, CommandHandler)) + info_text = f""" +Grupo: {group} +Miembros: {member_count} +Creador: {BOT_OWNER} +Nº Comandos: {command_count} + +Info técnica: +Nombre: {BOT_NAME} +Lenguaje: {BOT_LANG} +Tipo: {BOT_TYPE} +Versión: {BOT_VERSION} + """ + + await update.effective_chat.send_message( + text=info_text, + parse_mode="HTML", + disable_notification=True + ) + + @delete_user_message + async def say(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: + if not context.args: + await update.effective_chat.send_message( + text="Pero dime lo que tengo que decir puta", + disable_notification=True + ) + return + await update.effective_chat.send_message( + text=" ".join(arg for arg in context.args), + disable_notification=True + ) + + @delete_user_message + async def banana(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: + if update.effective_sender.id == BOT_OWNER_ID: + await update.effective_chat.send_message( + text=f"La banana de {update.effective_user.first_name} mide 21 cm 😳", + disable_notification=True + ) + else: + await update.effective_chat.send_message( + text=f"La banana de {update.effective_user.first_name} mide {randint(-5, 21)} cm 😳", + disable_notification=True + ) + + @delete_user_message + async def dice(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: + await update.effective_chat.send_dice( + emoji='🎲', + disable_notification=True + ) + + @delete_user_message + async def coin(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: + html =f""" +🪙 Se ha lanzado la moneda +Resultado: {choice(("Cara 😀", "Cruz ❌"))} + """ + await update.effective_chat.send_message( + text=html, + parse_mode="HTML", + disable_notification=True + ) + + @delete_user_message + async def walls(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: + if not context.args: + await update.effective_chat.send_message( + text="Debes especificar un usuario", + disable_notification=True + ) + return + + if not context.args[0].startswith("@"): + await update.effective_chat.send_message( + text="Debes mencionar a un usuario", + disable_notification=True + ) + return + + user = context.args[0] + caption = f"{user} está por las paredes" + + with open("data/images/interaction/paredes.gif", "rb") as gif: + await update.effective_chat.send_animation( + animation=gif, + caption=caption, + disable_notification=True + ) + + @delete_user_message + async def oooh(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: + with open("data/images/interaction/oooh.gif", "rb") as gif: + await update.effective_chat.send_animation( + animation=gif, + disable_notification=True + ) + + @delete_user_message + async def drink(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: + drinks = ["cerveza", "vino", "whisky", "ron", "vodka", "tequila", "ginebra", "sidra", "champán", "cava", "sake", "absenta", "brandy", "licor", "vermut", "mezcal", "pacharán", "anís", "aguardiente", "coñac", "cóctel", "cubata", "cóctel", "cubalibre"] + with open("data/images/interaction/beber.gif", "rb") as gif: + await update.effective_chat.send_animation( + animation=gif, + caption=f"@{update.effective_sender.username} ha bebido {choice(drinks)}", + disable_notification=True + ) + + @delete_user_message + async def bomb(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: + if not context.args: + await update.effective_chat.send_message( + text="Debes especificar algo que bombardear", + disable_notification=True + ) + return + + with open("data/images/interaction/bombardeen.gif") as gif: + await update.effective_chat.send_animation( + animation=gif, + caption=f"Bombardeen {context.args[0]}", + disable_notification=True + ) + + \ No newline at end of file diff --git a/data/files/counter.csv b/data/files/counter.csv new file mode 100644 index 0000000..56a6051 --- /dev/null +++ b/data/files/counter.csv @@ -0,0 +1 @@ +1 \ No newline at end of file diff --git a/data/files/grupos.txt b/data/files/grupos.txt new file mode 100644 index 0000000..a1afbbc --- /dev/null +++ b/data/files/grupos.txt @@ -0,0 +1,60 @@ +Imagine Dragons +Lil Nas X +Ed Sheeran +OneRepublic +Harry Styles +Mägo de Oz +Black Eyed Peas +Måneskin +BoyWithUke +Bad Bunny +Bizarrap +The Score +bbno$ +The Weeknd +Green Day +Queen +AC/DC +Elton John +Coldplay +LiSA +Glass Animals +Post Malone +KSI +Cardi B +JBalvin +Marshmello +Farruko +Dua Lipa +Ava Max +Armin van Buuren +Panic! At The Disco +Billie Eilish +Alan Walker +Bebe Rexha +Bruno Mars +Miley Cyrus +Maroon 5 +Tones And I +Why don't we +Ali Gatie +Canserbero +Residente +Dire Straits +Pink Floyd +Prince +The Police +Guns N' Roses +Linkin Park +Scorpion +Status Quo +Justin Bieber +Michael Jackson +Ariana Grande +Beyoncé +Lady Gaga +Katy Perry +Adele +Drake +Taylor Swift +Rihanna \ No newline at end of file diff --git a/data/files/hugs.json b/data/files/hugs.json new file mode 100644 index 0000000..e69de29 diff --git a/data/files/juegos.txt b/data/files/juegos.txt new file mode 100644 index 0000000..e01d4a4 --- /dev/null +++ b/data/files/juegos.txt @@ -0,0 +1,60 @@ +Dishonored 2 +The Witness +Journey +Uncharted 2: Among Thieves +Overwatch +Apex Legends +Hollow Knig +Ms. Pac-Man +Counter-Strike 1.6 +Left 4 Dead 2 +EarthBound +Diablo II +StarCraft +World of Warcraft +Star Wars: Knights of the Old Republic +Fallout: New Vegas +Final Fantasy VI +Pokémon Yellow +Metroid Prime +The Elder Scrolls V: Skyrim +Resident Evil 4 +Shadow of the Colossus +The Last of Us Part 2 +Red Dead Redemption +Metal Gear Solid +Sid Meier's Civilization IV +The Legend of Zelda: Ocarina of Time +Minecraft +Halo: Combat Evolved +Half-Life +Final Fantasy XIV +Doom +Tetris +Metal Gear Solid 3: Snake Eater +Half-Life: Alyx +God of War +Chrono Trigger +Portal +Street Fighter II +Super Mario Bros. +Undertale +Bloodborne +BioShock +The Last of Us +The Witcher 3: Wild Hunt +Halo 2 +Castlevania: Symphony of the Night +Hades +Grand Theft Auto V +Super Mario Bros. 3 +Disco Elysium +Half-Life 2 +Red Dead Redemption 2 +Super Mario 64 +Mass Effect 2 +Super Metroid +The Legend of Zelda: A Link to the Past +Portal 2 +Super Mario World +The Legend of Zelda: Breath of the Wild \ No newline at end of file diff --git a/data/files/shows.txt b/data/files/shows.txt new file mode 100644 index 0000000..77f0137 --- /dev/null +++ b/data/files/shows.txt @@ -0,0 +1,60 @@ +Squid Game +La Casa de Papel +Lupin +Avatar +Los Simpson +Lightyear +Tadeo Jones +Los Minions +Doraemon +Shin-Chan +JoJo's Bizarre Adventures +Boku no Hero Academia +Fullmetal Alchemist +SPY X FAMILY +Black Clover +My Dress-up Darling +New Amsterdam +Death Note +Cobra Kai +Karate Kid +Interstellar +Cómo entrenar a tu dragón +Free Guy +Spider Man +Dr Strange +Matrix +John Wick +Iron Man +The Good Doctor +Komi-san can't communicate +Big Mouth +(Des)encanto +Rick y Morty +Historias Corrientes +Hora de Aventuras +Chowder +Star Trek +Star Wars +Lost in Space +Tokyo Revengers +Gladiator +The Crown +Peaky Blinders +Sex Education +Enola Holmes +Los Juegos del Hambre +Juego de Tronos +El Señor de los Anillos +La princesa mononoke +Hitman +Los Croods +Plan de Escape +Código Lyoko +El Padrino +El viaje de Chihiro +El castillo ambulante +Coach Carter +Mascotas +Aida +La que se avecina \ No newline at end of file diff --git a/data/files/warns.json b/data/files/warns.json new file mode 100644 index 0000000..e69de29 diff --git a/data/images/djpype.png b/data/images/djpype.png new file mode 100644 index 0000000..3cdcd8b Binary files /dev/null and b/data/images/djpype.png differ diff --git a/data/images/graph.png b/data/images/graph.png new file mode 100644 index 0000000..6f151a9 Binary files /dev/null and b/data/images/graph.png differ diff --git a/data/images/interaction/beber.gif b/data/images/interaction/beber.gif new file mode 100644 index 0000000..54d9cef Binary files /dev/null and b/data/images/interaction/beber.gif differ diff --git a/data/images/interaction/bombardeen.gif b/data/images/interaction/bombardeen.gif new file mode 100644 index 0000000..777d5ca Binary files /dev/null and b/data/images/interaction/bombardeen.gif differ diff --git a/data/images/interaction/carey.webm b/data/images/interaction/carey.webm new file mode 100644 index 0000000..b37a5ed Binary files /dev/null and b/data/images/interaction/carey.webm differ diff --git a/data/images/interaction/cringe.gif b/data/images/interaction/cringe.gif new file mode 100644 index 0000000..f1d7338 Binary files /dev/null and b/data/images/interaction/cringe.gif differ diff --git a/data/images/interaction/fbi.gif b/data/images/interaction/fbi.gif new file mode 100644 index 0000000..2d3e17b Binary files /dev/null and b/data/images/interaction/fbi.gif differ diff --git a/data/images/interaction/femboy.png b/data/images/interaction/femboy.png new file mode 100644 index 0000000..970e9fa Binary files /dev/null and b/data/images/interaction/femboy.png differ diff --git a/data/images/interaction/moan.gif b/data/images/interaction/moan.gif new file mode 100644 index 0000000..5301d40 Binary files /dev/null and b/data/images/interaction/moan.gif differ diff --git a/data/images/interaction/oooh.gif b/data/images/interaction/oooh.gif new file mode 100644 index 0000000..286533f Binary files /dev/null and b/data/images/interaction/oooh.gif differ diff --git a/data/images/interaction/paredes.gif b/data/images/interaction/paredes.gif new file mode 100644 index 0000000..ecc6fbc Binary files /dev/null and b/data/images/interaction/paredes.gif differ diff --git a/data/images/interaction/run.gif b/data/images/interaction/run.gif new file mode 100644 index 0000000..94a62dd Binary files /dev/null and b/data/images/interaction/run.gif differ diff --git a/data/images/interaction/ship.gif b/data/images/interaction/ship.gif new file mode 100644 index 0000000..c5e56c2 Binary files /dev/null and b/data/images/interaction/ship.gif differ diff --git a/data/images/interaction/spank.gif b/data/images/interaction/spank.gif new file mode 100644 index 0000000..13f2480 Binary files /dev/null and b/data/images/interaction/spank.gif differ diff --git a/data/images/logo.png b/data/images/logo.png new file mode 100644 index 0000000..1740e79 Binary files /dev/null and b/data/images/logo.png differ diff --git a/data/images/pype.png b/data/images/pype.png new file mode 100644 index 0000000..882cd8c Binary files /dev/null and b/data/images/pype.png differ diff --git a/main.py b/main.py new file mode 100644 index 0000000..470b453 --- /dev/null +++ b/main.py @@ -0,0 +1,33 @@ +import os +from pathlib import Path +from dotenv import load_dotenv +from telegram import Update +from telegram.ext import ApplicationBuilder, CommandHandler, ContextTypes + +# importing command classes +from commands.misc import Misc +from commands.math import Math +from commands.interaction import Interaction +from commands.help import Help + +class PypeBot: + def __init__(self): + load_dotenv() + self.app = ApplicationBuilder().token(os.getenv("TOKEN")).build() + + # command registering + Misc(self.app) + Math(self.app) + Interaction(self.app) + Help(self.app) + + async def start(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: + await update.message.reply_text("Tamo' activo B)") + +def main() -> None: + bot = PypeBot() + bot.app.add_handler(CommandHandler("start", bot.start)) + bot.app.run_polling() + +if __name__ == '__main__': + main() \ No newline at end of file diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..25b3a7b --- /dev/null +++ b/requirements.txt @@ -0,0 +1,4 @@ +matplotlib +telegram +python-telegram-bot +numpy \ No newline at end of file diff --git a/settings.py b/settings.py new file mode 100644 index 0000000..939550c --- /dev/null +++ b/settings.py @@ -0,0 +1,92 @@ + ##### ####### # # ####### ### ##### # # ###### # ##### ### ####### # # + # # # # ## # # # # # # # # # # # # # # # # ## # + # # # # # # # # # # # # # # # # # # # # # # + # # # # # # ##### # # #### # # ###### # # # # # # # # # + # # # # # # # # # # # # # # ####### # # # # # # # + # # # # # ## # # # # # # # # # # # # # # # # ## + ##### ####### # # # ### ##### ##### # # # # ##### ### ####### # # + +# Configuración de parámetros del bot +GUILD_NAME = "The Boys" # nombre del servidor +BOT_OWNER = "Gallardo7761" +BOT_OWNER_ID = 8068730345 +BOT_LOGO ="data/images/pype.png" # png/jpg +BOT_NAME = "Pype" # nombre a elegir +BOT_LANG = "Python" # lenguaje +BOT_TYPE = "Multipropósito" # tipo +BOT_VERSION = "1.0.0" # versión del bot +LAVALINK_URI = '' # ip del servidor de Lavalink +LAVALINK_PASSWORD = '' +TIMEZONE = "Europe/Madrid" # zona horaria +GRAPH_PATH = "data/images/graph.png" # ruta para guardar gráficos + +# Cofiguración de parámetros del comando /help +VARIOS = """ +**MISCELÁNEA** +**/ping** - Ping de Pype. +**/info** - Info del discord. +**/say ** - Pype dice algo. +**/platano** - Banana! +**/dado** - Tira un dado de 6 caras. +**/moneda** - Tira una moneda al aire. +**/paredes ** - Están por las paredes. +**/oooh** - Ooooooooh! .- Exclamaron Mordecai y Rigby. +**/beber** - Bebe algo. +**/bombardeen ** - Bombardeen algo. +""" + +INTERACCION = """ +**INTERACCIÓN** +**/waifu** - Te da una waifu aleatoria en GIF. +**/neko** - Te da un neko aleatorio en GIF. +**/shinobu** - Te da un GIF de Shinobu. +**/megumin** - Te da un GIF de Megumin. +**/bully ** - Haz bullying a alguien (GIF). +**/cuddle ** - Acurrúcate con alguien (GIF). +**/cry** - Llora con un GIF. +**/hug ** - Abraza a alguien (GIF). +**/awoo** - Pide un GIF de furro. +**/kiss ** - Besa a alguien (GIF). +**/lick ** - Lame a alguien (GIF). +**/pat ** - Acaricia a alguien (GIF). +**/smug ** - Presume ante alguien (GIF). +**/bonk ** - Da un bonk a alguien (GIF). +**/yeet ** - Lanza a alguien (GIF). +**/blush** - Sonrojarse (GIF). +**/smile** - Sonríe (GIF). +**/wave ** - Saluda a alguien (GIF). +**/highfive ** - Choca la mano con alguien (GIF). +**/handhold ** - Cógela mano a mano con alguien (GIF). +**/nom** - Come algo rico (GIF). +**/bite ** - Muérdele a alguien (GIF). +**/glomp ** - Abalánzate sobre alguien (GIF). +**/slap ** - Da una bofetada a alguien (GIF). +**/kill ** - Mata a alguien (GIF). +**/kick ** - Patea a alguien (GIF). +**/happy** - Estás feliz (GIF). +**/wink ** - Guiña el ojo a alguien (GIF). +**/poke ** - Molesta a alguien (GIF). +**/dance ** - Baila (GIF). +**/cringe ** - Da cringe lo que hizo alguien (GIF). +**/run** - Huyes (GIF local). +**/fbi ** - Llama al FBI para alguien (GIF local). +**/spank ** - Da una nalgada a alguien (GIF local). +**/ship ** - Comprueba compatibilidad entre dos personas (GIF local). +**/moan** - Gemido (GIF local). +**/femboize ** - Convierte a alguien en femboy (PNG local). +""" + + +MATEMATICAS = """ +**MATEMÁTICAS** +**/calcular ** - Calcula expresiones matemáticas varias. +**/par ** - Comprueba si un número es par o no. +**/primo ** - Comprueba si un número es primo o no. +**/seno ** - Grafica una función seno. +**/coseno ** - Grafica una función coseno. +**/recta ** - Grafica una función lineal. +**/parabola ** ** - Grafica una función cuadrática. +**/circunferencia ** - Grafica una circunferencia. +**/log **** - Grafica una función logarítmica. +**/exp **** - Grafica una función exponencial. +""" \ No newline at end of file diff --git a/util/anime.py b/util/anime.py new file mode 100644 index 0000000..241ffbe --- /dev/null +++ b/util/anime.py @@ -0,0 +1,24 @@ +import requests + +class Anime: + def __init__(self): + self.base_url = f"https://api.waifu.pics/" + + def get(self, type: str, category: str) -> None: + if type != "nsfw" and type != "sfw": + raise Exception("Type not supported!") + + if not isinstance(category, str): + raise Exception("Category must be a string!") + + response = requests.get(f"{self.base_url}/{type}/{category}") + if response.status_code != 200: + raise Exception("Failed to retrieve data from API!") + + return response.json()["url"] + + def sfw(self, category: str) -> str: + return self.get("sfw", category) + + def nsfw(self, category: str) -> str: + return self.get("nsfw", category) \ No newline at end of file diff --git a/util/files.py b/util/files.py new file mode 100644 index 0000000..fd69242 --- /dev/null +++ b/util/files.py @@ -0,0 +1,17 @@ +import json + +def read(file: str) -> str: + with open(file, "r") as f: + return f.read() + +def read_json(file: str) -> dict: + with open(file, "r") as f: + return json.load(f) + +def write(file: str, content: str) -> None: + with open(file, "w") as f: + f.write(content) + +def write_json(file: str, content: dict) -> None: + with open(file, "w") as f: + json.dump(content, f, indent=4, sort_keys=True, separators=(',', ': '), ensure_ascii=False) \ No newline at end of file diff --git a/util/logger/colors.py b/util/logger/colors.py new file mode 100644 index 0000000..6250538 --- /dev/null +++ b/util/logger/colors.py @@ -0,0 +1,13 @@ +class Colors: + RED = "\033[91m" + GREEN = "\033[92m" + YELLOW = "\033[93m" + BLUE = "\033[94m" + MAGENTA = "\033[95m" + CYAN = "\033[96m" + WHITE = "\033[97m" + RESET = "\033[0m" + BOLD = "\033[1m" + UNDERLINE = "\033[4m" + LIME = "\033[32m" + GRAY = "\033[90m" \ No newline at end of file diff --git a/util/logger/logger.py b/util/logger/logger.py new file mode 100644 index 0000000..f2b34d1 --- /dev/null +++ b/util/logger/logger.py @@ -0,0 +1,43 @@ +from .colors import Colors +from datetime import datetime +import pytz +import traceback + +class PypeLogger: + @staticmethod + def info(message): + now = datetime.now(tz=pytz.timezone("Europe/Madrid")).strftime("%H:%M:%S") + print(f"{Colors.GRAY}[{now}] {Colors.GREEN}[INFO] {message}{Colors.RESET}") + + @staticmethod + def error(message, exception=None): + now = datetime.now(tz=pytz.timezone("Europe/Madrid")).strftime("%H:%M:%S") + main_error = f"{Colors.GRAY}[{now}] {Colors.RED}[ERROR] {message}{Colors.RESET}" + error_messages = [main_error] + if exception: + exception_message = f"\n{Colors.GRAY}[{now}] {Colors.RED}[ERROR] - Exception: {exception}" + traceback_message = f"\n{Colors.GRAY}[{now}] {Colors.RED}[ERROR] - Traceback: {traceback.format_exc()}" + error_messages.append(exception_message) + error_messages.append(traceback_message) + for error_message in error_messages: + print(error_message) + + @staticmethod + def debug(message): + now = datetime.now(tz=pytz.timezone("Europe/Madrid")).strftime("%H:%M:%S") + print(f"{Colors.GRAY}[{now}] {Colors.BLUE}[DEBUG] {message}{Colors.RESET}") + + @staticmethod + def warning(message): + now = datetime.now(tz=pytz.timezone("Europe/Madrid")).strftime("%H:%M:%S") + print(f"{Colors.GRAY}[{now}] {Colors.YELLOW}[WARNING] {message}{Colors.RESET}") + + @staticmethod + def success(message): + now = datetime.now(tz=pytz.timezone("Europe/Madrid")).strftime("%H:%M:%S") + print(f"{Colors.GRAY}[{now}] {Colors.LIME}[SUCCESS] {message}{Colors.RESET}") + + @staticmethod + def command(message): + now = datetime.now(tz=pytz.timezone("Europe/Madrid")).strftime("%H:%M:%S") + print(f"{Colors.GRAY}[{now}] {Colors.MAGENTA}[COMMAND] {message}{Colors.RESET}") \ No newline at end of file diff --git a/util/messages.py b/util/messages.py new file mode 100644 index 0000000..eaad5ee --- /dev/null +++ b/util/messages.py @@ -0,0 +1,18 @@ +from telegram import Update +from telegram.ext import ContextTypes + +async def respond(context: ContextTypes.DEFAULT_TYPE, chat_id: int, message: str): + await context.bot.send_message( + chat_id=chat_id, + text="✅ Mensaje recibido", + disable_notification=True + ) + +def delete_user_message(func): + async def wrapper(self, update: Update, context: ContextTypes.DEFAULT_TYPE): + await func(self, update, context) + try: + await context.bot.delete_message(update.effective_chat.id, update.message.message_id) + except: + pass + return wrapper \ No newline at end of file diff --git a/util/numbers.py b/util/numbers.py new file mode 100644 index 0000000..2c7a1b0 --- /dev/null +++ b/util/numbers.py @@ -0,0 +1,10 @@ +def is_even(n: int) -> bool: + return n % 2 == 0 + +def is_prime(n: int) -> bool: + if n <= 1: + return False + for i in range(2, int(n**0.5) + 1): + if n % i == 0: + return False + return True \ No newline at end of file