diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 00000000..215681ec Binary files /dev/null and b/.DS_Store differ diff --git a/Pipfile b/Pipfile index 096fb9b3..3cc318a5 100644 --- a/Pipfile +++ b/Pipfile @@ -8,6 +8,8 @@ name = "pypi" aiodns = "*" aiohttp = "<2.3.0,>=2.0.0" websockets = ">=4.0,<5.0" +"beautifulsoup4" = "*" +lxml = "*" [dev-packages] "flake8" = "*" diff --git a/Pipfile.lock b/Pipfile.lock index 4e5214bb..5a010121 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "d797e580ddcddc99bf058109ab0306ad584c2902752a3d4076ba713fdc580fb7" + "sha256": "b9b192123ee24bf056723e79ecaaf98633d36ec32fd0175f2823d20e13dc882b" }, "pipfile-spec": 6, "requires": { @@ -53,6 +53,15 @@ ], "version": "==2.0.1" }, + "beautifulsoup4": { + "hashes": [ + "sha256:11a9a27b7d3bddc6d86f59fb76afb70e921a25ac2d6cc55b40d072bd68435a76", + "sha256:7015e76bf32f1f574636c4288399a6de66ce08fb7b2457f628a8d70c0fbabb11", + "sha256:808b6ac932dccb0a4126558f7dfdcf41710dd44a4ef497a0bb59a77f9f078e89" + ], + "index": "pypi", + "version": "==4.6.0" + }, "chardet": { "hashes": [ "sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae", @@ -67,6 +76,40 @@ ], "version": "==2.6" }, + "lxml": { + "hashes": [ + "sha256:01c45df6d90497c20aa2a07789a41941f9a1029faa30bf725fc7f6d515b1afe9", + "sha256:0c9fef4f8d444e337df96c54544aeb85b7215b2ed7483bb6c35de97ac99f1bcd", + "sha256:0e3cd94c95d30ba9ca3cff40e9b2a14e1a10a4fd8131105b86c6b61648f57e4b", + "sha256:0e7996e9b46b4d8b4ac1c329a00e2d10edcd8380b95d2a676fccabf4c1dd0512", + "sha256:1858b1933d483ec5727549d3fe166eeb54229fbd6a9d3d7ea26d2c8a28048058", + "sha256:1b164bba1320b14905dcff77da10d5ce9c411ac4acc4fb4ed9a2a4d10fae38c9", + "sha256:1b46f37927fa6cd1f3fe34b54f1a23bd5bea1d905657289e08e1297069a1a597", + "sha256:231047b05907315ae9a9b6925751f9fd2c479cf7b100fff62485a25e382ca0d4", + "sha256:28f0c6652c1b130f1e576b60532f84b19379485eb8da6185c29bd8c9c9bc97bf", + "sha256:34d49d0f72dd82b9530322c48b70ac78cca0911275da741c3b1d2f3603c5f295", + "sha256:3682a17fbf72d56d7e46db2e80ca23850b79c28cfe75dcd9b82f58808f730909", + "sha256:3cf2830b9a6ad7f6e965fa53a768d4d2372a7856f20ffa6ce43d2fe9c0d34b19", + "sha256:5b653c9379ce29ce271fbe1010c5396670f018e78b643e21beefbb3dc6d291de", + "sha256:65a272821d5d8194358d6b46f3ca727fa56a6b63981606eac737c86d27309cdd", + "sha256:691f2cd97cf026c611df1ea5055755eec7f878f2d4f4330dc8686583de6fc5fd", + "sha256:6b6379495d3baacf7ed755ac68547c8dff6ce5d37bf370f0b7678888dc1283f9", + "sha256:75322a531504d4f383264391d89993a42e286da8821ddc5ac315e57305cb84f0", + "sha256:7f457cbda964257f443bac861d3a36732dcba8183149e7818ee2fb7c86901b94", + "sha256:7ff1fc76d8804e0f870c343a72007ff587090c218b0f92d8ee784ac2b6eaf5b9", + "sha256:8523fbde9c2216f3f2b950cb01ebe52e785eaa8a07ffeb456dd3576ca1b4fb9b", + "sha256:8f37627f16e026523fca326f1b5c9a43534862fede6c3e99c2ba6a776d75c1ab", + "sha256:a7182ea298cc3555ea56ffbb0748fe0d5e0d81451e2bc16d7f4645cd01b1ca70", + "sha256:abbd2fb4a5a04c11b5e04eb146659a0cf67bb237dd3d7ca3b9994d3a9f826e55", + "sha256:accc9f6b77bed0a6f267b4fae120f6008a951193d548cdbe9b61fc98a08b1cf8", + "sha256:bd88c8ce0d1504fdfd96a35911dd4f3edfb2e560d7cfdb5a3d09aa571ae5fbae", + "sha256:c557ad647facb3c0027a9d0af58853f905e85a0a2f04dcb73f8e665272fcdc3a", + "sha256:defabb7fbb99f9f7b3e0b24b286a46855caef4776495211b066e9e6592d12b04", + "sha256:e2629cdbcad82b83922a3488937632a4983ecc0fed3e5cfbf430d069382eeb9b" + ], + "index": "pypi", + "version": "==4.2.1" + }, "multidict": { "hashes": [ "sha256:0462372fc74e4c061335118a4a5992b9a618d6c584b028ef03cf3e9b88a960e2", @@ -282,10 +325,10 @@ }, "gitpython": { "hashes": [ - "sha256:ad61bc25deadb535b047684d06f3654c001d9415e1971e51c9c20f5b510076e9", - "sha256:b8367c432de995dc330b5b146c5bfdc0926b8496e100fda6692134e00c0dcdc5" + "sha256:05069e26177c650b3cb945dd543a7ef7ca449f8db5b73038b465105673c1ef61", + "sha256:c47cc31af6e88979c57a33962cbc30a7c25508d74a1b3a19ec5aa7ed64b03129" ], - "version": "==2.1.8" + "version": "==2.1.9" }, "idna": { "hashes": [ diff --git a/bot/cogs/snakes.py b/bot/cogs/snakes.py index c9ed8042..d0f096df 100644 --- a/bot/cogs/snakes.py +++ b/bot/cogs/snakes.py @@ -1,7 +1,15 @@ # coding=utf-8 +import asyncio import logging +import random + +import aiohttp from typing import Any, Dict +from bs4 import BeautifulSoup + + +import discord from discord.ext.commands import AutoShardedBot, Context, command log = logging.getLogger(__name__) @@ -11,8 +19,22 @@ class Snakes: """ Snake-related commands """ + python_info = ''' + Python (Programming Language) + \n + Python is powerful... and fast;\n + plays well with others;\n + runs everywhere;\n + is friendly & easy to learn;\n + is Open-Source. + ------------------------------- + Created by: Guido Van Rossum \n + Founded: 20th of February, 1991 \n + Official website: https://python.org + ''' def __init__(self, bot: AutoShardedBot): + self.inputs = [] self.bot = bot async def get_snek(self, name: str = None) -> Dict[str, Any]: @@ -29,8 +51,13 @@ async def get_snek(self, name: str = None) -> Dict[str, Any]: :return: A dict containing information on a snake """ + if name.lower() == 'python': + name = self.python_info + + return name + @command() - async def get(self, ctx: Context, name: str = None): + async def get(self, ctx: Context, name: str = None, ): """ Go online and fetch information about a snake @@ -41,7 +68,145 @@ async def get(self, ctx: Context, name: str = None): :param name: Optional, the name of the snake to get information for - omit for a random snake """ - # Any additional commands can be placed here. Be creative, but keep it to a reasonable amount! + site = 'https://en.wikipedia.org/wiki/' + name + async with aiohttp.ClientSession() as session: + async with session.get(site) as resp: + text = await resp.text() + soup = BeautifulSoup(text, 'lxml') + title = soup.find('h1').text + description = soup.find('p').text + table = soup.find('table').text + list(table) + table = table[120:] + table = ''.join(table) + description = description + '\n' + table + em = discord.Embed(title=title, description=description) + + if name.lower() == 'python': + await ctx.send(await self.get_snek(name)) + else: + await ctx.send(embed=em) + # await ctx.send(name) + + # Any additional commands can be placed here. Be creative, but keep it to a reasonable amount! + + @command() + async def snake(self, ctx: Context, x=8, y=8): + + snake = [] # define snake (where snake sections are stored) + head = [x // 2, y] # define head (where current snake head is stored) + apple = (random.randrange(x), random.randrange(y)) # define apple (where current apple position is stored) + + userID = ctx.author.id + facing = 0 + + snake.append(head) + running = True + + board = "\n " + ":black_large_square:" * x + ":black_large_square::black_large_square:" + for yAxis in range(y): + board += "\n:black_large_square:" + for xAxis in range(x): + if head == [xAxis, yAxis]: + board += ":snake:" + else: + board += ":white_large_square:" + + board += ":black_large_square:" + board += "\n" + ":black_large_square:" * x + ":black_large_square::black_large_square:" + + Board = discord.Embed(title="Snake!", description=board) + snakeBoard = await ctx.send(embed=Board) + + while running: + directionChange = True + for mess in self.inputs: + if mess.author.id == userID: + + if mess.content == "a": + if directionChange: + facing = (facing - 1) % 4 + directionChange = False + await mess.delete() + + elif mess.content == "d": + if directionChange: + facing = (facing + 1) % 4 + directionChange = False + await mess.delete() + break + + self.inputs = [] + + if facing == 0: + head[1] -= 1 + elif facing == 1: + head[0] += 1 + elif facing == 2: + head[1] += 1 + else: + head[0] -= 1 + + if head[0] < 0 or head[1] < 0 or head[0] > x - 1 or head[1] > y - 1: + await ctx.send(str(ctx.author.mention) + " become a wall :cry:") + running = False + + # check if + for snakeTail in snake: + if snakeTail == tuple(head): + await ctx.send(str(ctx.author.mention) + " ate himself :open_mouth: ") + running = False + + # check if an apple was eaten + for snakeTail in snake: + if snakeTail == apple: + # if so it generates a new apple + apple = (random.randrange(x), random.randrange(y)) + break + # if no apple is eaten then the else will run. + # So when an apple is eaten the last tuple to be added to list (snake) will not be removed + # this effectively makes the snake one section longer. + else: + snake.pop(0) + # add the current snake head to the list snake + snake.append(tuple(head)) + + # add title + board = """""" + # add top of board + board += "\n " + ":black_large_square:" * (x + 2) + for yAxis in range(y): + # add side of board + board += "\n:black_large_square:" + for xAxis in range(x): + # add snake sections + for snakeTail in snake: + if snakeTail == (xAxis, yAxis): + board += ":snake:" + break + + else: + # add apple + if apple == (xAxis, yAxis): + board += ":apple:" + # add background + else: + board += ":white_large_square:" + + # add side of board + board += ":black_large_square:" + # add bottom of board + board += "\n" + ":black_large_square:" * (x + 2) + + # edit message then wait for next frame + Board = discord.Embed(title="Snake!", description=board) + await snakeBoard.edit(embed=Board) + await asyncio.sleep(0.9) + + # get user snake inputs + async def on_message(self, message): + if message.content in ("a", "d"): + self.inputs.append(message) def setup(bot):