From 6f85d43148760f6b18754ba4b9785a30b3b65e75 Mon Sep 17 00:00:00 2001 From: biskette Date: Fri, 23 Mar 2018 01:13:36 +0000 Subject: [PATCH 01/47] Stone by stone we'll build our castle walls... --- bot/cogs/wtfisthis.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 bot/cogs/wtfisthis.py diff --git a/bot/cogs/wtfisthis.py b/bot/cogs/wtfisthis.py new file mode 100644 index 00000000..6dc9f4ca --- /dev/null +++ b/bot/cogs/wtfisthis.py @@ -0,0 +1,18 @@ +#!/usr/bin/env python3 + +from selenium import webdriver +from time import sleep + +options = webdriver.ChromeOptions() +options.add_argument('window-size=1280x720') + +driver = webdriver.Chrome(chrome_options=options) + +driver.get("https://en.wikipedia.org/wiki/Main_Page") +search = driver.find_element_by_id('searchInput') +search.send_keys('snakes') +driver.find_element_by_id('searchButton').click() + +sleep(5) + +driver.close() \ No newline at end of file From 895fefa88b82ea03af784143800566854269ac6d Mon Sep 17 00:00:00 2001 From: biskette Date: Fri, 23 Mar 2018 01:20:25 +0000 Subject: [PATCH 02/47] We'll build them on common ground, and how! --- bot/cogs/wtfisthis.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/bot/cogs/wtfisthis.py b/bot/cogs/wtfisthis.py index 6dc9f4ca..4a5826f2 100644 --- a/bot/cogs/wtfisthis.py +++ b/bot/cogs/wtfisthis.py @@ -8,9 +8,15 @@ driver = webdriver.Chrome(chrome_options=options) +# Wikipedia is nice because its elements are named cohesively driver.get("https://en.wikipedia.org/wiki/Main_Page") + +# Find search element search = driver.find_element_by_id('searchInput') -search.send_keys('snakes') + +# We obviously need to get a broad list of "snakes" from this search term +# Yet obviously not something scientific, unless we do some wild card random to please the gods +search.send_keys('list of snakes') driver.find_element_by_id('searchButton').click() sleep(5) From 8716582175b0d3c0b09d839d977148e744df53b5 Mon Sep 17 00:00:00 2001 From: biskette Date: Fri, 23 Mar 2018 01:41:18 +0000 Subject: [PATCH 03/47] We all live in the space age, coming down with road rage... --- bot/cogs/wtfisthis.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/bot/cogs/wtfisthis.py b/bot/cogs/wtfisthis.py index 4a5826f2..2df30010 100644 --- a/bot/cogs/wtfisthis.py +++ b/bot/cogs/wtfisthis.py @@ -16,9 +16,18 @@ # We obviously need to get a broad list of "snakes" from this search term # Yet obviously not something scientific, unless we do some wild card random to please the gods -search.send_keys('list of snakes') +search.send_keys('list of snakes by common name') driver.find_element_by_id('searchButton').click() -sleep(5) +# Now we build some cool shit to scrape a bunch of snakes! +# From a FUCKING MASSIVE list of shite +result = driver.find_element_by_class_name('mw-parser-output') + +# So we're pulling the UL out of the above div +newresults = result.find_elements_by_tag_name("ul") + +# Now we're just iterating over that and pulling the text element to see it works +for each in newresults: + print(each.text) driver.close() \ No newline at end of file From aa0aca12a7036454cf5416da12d3c99a5fd8b372 Mon Sep 17 00:00:00 2001 From: biskette Date: Fri, 23 Mar 2018 01:54:34 +0000 Subject: [PATCH 04/47] Travis is a bellend. --- bot/cogs/wtfisthis.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/bot/cogs/wtfisthis.py b/bot/cogs/wtfisthis.py index 2df30010..e9775156 100644 --- a/bot/cogs/wtfisthis.py +++ b/bot/cogs/wtfisthis.py @@ -1,7 +1,6 @@ #!/usr/bin/env python3 from selenium import webdriver -from time import sleep options = webdriver.ChromeOptions() options.add_argument('window-size=1280x720') @@ -30,4 +29,4 @@ for each in newresults: print(each.text) -driver.close() \ No newline at end of file +driver.close() From 2694897783ec5ba923adee91972eb9bc9f87a0de Mon Sep 17 00:00:00 2001 From: biskette Date: Fri, 23 Mar 2018 02:25:58 +0000 Subject: [PATCH 05/47] Square peg, round hole. --- bot/cogs/wtfisthis.py | 32 +------------------------------- 1 file changed, 1 insertion(+), 31 deletions(-) diff --git a/bot/cogs/wtfisthis.py b/bot/cogs/wtfisthis.py index e9775156..d19ec0b8 100644 --- a/bot/cogs/wtfisthis.py +++ b/bot/cogs/wtfisthis.py @@ -1,32 +1,2 @@ -#!/usr/bin/env python3 +#!/usr/bin/env python3.6 -from selenium import webdriver - -options = webdriver.ChromeOptions() -options.add_argument('window-size=1280x720') - -driver = webdriver.Chrome(chrome_options=options) - -# Wikipedia is nice because its elements are named cohesively -driver.get("https://en.wikipedia.org/wiki/Main_Page") - -# Find search element -search = driver.find_element_by_id('searchInput') - -# We obviously need to get a broad list of "snakes" from this search term -# Yet obviously not something scientific, unless we do some wild card random to please the gods -search.send_keys('list of snakes by common name') -driver.find_element_by_id('searchButton').click() - -# Now we build some cool shit to scrape a bunch of snakes! -# From a FUCKING MASSIVE list of shite -result = driver.find_element_by_class_name('mw-parser-output') - -# So we're pulling the UL out of the above div -newresults = result.find_elements_by_tag_name("ul") - -# Now we're just iterating over that and pulling the text element to see it works -for each in newresults: - print(each.text) - -driver.close() From 640e8898a15dfc7408b26c770556508f501727e0 Mon Sep 17 00:00:00 2001 From: runew0lf Date: Fri, 23 Mar 2018 10:32:15 +0000 Subject: [PATCH 06/47] Used wikipedia library to get initial data for testing --- bot/cogs/snakes.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/bot/cogs/snakes.py b/bot/cogs/snakes.py index c9ed8042..fb9d4265 100644 --- a/bot/cogs/snakes.py +++ b/bot/cogs/snakes.py @@ -1,8 +1,10 @@ # coding=utf-8 import logging +import wikipedia from typing import Any, Dict from discord.ext.commands import AutoShardedBot, Context, command +from discord import Embed log = logging.getLogger(__name__) @@ -30,7 +32,7 @@ async def get_snek(self, name: str = None) -> Dict[str, Any]: """ @command() - async def get(self, ctx: Context, name: str = None): + async def get(self, ctx: Context, name: str = "Vipera berus"): """ Go online and fetch information about a snake @@ -40,6 +42,15 @@ async def get(self, ctx: Context, name: str = None): :param ctx: Context object passed from discord.py :param name: Optional, the name of the snake to get information for - omit for a random snake """ + snakeembed = Embed(color=ctx.me.color, title="SNAKE") + + snake_data = wikipedia.summary(name, sentences=1) + snake_image = wikipedia.WikipediaPage(name) + + snakeembed.add_field(name=name, value=snake_data) + snakeembed.set_thumbnail(url=snake_image.images[0]) + + await ctx.send(embed=snakeembed) # Any additional commands can be placed here. Be creative, but keep it to a reasonable amount! From dc6aff51a029342aa5eeb110f18a7b8d296c52a3 Mon Sep 17 00:00:00 2001 From: runew0lf Date: Fri, 23 Mar 2018 14:40:19 +0000 Subject: [PATCH 07/47] Now uses our own code for getting wikipedia api data --- bot/cogs/snakes.py | 60 ++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 50 insertions(+), 10 deletions(-) diff --git a/bot/cogs/snakes.py b/bot/cogs/snakes.py index fb9d4265..a93a98b9 100644 --- a/bot/cogs/snakes.py +++ b/bot/cogs/snakes.py @@ -1,7 +1,9 @@ # coding=utf-8 import logging -import wikipedia from typing import Any, Dict +import aiohttp +import async_timeout +import pprint from discord.ext.commands import AutoShardedBot, Context, command from discord import Embed @@ -41,16 +43,54 @@ async def get(self, ctx: Context, name: str = "Vipera berus"): :param ctx: Context object passed from discord.py :param name: Optional, the name of the snake to get information for - omit for a random snake + https://en.wikipedia.org/w/api.php?action=query&titles=Vipera_berus&prop=extracts&exsentences=2&explaintext=1&format=json """ - snakeembed = Embed(color=ctx.me.color, title="SNAKE") - - snake_data = wikipedia.summary(name, sentences=1) - snake_image = wikipedia.WikipediaPage(name) - - snakeembed.add_field(name=name, value=snake_data) - snakeembed.set_thumbnail(url=snake_image.images[0]) - - await ctx.send(embed=snakeembed) + snake_embed = Embed(color=ctx.me.color, title="SNAKE") + name = name.replace(" ", "_") + + text_params = {'action': 'query', + 'titles': name, + 'prop': 'extracts', + 'exsentences': '2', + 'explaintext': '1', + 'format': 'json'} + + image_name_params = {'action': 'query', + 'titles': name, + 'prop': 'images', + 'imlimit': '1', + 'format': 'json'} + + async with aiohttp.ClientSession(headers={'User-Agent': 'DevBot v.10'}) as cs: + async with async_timeout.timeout(20): + async with cs.get("https://en.wikipedia.org/w/api.php", params=text_params) as r: + text_json = await r.json() + async with cs.get("https://en.wikipedia.org/w/api.php", params=image_name_params) as r: + image_name_json = await r.json() + + # snake_image = "https://pbs.twimg.com/profile_images/662615956670144512/dqsVK6Nw_400x400.jpg" + + page_id = list(text_json['query']['pages'].keys())[0] + image_id = image_name_json['query']['pages'][page_id]['images'][0]['title'] + + image_url_params = {'action': 'query', + 'titles': image_id, + 'prop': 'imageinfo', + 'iiprop': 'url', + 'format': 'json'} + + async with aiohttp.ClientSession(headers={'User-Agent': 'DevBot v.10'}) as cs: + async with async_timeout.timeout(20): + async with cs.get("https://en.wikipedia.org/w/api.php", params=image_url_params) as r: + image_url_json = await r.json() + + snake_image_id = list(image_url_json['query']['pages'].keys())[0] + snake_image = image_url_json['query']['pages'][snake_image_id]['imageinfo'][0]['url'] + + snake_embed.add_field(name=name, value=text_json['query']['pages'][page_id]['extract']) + snake_embed.set_thumbnail(url=snake_image) + + await ctx.send(embed=snake_embed) # Any additional commands can be placed here. Be creative, but keep it to a reasonable amount! From d838411be29aaba14a66b32edbc7db852040d782 Mon Sep 17 00:00:00 2001 From: runew0lf Date: Fri, 23 Mar 2018 15:11:05 +0000 Subject: [PATCH 08/47] Created function to grab json instead of repeating code --- bot/cogs/snakes.py | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/bot/cogs/snakes.py b/bot/cogs/snakes.py index a93a98b9..35c20b81 100644 --- a/bot/cogs/snakes.py +++ b/bot/cogs/snakes.py @@ -19,6 +19,12 @@ class Snakes: def __init__(self, bot: AutoShardedBot): self.bot = bot + async def get_wiki_json(self, params): + async with aiohttp.ClientSession(headers={'User-Agent': 'DevBot v.10'}) as cs: + async with async_timeout.timeout(20): + async with cs.get("https://en.wikipedia.org/w/api.php", params=params) as r: + return await r.json() + async def get_snek(self, name: str = None) -> Dict[str, Any]: """ Go online and fetch information about a snake @@ -61,12 +67,8 @@ async def get(self, ctx: Context, name: str = "Vipera berus"): 'imlimit': '1', 'format': 'json'} - async with aiohttp.ClientSession(headers={'User-Agent': 'DevBot v.10'}) as cs: - async with async_timeout.timeout(20): - async with cs.get("https://en.wikipedia.org/w/api.php", params=text_params) as r: - text_json = await r.json() - async with cs.get("https://en.wikipedia.org/w/api.php", params=image_name_params) as r: - image_name_json = await r.json() + text_json = await self.get_wiki_json(text_params) + image_name_json = await self.get_wiki_json(image_name_params) # snake_image = "https://pbs.twimg.com/profile_images/662615956670144512/dqsVK6Nw_400x400.jpg" @@ -79,10 +81,7 @@ async def get(self, ctx: Context, name: str = "Vipera berus"): 'iiprop': 'url', 'format': 'json'} - async with aiohttp.ClientSession(headers={'User-Agent': 'DevBot v.10'}) as cs: - async with async_timeout.timeout(20): - async with cs.get("https://en.wikipedia.org/w/api.php", params=image_url_params) as r: - image_url_json = await r.json() + image_url_json = await self.get_wiki_json(image_url_params) snake_image_id = list(image_url_json['query']['pages'].keys())[0] snake_image = image_url_json['query']['pages'][snake_image_id]['imageinfo'][0]['url'] From b8d7356f7553beb81844adbe93468fad32735467 Mon Sep 17 00:00:00 2001 From: biskette Date: Fri, 23 Mar 2018 15:24:30 +0000 Subject: [PATCH 09/47] Wtf am i doing --- bot/cogs/wtfisthis.py | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/bot/cogs/wtfisthis.py b/bot/cogs/wtfisthis.py index d19ec0b8..4ad5e9d5 100644 --- a/bot/cogs/wtfisthis.py +++ b/bot/cogs/wtfisthis.py @@ -1,2 +1,37 @@ #!/usr/bin/env python3.6 +import aiohttp +import async_timeout +import asyncio + + +async def query(request): + request['action'] = 'query' + request['format'] = 'json' + lastContinue = {} + + async with aiohttp.ClientSession(headers={'User-Agent': 'DevBot'}) as cs: + while True: + req = request.copy() + req.update(lastContinue) + async with cs.get('https://en.wikipedia.org/w/api.php', params=req) as result: + if 'error' in result: + raise Error(result['error']) + if 'warnings' in result: + print(result['warnings']) + if 'query' in result: + yield result['query'] + if 'continue' not in result: + break + lastContinue = result['continue'] + + +result = query({'action': 'query', 'titles': 'list_of_snakes_by_common_name', 'prop': 'links'}) + +print(result) + +async def somebollocks(): + async for item in result: + print(item) + +somebollocks() \ No newline at end of file From c66cdd81ec9594de84e06360f97905723ada3fce Mon Sep 17 00:00:00 2001 From: runew0lf Date: Fri, 23 Mar 2018 15:44:22 +0000 Subject: [PATCH 10/47] Created function to grab json instead of repeating code --- bot/cogs/snakes.py | 35 +++++++++++++++++++---------------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/bot/cogs/snakes.py b/bot/cogs/snakes.py index 35c20b81..2226f610 100644 --- a/bot/cogs/snakes.py +++ b/bot/cogs/snakes.py @@ -38,20 +38,6 @@ async def get_snek(self, name: str = None) -> Dict[str, Any]: :param name: Optional, the name of the snake to get information for - omit for a random snake :return: A dict containing information on a snake """ - - @command() - async def get(self, ctx: Context, name: str = "Vipera berus"): - """ - Go online and fetch information about a snake - - This should make use of your `get_snek` method, using it to get information about a snake. This information - should be sent back to Discord in an embed. - - :param ctx: Context object passed from discord.py - :param name: Optional, the name of the snake to get information for - omit for a random snake - https://en.wikipedia.org/w/api.php?action=query&titles=Vipera_berus&prop=extracts&exsentences=2&explaintext=1&format=json - """ - snake_embed = Embed(color=ctx.me.color, title="SNAKE") name = name.replace(" ", "_") text_params = {'action': 'query', @@ -85,10 +71,27 @@ async def get(self, ctx: Context, name: str = "Vipera berus"): snake_image_id = list(image_url_json['query']['pages'].keys())[0] snake_image = image_url_json['query']['pages'][snake_image_id]['imageinfo'][0]['url'] + snake_text = text_json['query']['pages'][page_id]['extract'] - snake_embed.add_field(name=name, value=text_json['query']['pages'][page_id]['extract']) - snake_embed.set_thumbnail(url=snake_image) + snake_dict = {"name": name, "snake_text": snake_text, "snake_image":snake_image} + return snake_dict + @command() + async def get(self, ctx: Context, name: str = "Vipera berus"): + """ + Go online and fetch information about a snake + + This should make use of your `get_snek` method, using it to get information about a snake. This information + should be sent back to Discord in an embed. + + :param ctx: Context object passed from discord.py + :param name: Optional, the name of the snake to get information for - omit for a random snake + https://en.wikipedia.org/w/api.php?action=query&titles=Vipera_berus&prop=extracts&exsentences=2&explaintext=1&format=json + """ + snake = await self.get_snek(name) + snake_embed = Embed(color=ctx.me.color, title="SNAKE") + snake_embed.add_field(name=snake['name'], value=snake['snake_text']) + snake_embed.set_thumbnail(url=snake['snake_image']) await ctx.send(embed=snake_embed) # Any additional commands can be placed here. Be creative, but keep it to a reasonable amount! From 751603b6d6bfff44432d4b74a091f9d8fb82457a Mon Sep 17 00:00:00 2001 From: biskette Date: Fri, 23 Mar 2018 15:45:55 +0000 Subject: [PATCH 11/47] writing bollocks --- bot/cogs/wtfisthis.py | 55 +++++++++++++++++++++++-------------------- 1 file changed, 30 insertions(+), 25 deletions(-) diff --git a/bot/cogs/wtfisthis.py b/bot/cogs/wtfisthis.py index 4ad5e9d5..aac999e0 100644 --- a/bot/cogs/wtfisthis.py +++ b/bot/cogs/wtfisthis.py @@ -5,33 +5,38 @@ import asyncio -async def query(request): - request['action'] = 'query' - request['format'] = 'json' - lastContinue = {} - - async with aiohttp.ClientSession(headers={'User-Agent': 'DevBot'}) as cs: - while True: - req = request.copy() - req.update(lastContinue) - async with cs.get('https://en.wikipedia.org/w/api.php', params=req) as result: - if 'error' in result: - raise Error(result['error']) - if 'warnings' in result: - print(result['warnings']) - if 'query' in result: - yield result['query'] - if 'continue' not in result: - break - lastContinue = result['continue'] +async def get_wiki_json(self, params): + async with aiohttp.ClientSession(headers={'User-Agent': 'DevBot v.10'}) as cs: + async with async_timeout.timeout(20): + async with cs.get("https://en.wikipedia.org/w/api.php", params=params) as r: + return await r.json() + + +async def query(params): + async with aiohttp.ClientSession(headers={'User-Agent': 'DickButt v.10rc2'}) as cs: + async with async_timeout.timeout(20): + async with cs.get("https://en.wikipedia.org/w/api.php", params=params) as r: + return await r.json() + # request['action'] = 'query' + # request['format'] = 'json' + # lastContinue = {} + # + # async with aiohttp.ClientSession(headers={'User-Agent': 'DevBot'}) as cs: + # while True: + # req = request.copy() + # req.update(lastContinue) + # async with cs.get('https://en.wikipedia.org/w/api.php', params=req) as result: + # if 'error' in result: + # raise Error(result['error']) + # if 'warnings' in result: + # print(result['warnings']) + # if 'query' in result: + # yield result['query'] + # if 'continue' not in result: + # break + # lastContinue = result['continue'] result = query({'action': 'query', 'titles': 'list_of_snakes_by_common_name', 'prop': 'links'}) print(result) - -async def somebollocks(): - async for item in result: - print(item) - -somebollocks() \ No newline at end of file From c640b7a008ca6f3af74caa50813392bc21a4fff5 Mon Sep 17 00:00:00 2001 From: biskette Date: Fri, 23 Mar 2018 15:46:55 +0000 Subject: [PATCH 12/47] fucking git eh? --- bot/cogs/wtfisthis.py | 51 ++++++++++++++++--------------------------- 1 file changed, 19 insertions(+), 32 deletions(-) diff --git a/bot/cogs/wtfisthis.py b/bot/cogs/wtfisthis.py index aac999e0..9e67e8a9 100644 --- a/bot/cogs/wtfisthis.py +++ b/bot/cogs/wtfisthis.py @@ -5,38 +5,25 @@ import asyncio -async def get_wiki_json(self, params): - async with aiohttp.ClientSession(headers={'User-Agent': 'DevBot v.10'}) as cs: - async with async_timeout.timeout(20): - async with cs.get("https://en.wikipedia.org/w/api.php", params=params) as r: - return await r.json() - - async def query(params): + lastcontinue = {} + async with aiohttp.ClientSession(headers={'User-Agent': 'DickButt v.10rc2'}) as cs: async with async_timeout.timeout(20): - async with cs.get("https://en.wikipedia.org/w/api.php", params=params) as r: - return await r.json() - # request['action'] = 'query' - # request['format'] = 'json' - # lastContinue = {} - # - # async with aiohttp.ClientSession(headers={'User-Agent': 'DevBot'}) as cs: - # while True: - # req = request.copy() - # req.update(lastContinue) - # async with cs.get('https://en.wikipedia.org/w/api.php', params=req) as result: - # if 'error' in result: - # raise Error(result['error']) - # if 'warnings' in result: - # print(result['warnings']) - # if 'query' in result: - # yield result['query'] - # if 'continue' not in result: - # break - # lastContinue = result['continue'] - - -result = query({'action': 'query', 'titles': 'list_of_snakes_by_common_name', 'prop': 'links'}) - -print(result) + while True: + req = params.copy() + req.update(lastcontinue) + async with cs.get("https://en.wikipedia.org/w/api.php", params=params) as r: + if 'continue' not in r: + break + lastcontinue = r['continue'] + + return await r.json() + + +async def main(): + result = await query({'action': 'query', 'titles': 'list_of_snakes_by_common_name', 'prop': 'links', 'format': 'json'}) + print(result) + +loop = asyncio.get_event_loop() +loop.run_until_complete(main()) \ No newline at end of file From f31430a7dd71b7b03eb96d21b8e9033eb742ff4b Mon Sep 17 00:00:00 2001 From: runew0lf Date: Fri, 23 Mar 2018 20:02:06 +0000 Subject: [PATCH 13/47] Split out everything, fixed things, added things! --- bot/cogs/data/quote.txt | 19 +++++++++++++++++++ bot/cogs/snakes.py | 37 ++++++++++++++++++++++++++++++------- 2 files changed, 49 insertions(+), 7 deletions(-) create mode 100644 bot/cogs/data/quote.txt diff --git a/bot/cogs/data/quote.txt b/bot/cogs/data/quote.txt new file mode 100644 index 00000000..bee5d8f6 --- /dev/null +++ b/bot/cogs/data/quote.txt @@ -0,0 +1,19 @@ +Beautiful is better than ugly. +Explicit is better than implicit. +Simple is better than complex. +Complex is better than complicated. +Flat is better than nested. +Sparse is better than dense. +Readability counts. +Special cases aren't special enough to break the rules. +Although practicality beats purity. +Errors should never pass silently. +Unless explicitly silenced. +In the face of ambiguity, refuse the temptation to guess. +There should be one-- and preferably only one --obvious way to do it. +Although that way may not be obvious at first unless you're Dutch. +Now is better than never. +Although never is often better than right now. +If the implementation is hard to explain, it's a bad idea. +If the implementation is easy to explain, it may be a good idea. +Namespaces are one honking great idea -- let's do more of those! \ No newline at end of file diff --git a/bot/cogs/snakes.py b/bot/cogs/snakes.py index 2226f610..8351d12a 100644 --- a/bot/cogs/snakes.py +++ b/bot/cogs/snakes.py @@ -23,6 +23,7 @@ async def get_wiki_json(self, params): async with aiohttp.ClientSession(headers={'User-Agent': 'DevBot v.10'}) as cs: async with async_timeout.timeout(20): async with cs.get("https://en.wikipedia.org/w/api.php", params=params) as r: + log.info(f"{r.url}: {r.status}: {r.reason}") return await r.json() async def get_snek(self, name: str = None) -> Dict[str, Any]: @@ -38,6 +39,7 @@ async def get_snek(self, name: str = None) -> Dict[str, Any]: :param name: Optional, the name of the snake to get information for - omit for a random snake :return: A dict containing information on a snake """ + snake_name = name name = name.replace(" ", "_") text_params = {'action': 'query', @@ -45,25 +47,36 @@ async def get_snek(self, name: str = None) -> Dict[str, Any]: 'prop': 'extracts', 'exsentences': '2', 'explaintext': '1', + 'autosuggest': '1', + 'redirects': '1', 'format': 'json'} image_name_params = {'action': 'query', 'titles': name, 'prop': 'images', + 'redirects': '1', + 'autosuggest': '1', 'imlimit': '1', 'format': 'json'} text_json = await self.get_wiki_json(text_params) + image_name_json = await self.get_wiki_json(image_name_params) - # snake_image = "https://pbs.twimg.com/profile_images/662615956670144512/dqsVK6Nw_400x400.jpg" + snake_image = "https://pbs.twimg.com/profile_images/662615956670144512/dqsVK6Nw_400x400.jpg" page_id = list(text_json['query']['pages'].keys())[0] + if page_id == "-1": + snake_dict = {"name": name, "snake_text": "You call that a snake?\nTHIS is a snake!", "snake_image": snake_image} + return snake_dict + image_id = image_name_json['query']['pages'][page_id]['images'][0]['title'] image_url_params = {'action': 'query', 'titles': image_id, 'prop': 'imageinfo', + 'redirects': '1', + 'autosuggest': '1', 'iiprop': 'url', 'format': 'json'} @@ -73,7 +86,7 @@ async def get_snek(self, name: str = None) -> Dict[str, Any]: snake_image = image_url_json['query']['pages'][snake_image_id]['imageinfo'][0]['url'] snake_text = text_json['query']['pages'][page_id]['extract'] - snake_dict = {"name": name, "snake_text": snake_text, "snake_image":snake_image} + snake_dict = {"name": snake_name, "snake_text": snake_text, "snake_image":snake_image} return snake_dict @command() @@ -88,11 +101,21 @@ async def get(self, ctx: Context, name: str = "Vipera berus"): :param name: Optional, the name of the snake to get information for - omit for a random snake https://en.wikipedia.org/w/api.php?action=query&titles=Vipera_berus&prop=extracts&exsentences=2&explaintext=1&format=json """ - snake = await self.get_snek(name) - snake_embed = Embed(color=ctx.me.color, title="SNAKE") - snake_embed.add_field(name=snake['name'], value=snake['snake_text']) - snake_embed.set_thumbnail(url=snake['snake_image']) - await ctx.send(embed=snake_embed) + if name == "snakes on a plane": + await ctx.send("https://media.giphy.com/media/5xtDartXnQbcW5CfM64/giphy.gif") + elif name == "python": + with open('bot/cogs/data/quote.txt', 'r') as file: + text = file.read() + snake_embed = Embed(color=ctx.me.color, title="SNEK") + snake_embed.add_field(name="Python", value=f"*{text}*") + snake_embed.set_thumbnail(url="http://www.pngall.com/wp-content/uploads/2016/05/Python-Logo-Free-PNG-Image.png") + await ctx.send(embed=snake_embed) + else: + snake = await self.get_snek(name) + snake_embed = Embed(color=ctx.me.color, title="SNEK") + snake_embed.add_field(name=snake['name'], value=snake['snake_text']) + snake_embed.set_thumbnail(url=snake['snake_image']) + await ctx.send(embed=snake_embed) # Any additional commands can be placed here. Be creative, but keep it to a reasonable amount! From 642762a04f6b811b37718468577737a472e29a8d Mon Sep 17 00:00:00 2001 From: runew0lf Date: Fri, 23 Mar 2018 20:34:42 +0000 Subject: [PATCH 14/47] linted code and added comments --- bot/cogs/snakes.py | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/bot/cogs/snakes.py b/bot/cogs/snakes.py index 8351d12a..0a76e60a 100644 --- a/bot/cogs/snakes.py +++ b/bot/cogs/snakes.py @@ -10,6 +10,14 @@ log = logging.getLogger(__name__) +SNEKFILE = 'bot/cogs/data/quote.txt' + +FIRST_EMOJI = "💉" +SECOND_EMOJI = "💊" +THIRD_EMOJI = "🌡️" +FOURTH_EMOJI = "☠️" +FIFTH_EMOJI = "⚗️" + class Snakes: """ @@ -40,7 +48,7 @@ async def get_snek(self, name: str = None) -> Dict[str, Any]: :return: A dict containing information on a snake """ snake_name = name - name = name.replace(" ", "_") + name = name.replace(" ", "_") # sanitize name text_params = {'action': 'query', 'titles': name, @@ -60,14 +68,14 @@ async def get_snek(self, name: str = None) -> Dict[str, Any]: 'format': 'json'} text_json = await self.get_wiki_json(text_params) - image_name_json = await self.get_wiki_json(image_name_params) - snake_image = "https://pbs.twimg.com/profile_images/662615956670144512/dqsVK6Nw_400x400.jpg" page_id = list(text_json['query']['pages'].keys())[0] - if page_id == "-1": - snake_dict = {"name": name, "snake_text": "You call that a snake?\nTHIS is a snake!", "snake_image": snake_image} + if page_id == "-1": # No entry on the wiki + snake_dict = {"name": name, + "snake_text": "You call that a snake?\nTHIS is a snake!", + "snake_image": snake_image} return snake_dict image_id = image_name_json['query']['pages'][page_id]['images'][0]['title'] @@ -86,7 +94,7 @@ async def get_snek(self, name: str = None) -> Dict[str, Any]: snake_image = image_url_json['query']['pages'][snake_image_id]['imageinfo'][0]['url'] snake_text = text_json['query']['pages'][page_id]['extract'] - snake_dict = {"name": snake_name, "snake_text": snake_text, "snake_image":snake_image} + snake_dict = {"name": snake_name, "snake_text": snake_text, "snake_image": snake_image} return snake_dict @command() @@ -99,12 +107,11 @@ async def get(self, ctx: Context, name: str = "Vipera berus"): :param ctx: Context object passed from discord.py :param name: Optional, the name of the snake to get information for - omit for a random snake - https://en.wikipedia.org/w/api.php?action=query&titles=Vipera_berus&prop=extracts&exsentences=2&explaintext=1&format=json """ if name == "snakes on a plane": await ctx.send("https://media.giphy.com/media/5xtDartXnQbcW5CfM64/giphy.gif") elif name == "python": - with open('bot/cogs/data/quote.txt', 'r') as file: + with open(SNEKFILE, 'r') as file: text = file.read() snake_embed = Embed(color=ctx.me.color, title="SNEK") snake_embed.add_field(name="Python", value=f"*{text}*") From 84a773a49f030183aa3760cad4ee1f5c3e318997 Mon Sep 17 00:00:00 2001 From: biskette Date: Fri, 23 Mar 2018 21:23:24 +0000 Subject: [PATCH 15/47] Mostly finished snake list --- bot/cogs/wtfisthis.py | 47 +++++++++++++++++++++++++++++++------------ 1 file changed, 34 insertions(+), 13 deletions(-) diff --git a/bot/cogs/wtfisthis.py b/bot/cogs/wtfisthis.py index 9e67e8a9..16898169 100644 --- a/bot/cogs/wtfisthis.py +++ b/bot/cogs/wtfisthis.py @@ -5,25 +5,46 @@ import asyncio -async def query(params): - lastcontinue = {} +async def wikiquery(params): + params['format'] = 'json' async with aiohttp.ClientSession(headers={'User-Agent': 'DickButt v.10rc2'}) as cs: async with async_timeout.timeout(20): - while True: - req = params.copy() - req.update(lastcontinue) - async with cs.get("https://en.wikipedia.org/w/api.php", params=params) as r: - if 'continue' not in r: - break - lastcontinue = r['continue'] + async with cs.get("https://en.wikipedia.org/w/api.php", params=params) as r: + result = await r.json() - return await r.json() + return result + + +async def contquery(params): + last_continue = {} + + while True: + req = params.copy() + req.update(last_continue) + + request = await wikiquery(req) + + if 'query' not in request: + break + + pages = request['query']['pages']['13205433']['links'] + yield pages + + if 'continue' not in request: + break + + last_continue = request['continue'] async def main(): - result = await query({'action': 'query', 'titles': 'list_of_snakes_by_common_name', 'prop': 'links', 'format': 'json'}) - print(result) + ambiguous = ["(disambiguation)", "Wikipedia:", "Help:", "Category:"] + result = contquery({'action': 'query', 'titles': 'list_of_snakes_by_common_name', 'prop': 'links', 'format': 'json'}) + async for dicks in result: + listed = dicks + for item in listed: + if not any(s in item['title'] for s in ambiguous): + print(item['title']) loop = asyncio.get_event_loop() -loop.run_until_complete(main()) \ No newline at end of file +loop.run_until_complete(main()) From da1c8515c2eb351f17fc6ab895f1f4d0307ddef8 Mon Sep 17 00:00:00 2001 From: biskette Date: Fri, 23 Mar 2018 21:24:00 +0000 Subject: [PATCH 16/47] Mostly finished snake list --- bot/cogs/data/quote.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bot/cogs/data/quote.txt b/bot/cogs/data/quote.txt index bee5d8f6..5fe2a08e 100644 --- a/bot/cogs/data/quote.txt +++ b/bot/cogs/data/quote.txt @@ -16,4 +16,5 @@ Now is better than never. Although never is often better than right now. If the implementation is hard to explain, it's a bad idea. If the implementation is easy to explain, it may be a good idea. -Namespaces are one honking great idea -- let's do more of those! \ No newline at end of file +Namespaces are one honking great idea -- let's do more of those! +I like penis. \ No newline at end of file From f7da5b82a0218e95c6d6ad760c86561de5bfff22 Mon Sep 17 00:00:00 2001 From: biskette Date: Fri, 23 Mar 2018 21:32:14 +0000 Subject: [PATCH 17/47] Trimmed to necessary for integration --- bot/cogs/wtfisthis.py | 31 +++++++------------------------ 1 file changed, 7 insertions(+), 24 deletions(-) diff --git a/bot/cogs/wtfisthis.py b/bot/cogs/wtfisthis.py index 16898169..9680a366 100644 --- a/bot/cogs/wtfisthis.py +++ b/bot/cogs/wtfisthis.py @@ -1,22 +1,4 @@ -#!/usr/bin/env python3.6 - -import aiohttp -import async_timeout -import asyncio - - -async def wikiquery(params): - params['format'] = 'json' - - async with aiohttp.ClientSession(headers={'User-Agent': 'DickButt v.10rc2'}) as cs: - async with async_timeout.timeout(20): - async with cs.get("https://en.wikipedia.org/w/api.php", params=params) as r: - result = await r.json() - - return result - - -async def contquery(params): +async def cont_query(params): last_continue = {} while True: @@ -37,14 +19,15 @@ async def contquery(params): last_continue = request['continue'] -async def main(): +async def get_snake_list(): ambiguous = ["(disambiguation)", "Wikipedia:", "Help:", "Category:"] - result = contquery({'action': 'query', 'titles': 'list_of_snakes_by_common_name', 'prop': 'links', 'format': 'json'}) + + snake_list = [] + result = cont_query({'action': 'query', 'titles': 'list_of_snakes_by_common_name', 'prop': 'links', 'format': 'json'}) async for dicks in result: listed = dicks for item in listed: if not any(s in item['title'] for s in ambiguous): - print(item['title']) + snake_list.append(item['title']) -loop = asyncio.get_event_loop() -loop.run_until_complete(main()) + return snake_list From d9095e7739269f74d30aeb5cb3b29975466eb72f Mon Sep 17 00:00:00 2001 From: runew0lf Date: Fri, 23 Mar 2018 22:04:15 +0000 Subject: [PATCH 18/47] Added bisks snake lookup --- bot/cogs/snakes.py | 62 ++++++++++++++++++++++++++++++++++++++++------ bot/pagination.py | 1 + 2 files changed, 55 insertions(+), 8 deletions(-) diff --git a/bot/cogs/snakes.py b/bot/cogs/snakes.py index 0a76e60a..f694f125 100644 --- a/bot/cogs/snakes.py +++ b/bot/cogs/snakes.py @@ -3,6 +3,8 @@ from typing import Any, Dict import aiohttp import async_timeout +import random +import asyncio import pprint from discord.ext.commands import AutoShardedBot, Context, command @@ -18,6 +20,8 @@ FOURTH_EMOJI = "☠️" FIFTH_EMOJI = "⚗️" +snakelist = [] + class Snakes: """ @@ -27,6 +31,10 @@ class Snakes: def __init__(self, bot: AutoShardedBot): self.bot = bot + async def cache_snakelist(self): + global snakelist + snakelist = await self.get_snake_list() + async def get_wiki_json(self, params): async with aiohttp.ClientSession(headers={'User-Agent': 'DevBot v.10'}) as cs: async with async_timeout.timeout(20): @@ -34,6 +42,40 @@ async def get_wiki_json(self, params): log.info(f"{r.url}: {r.status}: {r.reason}") return await r.json() + async def cont_query(self, params): + last_continue = {} + + while True: + req = params.copy() + req.update(last_continue) + + request = await self.get_wiki_json(req) + + if 'query' not in request: + break + + pages = request['query']['pages']['13205433']['links'] + yield pages + + if 'continue' not in request: + break + + last_continue = request['continue'] + + async def get_snake_list(self): + ambiguous = ["(disambiguation)", "Wikipedia:", "Help:", "Category:"] + + snake_list = [] + result = self.cont_query( + {'action': 'query', 'titles': 'list_of_snakes_by_common_name', 'prop': 'links', 'format': 'json'}) + async for dicks in result: + listed = dicks + for item in listed: + if not any(s in item['title'] for s in ambiguous): + snake_list.append(item['title']) + + return snake_list + async def get_snek(self, name: str = None) -> Dict[str, Any]: """ Go online and fetch information about a snake @@ -98,7 +140,8 @@ async def get_snek(self, name: str = None) -> Dict[str, Any]: return snake_dict @command() - async def get(self, ctx: Context, name: str = "Vipera berus"): + async def get(self, ctx: Context, name: str = None): + global snakelist """ Go online and fetch information about a snake @@ -108,7 +151,9 @@ async def get(self, ctx: Context, name: str = "Vipera berus"): :param ctx: Context object passed from discord.py :param name: Optional, the name of the snake to get information for - omit for a random snake """ - if name == "snakes on a plane": + if name is None: + name = random.choice(snakelist) + elif name == "snakes on a plane": await ctx.send("https://media.giphy.com/media/5xtDartXnQbcW5CfM64/giphy.gif") elif name == "python": with open(SNEKFILE, 'r') as file: @@ -117,12 +162,12 @@ async def get(self, ctx: Context, name: str = "Vipera berus"): snake_embed.add_field(name="Python", value=f"*{text}*") snake_embed.set_thumbnail(url="http://www.pngall.com/wp-content/uploads/2016/05/Python-Logo-Free-PNG-Image.png") await ctx.send(embed=snake_embed) - else: - snake = await self.get_snek(name) - snake_embed = Embed(color=ctx.me.color, title="SNEK") - snake_embed.add_field(name=snake['name'], value=snake['snake_text']) - snake_embed.set_thumbnail(url=snake['snake_image']) - await ctx.send(embed=snake_embed) + + snake = await self.get_snek(name) + snake_embed = Embed(color=ctx.me.color, title="SNEK") + snake_embed.add_field(name=snake['name'], value=snake['snake_text']) + snake_embed.set_thumbnail(url=snake['snake_image']) + await ctx.send(embed=snake_embed) # Any additional commands can be placed here. Be creative, but keep it to a reasonable amount! @@ -130,3 +175,4 @@ async def get(self, ctx: Context, name: str = "Vipera berus"): def setup(bot): bot.add_cog(Snakes(bot)) log.info("Cog loaded: Snakes") + bot.loop.create_task(Snakes(bot).cache_snakelist()) \ No newline at end of file diff --git a/bot/pagination.py b/bot/pagination.py index 268f3474..e396f8b0 100644 --- a/bot/pagination.py +++ b/bot/pagination.py @@ -3,6 +3,7 @@ import logging from typing import Iterable, Optional + from discord import Embed, Member, Reaction from discord.abc import User from discord.ext.commands import Context, Paginator From fb0423f6b00c19423e94f08b11c2dc10e382e385 Mon Sep 17 00:00:00 2001 From: runew0lf Date: Fri, 23 Mar 2018 22:07:36 +0000 Subject: [PATCH 19/47] Caches snakelist on startup --- bot/cogs/snakes.py | 1 + 1 file changed, 1 insertion(+) diff --git a/bot/cogs/snakes.py b/bot/cogs/snakes.py index f694f125..14e9d189 100644 --- a/bot/cogs/snakes.py +++ b/bot/cogs/snakes.py @@ -74,6 +74,7 @@ async def get_snake_list(self): if not any(s in item['title'] for s in ambiguous): snake_list.append(item['title']) + snake_list.append("trouser snake") return snake_list async def get_snek(self, name: str = None) -> Dict[str, Any]: From b33bf1f8eb451392d612040b7a69e0223b4e2818 Mon Sep 17 00:00:00 2001 From: runew0lf Date: Fri, 23 Mar 2018 22:17:50 +0000 Subject: [PATCH 20/47] Added check to make sure we're selecting a snake --- bot/cogs/snakes.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/bot/cogs/snakes.py b/bot/cogs/snakes.py index 14e9d189..cd667579 100644 --- a/bot/cogs/snakes.py +++ b/bot/cogs/snakes.py @@ -90,6 +90,7 @@ async def get_snek(self, name: str = None) -> Dict[str, Any]: :param name: Optional, the name of the snake to get information for - omit for a random snake :return: A dict containing information on a snake """ + global snakelist snake_name = name name = name.replace(" ", "_") # sanitize name @@ -115,8 +116,8 @@ async def get_snek(self, name: str = None) -> Dict[str, Any]: snake_image = "https://pbs.twimg.com/profile_images/662615956670144512/dqsVK6Nw_400x400.jpg" page_id = list(text_json['query']['pages'].keys())[0] - if page_id == "-1": # No entry on the wiki - snake_dict = {"name": name, + if page_id == "-1" or snake_name not in snakelist: # No entry on the wiki + snake_dict = {"name": snake_name, "snake_text": "You call that a snake?\nTHIS is a snake!", "snake_image": snake_image} return snake_dict From 70158639ed5e84a69ec52c6410e65eab07c1efa4 Mon Sep 17 00:00:00 2001 From: runew0lf Date: Fri, 23 Mar 2018 22:32:43 +0000 Subject: [PATCH 21/47] Removed wtfisthis --- bot/cogs/wtfisthis.py | 33 --------------------------------- 1 file changed, 33 deletions(-) delete mode 100644 bot/cogs/wtfisthis.py diff --git a/bot/cogs/wtfisthis.py b/bot/cogs/wtfisthis.py deleted file mode 100644 index 9680a366..00000000 --- a/bot/cogs/wtfisthis.py +++ /dev/null @@ -1,33 +0,0 @@ -async def cont_query(params): - last_continue = {} - - while True: - req = params.copy() - req.update(last_continue) - - request = await wikiquery(req) - - if 'query' not in request: - break - - pages = request['query']['pages']['13205433']['links'] - yield pages - - if 'continue' not in request: - break - - last_continue = request['continue'] - - -async def get_snake_list(): - ambiguous = ["(disambiguation)", "Wikipedia:", "Help:", "Category:"] - - snake_list = [] - result = cont_query({'action': 'query', 'titles': 'list_of_snakes_by_common_name', 'prop': 'links', 'format': 'json'}) - async for dicks in result: - listed = dicks - for item in listed: - if not any(s in item['title'] for s in ambiguous): - snake_list.append(item['title']) - - return snake_list From c5464453e3895a50c5ca1f675c6627819c28f50b Mon Sep 17 00:00:00 2001 From: runew0lf Date: Sat, 24 Mar 2018 06:04:50 +0000 Subject: [PATCH 22/47] Linted code --- bot/cogs/snakes.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/bot/cogs/snakes.py b/bot/cogs/snakes.py index cd667579..fbf765dc 100644 --- a/bot/cogs/snakes.py +++ b/bot/cogs/snakes.py @@ -4,8 +4,6 @@ import aiohttp import async_timeout import random -import asyncio -import pprint from discord.ext.commands import AutoShardedBot, Context, command from discord import Embed @@ -13,6 +11,8 @@ log = logging.getLogger(__name__) SNEKFILE = 'bot/cogs/data/quote.txt' +PYTHONPIC = "http://www.pngall.com/wp-content/uploads/2016/05/Python-Logo-Free-PNG-Image.png" +DEFAULT_SNEK = "https://pbs.twimg.com/profile_images/662615956670144512/dqsVK6Nw_400x400.jpg" FIRST_EMOJI = "💉" SECOND_EMOJI = "💊" @@ -113,12 +113,13 @@ async def get_snek(self, name: str = None) -> Dict[str, Any]: text_json = await self.get_wiki_json(text_params) image_name_json = await self.get_wiki_json(image_name_params) - snake_image = "https://pbs.twimg.com/profile_images/662615956670144512/dqsVK6Nw_400x400.jpg" + snake_image = DEFAULT_SNEK page_id = list(text_json['query']['pages'].keys())[0] if page_id == "-1" or snake_name not in snakelist: # No entry on the wiki snake_dict = {"name": snake_name, - "snake_text": "You call that a snake?\nTHIS is a snake!", + "snake_text": "You call that a snake?\n" + "THIS is a snake!", "snake_image": snake_image} return snake_dict @@ -162,7 +163,7 @@ async def get(self, ctx: Context, name: str = None): text = file.read() snake_embed = Embed(color=ctx.me.color, title="SNEK") snake_embed.add_field(name="Python", value=f"*{text}*") - snake_embed.set_thumbnail(url="http://www.pngall.com/wp-content/uploads/2016/05/Python-Logo-Free-PNG-Image.png") + snake_embed.set_thumbnail(url=PYTHONPIC) await ctx.send(embed=snake_embed) snake = await self.get_snek(name) @@ -177,4 +178,4 @@ async def get(self, ctx: Context, name: str = None): def setup(bot): bot.add_cog(Snakes(bot)) log.info("Cog loaded: Snakes") - bot.loop.create_task(Snakes(bot).cache_snakelist()) \ No newline at end of file + bot.loop.create_task(Snakes(bot).cache_snakelist()) From b93ae6a80754775f98b4aa14f0d85c4239d46ae2 Mon Sep 17 00:00:00 2001 From: runew0lf Date: Sat, 24 Mar 2018 10:50:08 +0000 Subject: [PATCH 23/47] Linted code and started on antidote game --- bot/cogs/data/quote.txt | 3 +- bot/cogs/snakes.py | 102 ++++++++++++++++++++++++++++++++++------ bot/pagination.py | 1 - 3 files changed, 88 insertions(+), 18 deletions(-) diff --git a/bot/cogs/data/quote.txt b/bot/cogs/data/quote.txt index 5fe2a08e..bee5d8f6 100644 --- a/bot/cogs/data/quote.txt +++ b/bot/cogs/data/quote.txt @@ -16,5 +16,4 @@ Now is better than never. Although never is often better than right now. If the implementation is hard to explain, it's a bad idea. If the implementation is easy to explain, it may be a good idea. -Namespaces are one honking great idea -- let's do more of those! -I like penis. \ No newline at end of file +Namespaces are one honking great idea -- let's do more of those! \ No newline at end of file diff --git a/bot/cogs/snakes.py b/bot/cogs/snakes.py index fbf765dc..46dfc2b5 100644 --- a/bot/cogs/snakes.py +++ b/bot/cogs/snakes.py @@ -1,12 +1,16 @@ # coding=utf-8 +import asyncio import logging +import random from typing import Any, Dict + import aiohttp + import async_timeout -import random +from discord import Embed, Member, Reaction from discord.ext.commands import AutoShardedBot, Context, command -from discord import Embed + log = logging.getLogger(__name__) @@ -14,13 +18,24 @@ PYTHONPIC = "http://www.pngall.com/wp-content/uploads/2016/05/Python-Logo-Free-PNG-Image.png" DEFAULT_SNEK = "https://pbs.twimg.com/profile_images/662615956670144512/dqsVK6Nw_400x400.jpg" -FIRST_EMOJI = "💉" -SECOND_EMOJI = "💊" -THIRD_EMOJI = "🌡️" -FOURTH_EMOJI = "☠️" -FIFTH_EMOJI = "⚗️" +# Pegs +FIRST_EMOJI = "\U0001F489" +SECOND_EMOJI = "\U0001F48A" +THIRD_EMOJI = "\u231B" +FOURTH_EMOJI = "\u2620" +FIFTH_EMOJI = "\u2697" + +EMPTY = u'\u200b' -snakelist = [] +# Results +TICK_EMOJI = "\u2714" # Correct Peg, Correct Hole +CROSS_EMOJI = "\u274C" # Wrong +BLANK_EMOJI = "\u26AA" # Correct Peg Wrong Hole + +# Holes +HOLE_EMOJI = "\u2B1C" + +ANTIDOTE_EMOJI = [FIRST_EMOJI, SECOND_EMOJI, THIRD_EMOJI, FOURTH_EMOJI, FIFTH_EMOJI] class Snakes: @@ -30,10 +45,12 @@ class Snakes: def __init__(self, bot: AutoShardedBot): self.bot = bot + self.snakelist = [] + self.setup = bot.loop.create_task(self.cache_snakelist()) async def cache_snakelist(self): - global snakelist - snakelist = await self.get_snake_list() + return + self.snakelist = await self.get_snake_list() async def get_wiki_json(self, params): async with aiohttp.ClientSession(headers={'User-Agent': 'DevBot v.10'}) as cs: @@ -90,7 +107,7 @@ async def get_snek(self, name: str = None) -> Dict[str, Any]: :param name: Optional, the name of the snake to get information for - omit for a random snake :return: A dict containing information on a snake """ - global snakelist + await self.setup # pauses here until the "setup" task has completed snake_name = name name = name.replace(" ", "_") # sanitize name @@ -116,7 +133,7 @@ async def get_snek(self, name: str = None) -> Dict[str, Any]: snake_image = DEFAULT_SNEK page_id = list(text_json['query']['pages'].keys())[0] - if page_id == "-1" or snake_name not in snakelist: # No entry on the wiki + if page_id == "-1" or snake_name not in self.snakelist: # No entry on the wiki snake_dict = {"name": snake_name, "snake_text": "You call that a snake?\n" "THIS is a snake!", @@ -144,7 +161,6 @@ async def get_snek(self, name: str = None) -> Dict[str, Any]: @command() async def get(self, ctx: Context, name: str = None): - global snakelist """ Go online and fetch information about a snake @@ -155,7 +171,7 @@ 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 """ if name is None: - name = random.choice(snakelist) + name = random.choice(self.snakelist) elif name == "snakes on a plane": await ctx.send("https://media.giphy.com/media/5xtDartXnQbcW5CfM64/giphy.gif") elif name == "python": @@ -173,9 +189,65 @@ async def get(self, ctx: Context, name: str = None): await ctx.send(embed=snake_embed) # Any additional commands can be placed here. Be creative, but keep it to a reasonable amount! + @command(name="bb") + async def build_board(self, ctx: Context): + antidote_embed = Embed(color=ctx.me.color, title="Antidote") + antidote_embed.set_author(name=ctx.author.name, icon_url=ctx.author.avatar_url) + # Generate answer + antidote_answer = list(ANTIDOTE_EMOJI) # duplicate list, not reference it + random.shuffle(antidote_answer) + log.info(antidote_answer) + # begin board building + board = [] + for i in range(0, 10): + board.append(f"`{10-i:02d}` " + f"{HOLE_EMOJI} {HOLE_EMOJI} {HOLE_EMOJI} {HOLE_EMOJI} - " + f"{CROSS_EMOJI} {CROSS_EMOJI} {CROSS_EMOJI} {CROSS_EMOJI}") + board.append(EMPTY) + + antidote_embed.add_field(name="10 guesses remaining", value="\n".join(board)) + # Display board + board_id = await ctx.send(embed=antidote_embed) + # add our reactions + for emoji in ANTIDOTE_EMOJI: + await board_id.add_reaction(emoji) + + def event_check(reaction_: Reaction, user_: Member): + """ + Make sure that this reaction is what we want to operate on + """ + + no_restrictions = ( + # Pagination is not restricted + user_.id == ctx.author.id + ) + + return ( + # Conditions for a successful pagination: + all(( + # Reaction is on this message + reaction_.message.id == board_id.id, + # Reaction is one of the pagination emotes + reaction_.emoji in ANTIDOTE_EMOJI, + # Reaction was not made by the Bot + user_.id != self.bot.user.id, + # There were no restrictions + no_restrictions + )) + ) + + while True: + try: + reaction, user = await ctx.bot.wait_for("reaction_add", timeout=300, check=event_check) + log.trace(f"Got reaction: {reaction}") + except asyncio.TimeoutError: + log.debug("Timed out waiting for a reaction") + break # We're done, no reactions for the last 5 minutes + + log.debug("Ending pagination and removing all reactions...") + await board_id.clear_reactions() def setup(bot): bot.add_cog(Snakes(bot)) log.info("Cog loaded: Snakes") - bot.loop.create_task(Snakes(bot).cache_snakelist()) diff --git a/bot/pagination.py b/bot/pagination.py index e396f8b0..268f3474 100644 --- a/bot/pagination.py +++ b/bot/pagination.py @@ -3,7 +3,6 @@ import logging from typing import Iterable, Optional - from discord import Embed, Member, Reaction from discord.abc import User from discord.ext.commands import Context, Paginator From 3994f683fe1ff236dcff458927e6aa851b948a1e Mon Sep 17 00:00:00 2001 From: biskette Date: Sat, 24 Mar 2018 10:57:38 +0000 Subject: [PATCH 24/47] Trimmed to necessary for integration --- bot/cogs/snakes.py | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/bot/cogs/snakes.py b/bot/cogs/snakes.py index cd667579..70020f93 100644 --- a/bot/cogs/snakes.py +++ b/bot/cogs/snakes.py @@ -20,7 +20,7 @@ FOURTH_EMOJI = "☠️" FIFTH_EMOJI = "⚗️" -snakelist = [] +snake_cache = [] class Snakes: @@ -32,8 +32,8 @@ def __init__(self, bot: AutoShardedBot): self.bot = bot async def cache_snakelist(self): - global snakelist - snakelist = await self.get_snake_list() + global snake_cache + snake_cache = await self.get_snake_list() async def get_wiki_json(self, params): async with aiohttp.ClientSession(headers={'User-Agent': 'DevBot v.10'}) as cs: @@ -71,8 +71,8 @@ async def get_snake_list(self): async for dicks in result: listed = dicks for item in listed: - if not any(s in item['title'] for s in ambiguous): - snake_list.append(item['title']) + # if not any(s in item['title'] for s in ambiguous): + snake_list.append(item['title']) snake_list.append("trouser snake") return snake_list @@ -90,7 +90,7 @@ async def get_snek(self, name: str = None) -> Dict[str, Any]: :param name: Optional, the name of the snake to get information for - omit for a random snake :return: A dict containing information on a snake """ - global snakelist + global snake_cache snake_name = name name = name.replace(" ", "_") # sanitize name @@ -116,12 +116,15 @@ async def get_snek(self, name: str = None) -> Dict[str, Any]: snake_image = "https://pbs.twimg.com/profile_images/662615956670144512/dqsVK6Nw_400x400.jpg" page_id = list(text_json['query']['pages'].keys())[0] - if page_id == "-1" or snake_name not in snakelist: # No entry on the wiki + if page_id == "-1" or snake_name not in snake_cache: # No entry on the wiki snake_dict = {"name": snake_name, "snake_text": "You call that a snake?\nTHIS is a snake!", "snake_image": snake_image} return snake_dict + if any(s in snake_name for s in snake_cache): + print("Yes there is a snake in here") + image_id = image_name_json['query']['pages'][page_id]['images'][0]['title'] image_url_params = {'action': 'query', @@ -143,7 +146,7 @@ async def get_snek(self, name: str = None) -> Dict[str, Any]: @command() async def get(self, ctx: Context, name: str = None): - global snakelist + global snake_cache """ Go online and fetch information about a snake @@ -154,7 +157,7 @@ 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 """ if name is None: - name = random.choice(snakelist) + name = random.choice(snake_cache) elif name == "snakes on a plane": await ctx.send("https://media.giphy.com/media/5xtDartXnQbcW5CfM64/giphy.gif") elif name == "python": From 0f3acb4cbee372100fff9424e973baa7a460122c Mon Sep 17 00:00:00 2001 From: runew0lf Date: Sat, 24 Mar 2018 12:47:51 +0000 Subject: [PATCH 25/47] Linted code and started on antidote game --- bot/cogs/snakes.py | 52 ++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 46 insertions(+), 6 deletions(-) diff --git a/bot/cogs/snakes.py b/bot/cogs/snakes.py index 46dfc2b5..5fcce59f 100644 --- a/bot/cogs/snakes.py +++ b/bot/cogs/snakes.py @@ -28,7 +28,7 @@ EMPTY = u'\u200b' # Results -TICK_EMOJI = "\u2714" # Correct Peg, Correct Hole +TICK_EMOJI = "\u2705" # Correct Peg, Correct Hole CROSS_EMOJI = "\u274C" # Wrong BLANK_EMOJI = "\u26AA" # Correct Peg Wrong Hole @@ -191,24 +191,32 @@ async def get(self, ctx: Context, name: str = None): # Any additional commands can be placed here. Be creative, but keep it to a reasonable amount! @command(name="bb") async def build_board(self, ctx: Context): + antidote_tries = 0 + antidote_guess_count = 0 + antidote_guess_list = [] + guess_result = [] + board = [] + page_guess_list = [] + page_result_list = [] antidote_embed = Embed(color=ctx.me.color, title="Antidote") antidote_embed.set_author(name=ctx.author.name, icon_url=ctx.author.avatar_url) # Generate answer antidote_answer = list(ANTIDOTE_EMOJI) # duplicate list, not reference it random.shuffle(antidote_answer) + antidote_answer.pop() log.info(antidote_answer) # begin board building - board = [] for i in range(0, 10): + page_guess_list.append(f"{HOLE_EMOJI} {HOLE_EMOJI} {HOLE_EMOJI} {HOLE_EMOJI}") + page_result_list.append(f"{CROSS_EMOJI} {CROSS_EMOJI} {CROSS_EMOJI} {CROSS_EMOJI}") board.append(f"`{10-i:02d}` " - f"{HOLE_EMOJI} {HOLE_EMOJI} {HOLE_EMOJI} {HOLE_EMOJI} - " - f"{CROSS_EMOJI} {CROSS_EMOJI} {CROSS_EMOJI} {CROSS_EMOJI}") + f"{page_guess_list[i]} - " + f"{page_result_list[i]}") board.append(EMPTY) - antidote_embed.add_field(name="10 guesses remaining", value="\n".join(board)) # Display board board_id = await ctx.send(embed=antidote_embed) - # add our reactions + # add our player reactions for emoji in ANTIDOTE_EMOJI: await board_id.add_reaction(emoji) @@ -240,6 +248,38 @@ def event_check(reaction_: Reaction, user_: Member): try: reaction, user = await ctx.bot.wait_for("reaction_add", timeout=300, check=event_check) log.trace(f"Got reaction: {reaction}") + if antidote_tries < 10: + if antidote_guess_count < 4: + if reaction.emoji in ANTIDOTE_EMOJI: + antidote_guess_list.append(reaction.emoji) + antidote_guess_count += 1 + + if antidote_guess_count == 4: # GUESSES COMPLETE + antidote_guess_count = 0 + page_guess_list[antidote_tries] = " ".join(antidote_guess_list) + log.info(f"Guess: {' '.join(antidote_guess_list)}") + + # Now Check Guess + for i in range(0, len(antidote_answer)): + if antidote_guess_list[i] == antidote_answer[i]: + guess_result.append(TICK_EMOJI) + elif antidote_guess_list[i] in antidote_answer: + guess_result.append(BLANK_EMOJI) + else: + guess_result.append(CROSS_EMOJI) + page_result_list[antidote_tries] = " ".join(guess_result) + log.info(f"Guess Result: {' '.join(guess_result)}") + board = [] + for i in range(0, 10): + page_guess_list.append(f"{HOLE_EMOJI} {HOLE_EMOJI} {HOLE_EMOJI} {HOLE_EMOJI}") + page_result_list.append(f"{CROSS_EMOJI} {CROSS_EMOJI} {CROSS_EMOJI} {CROSS_EMOJI}") + board.append(f"`{10-i:02d}` " + f"{page_guess_list[i]} - " + f"{page_result_list[i]}") + board.append(EMPTY) + antidote_embed.add_field(name="10 guesses remaining", value="\n".join(board)) + await board_id.edit(embed=antidote_embed) + except asyncio.TimeoutError: log.debug("Timed out waiting for a reaction") break # We're done, no reactions for the last 5 minutes From 684e92112db02358c0b1d85a7456d0691c604617 Mon Sep 17 00:00:00 2001 From: runew0lf Date: Sat, 24 Mar 2018 13:32:45 +0000 Subject: [PATCH 26/47] Linted code and started on antidote game --- bot/cogs/snakes.py | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/bot/cogs/snakes.py b/bot/cogs/snakes.py index 5fcce59f..509bab74 100644 --- a/bot/cogs/snakes.py +++ b/bot/cogs/snakes.py @@ -209,7 +209,7 @@ async def build_board(self, ctx: Context): for i in range(0, 10): page_guess_list.append(f"{HOLE_EMOJI} {HOLE_EMOJI} {HOLE_EMOJI} {HOLE_EMOJI}") page_result_list.append(f"{CROSS_EMOJI} {CROSS_EMOJI} {CROSS_EMOJI} {CROSS_EMOJI}") - board.append(f"`{10-i:02d}` " + board.append(f"`{i+1:02d}` " f"{page_guess_list[i]} - " f"{page_result_list[i]}") board.append(EMPTY) @@ -271,13 +271,19 @@ def event_check(reaction_: Reaction, user_: Member): log.info(f"Guess Result: {' '.join(guess_result)}") board = [] for i in range(0, 10): - page_guess_list.append(f"{HOLE_EMOJI} {HOLE_EMOJI} {HOLE_EMOJI} {HOLE_EMOJI}") - page_result_list.append(f"{CROSS_EMOJI} {CROSS_EMOJI} {CROSS_EMOJI} {CROSS_EMOJI}") - board.append(f"`{10-i:02d}` " + board.append(f"`{i+1:02d}` " f"{page_guess_list[i]} - " f"{page_result_list[i]}") board.append(EMPTY) - antidote_embed.add_field(name="10 guesses remaining", value="\n".join(board)) + for emoji in antidote_guess_list: + await board_id.remove_reaction(emoji, user) + + antidote_tries += 1 + guess_result = [] + antidote_guess_list = [] + + antidote_embed.clear_fields() + antidote_embed.add_field(name=f"{10 - antidote_tries} guesses remaining", value="\n".join(board)) await board_id.edit(embed=antidote_embed) except asyncio.TimeoutError: From 75fb50c05f0db78a80a952fa6f27d325a99bda3b Mon Sep 17 00:00:00 2001 From: runew0lf Date: Sat, 24 Mar 2018 15:01:24 +0000 Subject: [PATCH 27/47] Linted code and finished basic game --- bot/cogs/snakes.py | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/bot/cogs/snakes.py b/bot/cogs/snakes.py index 509bab74..5d0e8603 100644 --- a/bot/cogs/snakes.py +++ b/bot/cogs/snakes.py @@ -198,6 +198,7 @@ async def build_board(self, ctx: Context): board = [] page_guess_list = [] page_result_list = [] + win = False antidote_embed = Embed(color=ctx.me.color, title="Antidote") antidote_embed.set_author(name=ctx.author.name, icon_url=ctx.author.avatar_url) # Generate answer @@ -247,14 +248,13 @@ def event_check(reaction_: Reaction, user_: Member): while True: try: reaction, user = await ctx.bot.wait_for("reaction_add", timeout=300, check=event_check) - log.trace(f"Got reaction: {reaction}") if antidote_tries < 10: if antidote_guess_count < 4: if reaction.emoji in ANTIDOTE_EMOJI: antidote_guess_list.append(reaction.emoji) antidote_guess_count += 1 - if antidote_guess_count == 4: # GUESSES COMPLETE + if antidote_guess_count == 4: # GUESSES COMPLETE antidote_guess_count = 0 page_guess_list[antidote_tries] = " ".join(antidote_guess_list) log.info(f"Guess: {' '.join(antidote_guess_list)}") @@ -267,6 +267,7 @@ def event_check(reaction_: Reaction, user_: Member): guess_result.append(BLANK_EMOJI) else: guess_result.append(CROSS_EMOJI) + guess_result.sort() page_result_list[antidote_tries] = " ".join(guess_result) log.info(f"Guess Result: {' '.join(guess_result)}") board = [] @@ -278,18 +279,35 @@ def event_check(reaction_: Reaction, user_: Member): for emoji in antidote_guess_list: await board_id.remove_reaction(emoji, user) + if antidote_guess_list == antidote_answer: + win = True + antidote_tries += 1 guess_result = [] antidote_guess_list = [] antidote_embed.clear_fields() - antidote_embed.add_field(name=f"{10 - antidote_tries} guesses remaining", value="\n".join(board)) + antidote_embed.add_field(name=f"{10 - antidote_tries} " + f"guesses remaining", + value="\n".join(board)) await board_id.edit(embed=antidote_embed) + if win is True: + break + if antidote_tries == 10: + break + except asyncio.TimeoutError: log.debug("Timed out waiting for a reaction") break # We're done, no reactions for the last 5 minutes + if win is True: + await ctx.send(f"You have created the snake antidote! with {10 - antidote_tries} tries remaining") + await board_id.clear_reactions() + else: + await ctx.send(f"Sorry you didnt make the antidote in time, the formula was {' '.join(antidote_answer)}") + await board_id.clear_reactions() + log.debug("Ending pagination and removing all reactions...") await board_id.clear_reactions() From bd44a3f42e6ee13858245465c5d315cf0cf2d8ee Mon Sep 17 00:00:00 2001 From: runew0lf Date: Sat, 24 Mar 2018 15:01:59 +0000 Subject: [PATCH 28/47] Linted code and finished basic game --- bot/cogs/snakes.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bot/cogs/snakes.py b/bot/cogs/snakes.py index 5d0e8603..1817e51b 100644 --- a/bot/cogs/snakes.py +++ b/bot/cogs/snakes.py @@ -189,7 +189,7 @@ async def get(self, ctx: Context, name: str = None): await ctx.send(embed=snake_embed) # Any additional commands can be placed here. Be creative, but keep it to a reasonable amount! - @command(name="bb") + @command(name="antidote") async def build_board(self, ctx: Context): antidote_tries = 0 antidote_guess_count = 0 From 96551b36e4c008c8e6e0cb15fb65a06013e7525a Mon Sep 17 00:00:00 2001 From: biskette Date: Sat, 24 Mar 2018 16:14:48 +0000 Subject: [PATCH 29/47] Working on nicer return for ambiguous searches --- bot/cogs/snakes.py | 120 ++++++++++++++++++++++++++++++++------------- 1 file changed, 85 insertions(+), 35 deletions(-) diff --git a/bot/cogs/snakes.py b/bot/cogs/snakes.py index 46dfc2b5..9246fa05 100644 --- a/bot/cogs/snakes.py +++ b/bot/cogs/snakes.py @@ -2,6 +2,7 @@ import asyncio import logging import random +from string import capwords from typing import Any, Dict import aiohttp @@ -14,9 +15,9 @@ log = logging.getLogger(__name__) -SNEKFILE = 'bot/cogs/data/quote.txt' -PYTHONPIC = "http://www.pngall.com/wp-content/uploads/2016/05/Python-Logo-Free-PNG-Image.png" -DEFAULT_SNEK = "https://pbs.twimg.com/profile_images/662615956670144512/dqsVK6Nw_400x400.jpg" +PYTHON_QUOTE = 'bot/cogs/data/quote.txt' +PYTHON_PIC = "http://www.pngall.com/wp-content/uploads/2016/05/Python-Logo-Free-PNG-Image.png" +DEFAULT_SNAKE = "https://pbs.twimg.com/profile_images/662615956670144512/dqsVK6Nw_400x400.jpg" # Pegs FIRST_EMOJI = "\U0001F489" @@ -45,14 +46,25 @@ class Snakes: def __init__(self, bot: AutoShardedBot): self.bot = bot - self.snakelist = [] - self.setup = bot.loop.create_task(self.cache_snakelist()) + self.snake_cache = [] - async def cache_snakelist(self): + # This caches the very expensive snake list operation on load + self.setup = bot.loop.create_task(self.cache_snake_list()) + + async def cache_snake_list(self): + """ + Calls get_snake_list, which is *very* hungry, and caches it + :return: + """ + self.snake_cache = await self.get_snake_list() return - self.snakelist = await self.get_snake_list() async def get_wiki_json(self, params): + """ + Makes a call to the Wikipedia API using the passed params and returns it as json + :param params: Pass the params as some kind of dictionary / json thing + :return: + """ async with aiohttp.ClientSession(headers={'User-Agent': 'DevBot v.10'}) as cs: async with async_timeout.timeout(20): async with cs.get("https://en.wikipedia.org/w/api.php", params=params) as r: @@ -60,12 +72,17 @@ async def get_wiki_json(self, params): return await r.json() async def cont_query(self, params): + """ + This function checks for continue within the results of the API call and then appends the params + to continue the API call across multiple pages + :param params: Pass the params as some kind of dictionary / json thing + :return: + """ last_continue = {} while True: req = params.copy() req.update(last_continue) - request = await self.get_wiki_json(req) if 'query' not in request: @@ -80,36 +97,38 @@ async def cont_query(self, params): last_continue = request['continue'] async def get_snake_list(self): - ambiguous = ["(disambiguation)", "Wikipedia:", "Help:", "Category:"] + """ + This queries the API for a specific list (of snakes by common name) and returns + a sanitized list of snake names, minus the ambiguous terms... Plus some junk ;) + :return: + """ + ambiguous = ["(disambiguation)", "wikipedia:", "help:", "category:", "list of"] snake_list = [] result = self.cont_query( {'action': 'query', 'titles': 'list_of_snakes_by_common_name', 'prop': 'links', 'format': 'json'}) - async for dicks in result: - listed = dicks + + async for params in result: + listed = params for item in listed: - if not any(s in item['title'] for s in ambiguous): - snake_list.append(item['title']) + if not any(s in item['title'].lower() for s in ambiguous): + snake_list.append(item['title'].lower()) snake_list.append("trouser snake") + snake_list = sorted(list(set(snake_list))) return snake_list async def get_snek(self, name: str = None) -> Dict[str, Any]: """ - Go online and fetch information about a snake - - The information includes the name of the snake, a picture of the snake, and various other pieces of info. - What information you get for the snake is up to you. Be creative! - - If "python" is given as the snake name, you should return information about the programming language, but with - all the information you'd provide for a real snake. Try to have some fun with this! - - :param name: Optional, the name of the snake to get information for - omit for a random snake - :return: A dict containing information on a snake + On user input it validates vs the snake cache and also that the page exists + If the page doesn't exist it sends a ssssassy message + If the page does exist it passes off the params to get_wiki_json + :param name: Just some sort of user input, preferably a snake. + :return: """ - await self.setup # pauses here until the "setup" task has completed + await self.setup # Pauses here until the "setup" task has completed snake_name = name - name = name.replace(" ", "_") # sanitize name + name = name.replace(" ", "_") # Sanitize name for use with the API text_params = {'action': 'query', 'titles': name, @@ -130,10 +149,42 @@ async def get_snek(self, name: str = None) -> Dict[str, Any]: text_json = await self.get_wiki_json(text_params) image_name_json = await self.get_wiki_json(image_name_params) - snake_image = DEFAULT_SNEK + snake_image = DEFAULT_SNAKE + + # Here we check if *ANY* of the values a user has submitted + # match *ANY* of the values in snake_cache page_id = list(text_json['query']['pages'].keys())[0] - if page_id == "-1" or snake_name not in self.snakelist: # No entry on the wiki + if page_id == "-1" or snake_name.lower() not in self.snake_cache: + matched_snakes = [] + + for snake in self.snake_cache: + if any(s in snake for s in snake_name.lower().split()): + matched_snakes.append(snake) + + if matched_snakes: + if len(matched_snakes) > 1: + random.shuffle(matched_snakes) + trimmed_snakes = [] + for snake in matched_snakes[0:9]: + trimmed_snakes.append(capwords(f'{snake}') + '\n') + + trimmed_snakes = sorted(trimmed_snakes) + print(f"Trimmed: {trimmed_snakes}") + + snake_dict = {"name": "No snake found, here are some suggestions:", + "snake_text": ''.join(trimmed_snakes), + "snake_image": snake_image} + return snake_dict + else: + snake = matched_snakes[0] + print(snake) + snake_dict = {"name": snake_name, + "snake_text": '', + "snake_image": snake_image} + # return await self.get_snek(snake) + + snake_dict = {"name": snake_name, "snake_text": "You call that a snake?\n" "THIS is a snake!", @@ -162,25 +213,24 @@ async def get_snek(self, name: str = None) -> Dict[str, Any]: @command() async def get(self, ctx: Context, name: str = None): """ - Go online and fetch information about a snake - - This should make use of your `get_snek` method, using it to get information about a snake. This information - should be sent back to Discord in an embed. - + Calls get_snek and puts results inside an embed for sending + If it matches some special checks, alternative action is taken :param ctx: Context object passed from discord.py :param name: Optional, the name of the snake to get information for - omit for a random snake """ if name is None: - name = random.choice(self.snakelist) + name = random.choice(self.snake_cache) elif name == "snakes on a plane": await ctx.send("https://media.giphy.com/media/5xtDartXnQbcW5CfM64/giphy.gif") + return elif name == "python": - with open(SNEKFILE, 'r') as file: + with open(PYTHON_QUOTE, 'r') as file: text = file.read() snake_embed = Embed(color=ctx.me.color, title="SNEK") snake_embed.add_field(name="Python", value=f"*{text}*") - snake_embed.set_thumbnail(url=PYTHONPIC) + snake_embed.set_thumbnail(url=PYTHON_PIC) await ctx.send(embed=snake_embed) + return snake = await self.get_snek(name) snake_embed = Embed(color=ctx.me.color, title="SNEK") From 631d2cebae617f510704594c95b09981697df102 Mon Sep 17 00:00:00 2001 From: biskette Date: Sat, 24 Mar 2018 16:37:45 +0000 Subject: [PATCH 30/47] Making some checks for in snake_cache but -1 pageid --- bot/cogs/snakes.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/bot/cogs/snakes.py b/bot/cogs/snakes.py index 9246fa05..a21dc424 100644 --- a/bot/cogs/snakes.py +++ b/bot/cogs/snakes.py @@ -156,6 +156,12 @@ async def get_snek(self, name: str = None) -> Dict[str, Any]: page_id = list(text_json['query']['pages'].keys())[0] if page_id == "-1" or snake_name.lower() not in self.snake_cache: + if page_id == "-1" and snake_name.lower() in self.snake_cache: + snake_dict = {"name": "No one has written about this snake! Have some suggestions:", + "snake_text": self.get_snek('snake'), + "snake_image": snake_image} + return snake_dict + matched_snakes = [] for snake in self.snake_cache: @@ -182,7 +188,7 @@ async def get_snek(self, name: str = None) -> Dict[str, Any]: snake_dict = {"name": snake_name, "snake_text": '', "snake_image": snake_image} - # return await self.get_snek(snake) + return await self.get_snek(snake) snake_dict = {"name": snake_name, From a402c17400ca952102eb46fe411e86260bbc3a09 Mon Sep 17 00:00:00 2001 From: biskette Date: Sat, 24 Mar 2018 17:03:27 +0000 Subject: [PATCH 31/47] Stuff about a snake being in list but no page --- bot/cogs/snakes.py | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/bot/cogs/snakes.py b/bot/cogs/snakes.py index a21dc424..5a11c0ef 100644 --- a/bot/cogs/snakes.py +++ b/bot/cogs/snakes.py @@ -156,12 +156,6 @@ async def get_snek(self, name: str = None) -> Dict[str, Any]: page_id = list(text_json['query']['pages'].keys())[0] if page_id == "-1" or snake_name.lower() not in self.snake_cache: - if page_id == "-1" and snake_name.lower() in self.snake_cache: - snake_dict = {"name": "No one has written about this snake! Have some suggestions:", - "snake_text": self.get_snek('snake'), - "snake_image": snake_image} - return snake_dict - matched_snakes = [] for snake in self.snake_cache: @@ -169,12 +163,20 @@ async def get_snek(self, name: str = None) -> Dict[str, Any]: matched_snakes.append(snake) if matched_snakes: - if len(matched_snakes) > 1: - random.shuffle(matched_snakes) - trimmed_snakes = [] - for snake in matched_snakes[0:9]: - trimmed_snakes.append(capwords(f'{snake}') + '\n') + trimmed_snakes = [] + random_matched_snakes = list(matched_snakes) + random.shuffle(random_matched_snakes) + + for snake in random_matched_snakes[0:9]: + trimmed_snakes.append(capwords(f'{snake}') + '\n') + if page_id == "-1" and snake_name.lower() in self.snake_cache: + snake_dict = {"name": f"Cannot find a page for {snake_name}! Suggestions from query:", + "snake_text": ''.join(trimmed_snakes), + "snake_image": snake_image} + return snake_dict + + if len(matched_snakes) > 1: trimmed_snakes = sorted(trimmed_snakes) print(f"Trimmed: {trimmed_snakes}") @@ -185,10 +187,10 @@ async def get_snek(self, name: str = None) -> Dict[str, Any]: else: snake = matched_snakes[0] print(snake) - snake_dict = {"name": snake_name, - "snake_text": '', - "snake_image": snake_image} - return await self.get_snek(snake) + # snake_dict = {"name": snake_name, + # "snake_text": "This snake doesn't appear to have a page.", + # "snake_image": snake_image} + return self.get_snek(snake) snake_dict = {"name": snake_name, From dac90ddd264b090238e2c659ce57d69bb80af83a Mon Sep 17 00:00:00 2001 From: biskette Date: Sat, 24 Mar 2018 17:19:33 +0000 Subject: [PATCH 32/47] Cleaned up and tested get_snek function --- bot/cogs/snakes.py | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/bot/cogs/snakes.py b/bot/cogs/snakes.py index 5a11c0ef..d3c83e6c 100644 --- a/bot/cogs/snakes.py +++ b/bot/cogs/snakes.py @@ -170,15 +170,15 @@ async def get_snek(self, name: str = None) -> Dict[str, Any]: for snake in random_matched_snakes[0:9]: trimmed_snakes.append(capwords(f'{snake}') + '\n') + trimmed_snakes = sorted(trimmed_snakes) + if page_id == "-1" and snake_name.lower() in self.snake_cache: - snake_dict = {"name": f"Cannot find a page for {snake_name}! Suggestions from query:", + snake_dict = {"name": f"Found {capwords(snake_name)} but no page! Suggestions:", "snake_text": ''.join(trimmed_snakes), "snake_image": snake_image} return snake_dict if len(matched_snakes) > 1: - trimmed_snakes = sorted(trimmed_snakes) - print(f"Trimmed: {trimmed_snakes}") snake_dict = {"name": "No snake found, here are some suggestions:", "snake_text": ''.join(trimmed_snakes), @@ -186,11 +186,7 @@ async def get_snek(self, name: str = None) -> Dict[str, Any]: return snake_dict else: snake = matched_snakes[0] - print(snake) - # snake_dict = {"name": snake_name, - # "snake_text": "This snake doesn't appear to have a page.", - # "snake_image": snake_image} - return self.get_snek(snake) + return await self.get_snek(snake) snake_dict = {"name": snake_name, @@ -215,7 +211,7 @@ async def get_snek(self, name: str = None) -> Dict[str, Any]: snake_image = image_url_json['query']['pages'][snake_image_id]['imageinfo'][0]['url'] snake_text = text_json['query']['pages'][page_id]['extract'] - snake_dict = {"name": snake_name, "snake_text": snake_text, "snake_image": snake_image} + snake_dict = {"name": capwords(snake_name), "snake_text": snake_text, "snake_image": snake_image} return snake_dict @command() From d30730968d0f63ffe5d78ff5b7b00ab0500b619e Mon Sep 17 00:00:00 2001 From: biskette Date: Sat, 24 Mar 2018 17:49:29 +0000 Subject: [PATCH 33/47] Fixed the flakey flake8. Doing comments. --- bot/cogs/snakes.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/bot/cogs/snakes.py b/bot/cogs/snakes.py index f123cacf..f6a2f56d 100644 --- a/bot/cogs/snakes.py +++ b/bot/cogs/snakes.py @@ -121,8 +121,8 @@ async def get_snake_list(self): async def get_snek(self, name: str = None) -> Dict[str, Any]: """ On user input it validates vs the snake cache and also that the page exists - If the page doesn't exist it sends a ssssassy message - If the page does exist it passes off the params to get_wiki_json + If the input exists in the snake cache but the page does not exist + We call the function again using the previous search terms :param name: Just some sort of user input, preferably a snake. :return: """ @@ -188,7 +188,6 @@ async def get_snek(self, name: str = None) -> Dict[str, Any]: snake = matched_snakes[0] return await self.get_snek(snake) - snake_dict = {"name": snake_name, "snake_text": "You call that a snake?\n" "THIS is a snake!", From c7912d0fdb89b4846f07e6198fefc4cdcb3782ce Mon Sep 17 00:00:00 2001 From: biskette Date: Sat, 24 Mar 2018 17:58:54 +0000 Subject: [PATCH 34/47] Wrote a doc string for get_snek --- bot/cogs/snakes.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/bot/cogs/snakes.py b/bot/cogs/snakes.py index f6a2f56d..07a2699f 100644 --- a/bot/cogs/snakes.py +++ b/bot/cogs/snakes.py @@ -120,10 +120,12 @@ async def get_snake_list(self): async def get_snek(self, name: str = None) -> Dict[str, Any]: """ - On user input it validates vs the snake cache and also that the page exists - If the input exists in the snake cache but the page does not exist - We call the function again using the previous search terms - :param name: Just some sort of user input, preferably a snake. + On user input it checks vs the snake cache and that page exists + If there is a hit on the cache and on the page it grabs the info + If the cache is hit but the page doesn't exist it suggests based off input + If the input only hits one item in cache it returns the info for that cache hit + If you write something stupid it'll throw up a knifey spoony error + :param name: Just some sort of user input, preferably a snake :return: """ await self.setup # Pauses here until the "setup" task has completed From 2b9752a564735c657d50067c73c0559868673f33 Mon Sep 17 00:00:00 2001 From: biskette Date: Sat, 24 Mar 2018 18:12:43 +0000 Subject: [PATCH 35/47] Wrote a bunch of comments explaining the Snake Finder General --- bot/cogs/snakes.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/bot/cogs/snakes.py b/bot/cogs/snakes.py index 07a2699f..202177ac 100644 --- a/bot/cogs/snakes.py +++ b/bot/cogs/snakes.py @@ -153,17 +153,18 @@ async def get_snek(self, name: str = None) -> Dict[str, Any]: image_name_json = await self.get_wiki_json(image_name_params) snake_image = DEFAULT_SNAKE - # Here we check if *ANY* of the values a user has submitted - # match *ANY* of the values in snake_cache - page_id = list(text_json['query']['pages'].keys())[0] + + # Check that page exists or that snake is in cache if page_id == "-1" or snake_name.lower() not in self.snake_cache: + # Build a list of matching snakes matched_snakes = [] for snake in self.snake_cache: if any(s in snake for s in snake_name.lower().split()): matched_snakes.append(snake) + # On cache hit start building a sorted, trimmed, random list from hits if matched_snakes: trimmed_snakes = [] random_matched_snakes = list(matched_snakes) @@ -174,18 +175,23 @@ async def get_snek(self, name: str = None) -> Dict[str, Any]: trimmed_snakes = sorted(trimmed_snakes) + # If page doesn't exist and snake DOES exist in cache return error and suggestions + # E.g. "corn" wont hit any snakes directly, but exists inside more than 1 result if page_id == "-1" and snake_name.lower() in self.snake_cache: snake_dict = {"name": f"Found {capwords(snake_name)} but no page! Suggestions:", "snake_text": ''.join(trimmed_snakes), "snake_image": snake_image} return snake_dict + # If more than 1 indirect cache hit then offer suggestions based off the hits if len(matched_snakes) > 1: snake_dict = {"name": "No snake found, here are some suggestions:", "snake_text": ''.join(trimmed_snakes), "snake_image": snake_image} return snake_dict + # If only 1 cache hit then re-run get_snek with the full term from cache + # A good example of this in action is "bot.get rosy" else: snake = matched_snakes[0] return await self.get_snek(snake) From 9f8b102da6c53ab8d677a60b46aa0d3ae8d506d9 Mon Sep 17 00:00:00 2001 From: runew0lf Date: Sat, 24 Mar 2018 21:48:01 +0000 Subject: [PATCH 36/47] Commented code to make it more legible to bisk --- bot/cogs/snakes.py | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/bot/cogs/snakes.py b/bot/cogs/snakes.py index f123cacf..2ccbea3b 100644 --- a/bot/cogs/snakes.py +++ b/bot/cogs/snakes.py @@ -245,6 +245,16 @@ async def get(self, ctx: Context, name: str = None): # Any additional commands can be placed here. Be creative, but keep it to a reasonable amount! @command(name="antidote") async def build_board(self, ctx: Context): + """ + Antidote - Can you create the antivenom before the patient dies! + Rules: You have 4 ingredients for each antidote, you only have 10 attempts + Once you synthesize the antidote, you will be presented with 4 markers + Tick: This means you have a CORRECT ingredient in the CORRECT position + Circle: This means you have a CORRECT ingredient in the WRONG position + Cross: This means you have a WRONG ingredient in the WRONG position + Info: The game automatically ends after 5 minutes inactivity. + You should only use each ingredient once. + """ antidote_tries = 0 antidote_guess_count = 0 antidote_guess_list = [] @@ -253,14 +263,19 @@ async def build_board(self, ctx: Context): page_guess_list = [] page_result_list = [] win = False + + # initialize variables + antidote_embed = Embed(color=ctx.me.color, title="Antidote") antidote_embed.set_author(name=ctx.author.name, icon_url=ctx.author.avatar_url) + # Generate answer antidote_answer = list(ANTIDOTE_EMOJI) # duplicate list, not reference it random.shuffle(antidote_answer) antidote_answer.pop() log.info(antidote_answer) - # begin board building + + # begin initial board building for i in range(0, 10): page_guess_list.append(f"{HOLE_EMOJI} {HOLE_EMOJI} {HOLE_EMOJI} {HOLE_EMOJI}") page_result_list.append(f"{CROSS_EMOJI} {CROSS_EMOJI} {CROSS_EMOJI} {CROSS_EMOJI}") @@ -269,8 +284,10 @@ async def build_board(self, ctx: Context): f"{page_result_list[i]}") board.append(EMPTY) antidote_embed.add_field(name="10 guesses remaining", value="\n".join(board)) + # Display board board_id = await ctx.send(embed=antidote_embed) + # add our player reactions for emoji in ANTIDOTE_EMOJI: await board_id.add_reaction(emoji) @@ -324,6 +341,9 @@ def event_check(reaction_: Reaction, user_: Member): guess_result.sort() page_result_list[antidote_tries] = " ".join(guess_result) log.info(f"Guess Result: {' '.join(guess_result)}") + + # Rebuild the board + board = [] for i in range(0, 10): board.append(f"`{i+1:02d}` " @@ -344,6 +364,7 @@ def event_check(reaction_: Reaction, user_: Member): antidote_embed.add_field(name=f"{10 - antidote_tries} " f"guesses remaining", value="\n".join(board)) + # Redisplay the board await board_id.edit(embed=antidote_embed) if win is True: @@ -355,6 +376,7 @@ def event_check(reaction_: Reaction, user_: Member): log.debug("Timed out waiting for a reaction") break # We're done, no reactions for the last 5 minutes + # Winning / Ending Screen if win is True: await ctx.send(f"You have created the snake antidote! with {10 - antidote_tries} tries remaining") await board_id.clear_reactions() From 9b770ea497a8b300e44b412713f7932c62b00cae Mon Sep 17 00:00:00 2001 From: runew0lf Date: Sun, 25 Mar 2018 09:09:47 +0100 Subject: [PATCH 37/47] Finished Game and added Win / Lose Messages --- bot/cogs/snakes.py | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/bot/cogs/snakes.py b/bot/cogs/snakes.py index b4531ce6..5a09d7b1 100644 --- a/bot/cogs/snakes.py +++ b/bot/cogs/snakes.py @@ -305,7 +305,6 @@ def event_check(reaction_: Reaction, user_: Member): """ no_restrictions = ( - # Pagination is not restricted user_.id == ctx.author.id ) @@ -385,11 +384,21 @@ def event_check(reaction_: Reaction, user_: Member): # Winning / Ending Screen if win is True: - await ctx.send(f"You have created the snake antidote! with {10 - antidote_tries} tries remaining") - await board_id.clear_reactions() + antidote_embed = Embed(color=ctx.me.color, title="Antidote") + antidote_embed.set_author(name=ctx.author.name, icon_url=ctx.author.avatar_url) + antidote_embed.set_image(url="https://i.makeagif.com/media/7-12-2015/Cj1pts.gif") + antidote_embed.add_field(name=EMPTY, + value=f"You have created the snake antidote!\n" + f"You had {10 - antidote_tries} tries remaining") + await board_id.edit(embed=antidote_embed) else: - await ctx.send(f"Sorry you didnt make the antidote in time, the formula was {' '.join(antidote_answer)}") - await board_id.clear_reactions() + antidote_embed = Embed(color=ctx.me.color, title="Antidote") + antidote_embed.set_author(name=ctx.author.name, icon_url=ctx.author.avatar_url) + antidote_embed.set_image(url="https://media.giphy.com/media/ceeN6U57leAhi/giphy.gif") + antidote_embed.add_field(name=EMPTY, + value=f"Sorry you didnt make the antidote in time.\n" + f"The formula was {' '.join(antidote_answer)}") + await board_id.edit(embed=antidote_embed) log.debug("Ending pagination and removing all reactions...") await board_id.clear_reactions() From d3300d1e73b6930df08c3b072af745f9786dc63a Mon Sep 17 00:00:00 2001 From: runew0lf Date: Sun, 25 Mar 2018 12:52:53 +0100 Subject: [PATCH 38/47] Fixed some issues that lemon highlighted --- bot/cogs/snakes.py | 149 ++++++++++++++++++++++----------------------- 1 file changed, 74 insertions(+), 75 deletions(-) diff --git a/bot/cogs/snakes.py b/bot/cogs/snakes.py index 5a09d7b1..95eb60ec 100644 --- a/bot/cogs/snakes.py +++ b/bot/cogs/snakes.py @@ -29,9 +29,9 @@ EMPTY = u'\u200b' # Results -TICK_EMOJI = "\u2705" # Correct Peg, Correct Hole +TICK_EMOJI = "\u2705" # Correct peg, correct hole CROSS_EMOJI = "\u274C" # Wrong -BLANK_EMOJI = "\u26AA" # Correct Peg Wrong Hole +BLANK_EMOJI = "\u26AA" # Correct peg, wrong hle # Holes HOLE_EMOJI = "\u2B1C" @@ -39,6 +39,9 @@ ANTIDOTE_EMOJI = [FIRST_EMOJI, SECOND_EMOJI, THIRD_EMOJI, FOURTH_EMOJI, FIFTH_EMOJI] +def to_lower(argument): + return argument.lower() + class Snakes: """ Snake-related commands @@ -222,7 +225,7 @@ async def get_snek(self, name: str = None) -> Dict[str, Any]: return snake_dict @command() - async def get(self, ctx: Context, name: str = None): + async def get(self, ctx: Context, name: to_lower = None): """ Calls get_snek and puts results inside an embed for sending If it matches some special checks, alternative action is taken @@ -253,7 +256,7 @@ async def get(self, ctx: Context, name: str = None): @command(name="antidote") async def build_board(self, ctx: Context): """ - Antidote - Can you create the antivenom before the patient dies! + Antidote - Can you create the antivenom before the patient dies? Rules: You have 4 ingredients for each antidote, you only have 10 attempts Once you synthesize the antidote, you will be presented with 4 markers Tick: This means you have a CORRECT ingredient in the CORRECT position @@ -262,6 +265,13 @@ async def build_board(self, ctx: Context): Info: The game automatically ends after 5 minutes inactivity. You should only use each ingredient once. """ + + # Check to see if the bot can remove reactions + if not ctx.channel.permissions_for(ctx.guild.me).manage_messages: + await ctx.send("Unable to start game as I dont have manage_messages permissions") + return + + # initialize variables antidote_tries = 0 antidote_guess_count = 0 antidote_guess_list = [] @@ -271,8 +281,6 @@ async def build_board(self, ctx: Context): page_result_list = [] win = False - # initialize variables - antidote_embed = Embed(color=ctx.me.color, title="Antidote") antidote_embed.set_author(name=ctx.author.name, icon_url=ctx.author.avatar_url) @@ -291,9 +299,7 @@ async def build_board(self, ctx: Context): f"{page_result_list[i]}") board.append(EMPTY) antidote_embed.add_field(name="10 guesses remaining", value="\n".join(board)) - - # Display board - board_id = await ctx.send(embed=antidote_embed) + board_id = await ctx.send(embed=antidote_embed) # Display board # add our player reactions for emoji in ANTIDOTE_EMOJI: @@ -303,85 +309,78 @@ def event_check(reaction_: Reaction, user_: Member): """ Make sure that this reaction is what we want to operate on """ - - no_restrictions = ( - user_.id == ctx.author.id - ) - return ( # Conditions for a successful pagination: all(( - # Reaction is on this message - reaction_.message.id == board_id.id, - # Reaction is one of the pagination emotes - reaction_.emoji in ANTIDOTE_EMOJI, - # Reaction was not made by the Bot - user_.id != self.bot.user.id, - # There were no restrictions - no_restrictions + reaction_.message.id == board_id.id, # Reaction is on this message + reaction_.emoji in ANTIDOTE_EMOJI, # Reaction is one of the pagination emotes + user_.id != self.bot.user.id, # Reaction was not made by the Bot + user_.id == ctx.author.id # There were no restrictions )) ) + # Begin main game loop while True: try: reaction, user = await ctx.bot.wait_for("reaction_add", timeout=300, check=event_check) - if antidote_tries < 10: - if antidote_guess_count < 4: - if reaction.emoji in ANTIDOTE_EMOJI: - antidote_guess_list.append(reaction.emoji) - antidote_guess_count += 1 - - if antidote_guess_count == 4: # GUESSES COMPLETE - antidote_guess_count = 0 - page_guess_list[antidote_tries] = " ".join(antidote_guess_list) - log.info(f"Guess: {' '.join(antidote_guess_list)}") - - # Now Check Guess - for i in range(0, len(antidote_answer)): - if antidote_guess_list[i] == antidote_answer[i]: - guess_result.append(TICK_EMOJI) - elif antidote_guess_list[i] in antidote_answer: - guess_result.append(BLANK_EMOJI) - else: - guess_result.append(CROSS_EMOJI) - guess_result.sort() - page_result_list[antidote_tries] = " ".join(guess_result) - log.info(f"Guess Result: {' '.join(guess_result)}") - - # Rebuild the board - - board = [] - for i in range(0, 10): - board.append(f"`{i+1:02d}` " - f"{page_guess_list[i]} - " - f"{page_result_list[i]}") - board.append(EMPTY) - for emoji in antidote_guess_list: - await board_id.remove_reaction(emoji, user) - - if antidote_guess_list == antidote_answer: - win = True - - antidote_tries += 1 - guess_result = [] - antidote_guess_list = [] - - antidote_embed.clear_fields() - antidote_embed.add_field(name=f"{10 - antidote_tries} " - f"guesses remaining", - value="\n".join(board)) - # Redisplay the board - await board_id.edit(embed=antidote_embed) - - if win is True: - break - if antidote_tries == 10: - break - except asyncio.TimeoutError: log.debug("Timed out waiting for a reaction") break # We're done, no reactions for the last 5 minutes + if antidote_tries < 10: + if antidote_guess_count < 4: + if reaction.emoji in ANTIDOTE_EMOJI: + antidote_guess_list.append(reaction.emoji) + antidote_guess_count += 1 + + if antidote_guess_count == 4: # Guesses complete + antidote_guess_count = 0 + page_guess_list[antidote_tries] = " ".join(antidote_guess_list) + log.info(f"Guess: {' '.join(antidote_guess_list)}") + + # Now check guess + for i in range(0, len(antidote_answer)): + if antidote_guess_list[i] == antidote_answer[i]: + guess_result.append(TICK_EMOJI) + elif antidote_guess_list[i] in antidote_answer: + guess_result.append(BLANK_EMOJI) + else: + guess_result.append(CROSS_EMOJI) + guess_result.sort() + page_result_list[antidote_tries] = " ".join(guess_result) + log.info(f"Guess Result: {' '.join(guess_result)}") + + # Rebuild the board + board = [] + for i in range(0, 10): + board.append(f"`{i+1:02d}` " + f"{page_guess_list[i]} - " + f"{page_result_list[i]}") + board.append(EMPTY) + + # Remove Reactions + for emoji in antidote_guess_list: + await board_id.remove_reaction(emoji, user) + + if antidote_guess_list == antidote_answer: + win = True + + antidote_tries += 1 + guess_result = [] + antidote_guess_list = [] + + antidote_embed.clear_fields() + antidote_embed.add_field(name=f"{10 - antidote_tries} " + f"guesses remaining", + value="\n".join(board)) + # Redisplay the board + await board_id.edit(embed=antidote_embed) + + if win is True: + break + if antidote_tries == 10: + break + # Winning / Ending Screen if win is True: antidote_embed = Embed(color=ctx.me.color, title="Antidote") From 644f51ffabc8a7d75516deca12e000d96e0a2442 Mon Sep 17 00:00:00 2001 From: runew0lf Date: Sun, 25 Mar 2018 12:56:35 +0100 Subject: [PATCH 39/47] Linted code --- bot/cogs/snakes.py | 1 + 1 file changed, 1 insertion(+) diff --git a/bot/cogs/snakes.py b/bot/cogs/snakes.py index 95eb60ec..3661d49d 100644 --- a/bot/cogs/snakes.py +++ b/bot/cogs/snakes.py @@ -42,6 +42,7 @@ def to_lower(argument): return argument.lower() + class Snakes: """ Snake-related commands From 285ec33a10536ce21c1c56304fe1710bb1f7860a Mon Sep 17 00:00:00 2001 From: runew0lf Date: Sun, 25 Mar 2018 13:15:12 +0100 Subject: [PATCH 40/47] Linted code and finished basic game --- Pipfile | 1 + Pipfile.lock | 31 ++++++++++++++++++++++++++++++- bot/cogs/snakes.py | 4 +--- 3 files changed, 32 insertions(+), 4 deletions(-) diff --git a/Pipfile b/Pipfile index 096fb9b3..40d4c270 100644 --- a/Pipfile +++ b/Pipfile @@ -8,6 +8,7 @@ name = "pypi" aiodns = "*" aiohttp = "<2.3.0,>=2.0.0" websockets = ">=4.0,<5.0" +"flake8" = "*" [dev-packages] "flake8" = "*" diff --git a/Pipfile.lock b/Pipfile.lock index 4e5214bb..11dda82d 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "d797e580ddcddc99bf058109ab0306ad584c2902752a3d4076ba713fdc580fb7" + "sha256": "55aa606ecc2d1defa097476a608b21c724d068640b91b8148e688a66606a3569" }, "pipfile-spec": 6, "requires": { @@ -60,6 +60,14 @@ ], "version": "==3.0.4" }, + "flake8": { + "hashes": [ + "sha256:7253265f7abd8b313e3892944044a365e3f4ac3fcdcfb4298f55ee9ddf188ba0", + "sha256:c7841163e2b576d435799169b78703ad6ac1bbb0f199994fc05f700b2a90ea37" + ], + "index": "pypi", + "version": "==3.5.0" + }, "idna": { "hashes": [ "sha256:2c6a5de3089009e3da7c5dde64a141dbc8551d5b7f6cf4ed7c2568d0cc520a8f", @@ -67,6 +75,13 @@ ], "version": "==2.6" }, + "mccabe": { + "hashes": [ + "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42", + "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f" + ], + "version": "==0.6.1" + }, "multidict": { "hashes": [ "sha256:0462372fc74e4c061335118a4a5992b9a618d6c584b028ef03cf3e9b88a960e2", @@ -120,6 +135,20 @@ ], "version": "==2.3.0" }, + "pycodestyle": { + "hashes": [ + "sha256:682256a5b318149ca0d2a9185d365d8864a768a28db66a84a2ea946bcc426766", + "sha256:6c4245ade1edfad79c3446fadfc96b0de2759662dc29d07d80a6f27ad1ca6ba9" + ], + "version": "==2.3.1" + }, + "pyflakes": { + "hashes": [ + "sha256:08bd6a50edf8cffa9fa09a463063c425ecaaf10d1eb0335a7e8b1401aef89e6f", + "sha256:8d616a382f243dbf19b54743f280b80198be0bca3a5396f1d2e1fca6223e8805" + ], + "version": "==1.6.0" + }, "websockets": { "hashes": [ "sha256:0c31bc832d529dc7583d324eb6c836a4f362032a1902723c112cf57883488d8c", diff --git a/bot/cogs/snakes.py b/bot/cogs/snakes.py index 3661d49d..59024ee6 100644 --- a/bot/cogs/snakes.py +++ b/bot/cogs/snakes.py @@ -7,8 +7,6 @@ import aiohttp -import async_timeout - from discord import Embed, Member, Reaction from discord.ext.commands import AutoShardedBot, Context, command @@ -70,7 +68,7 @@ async def get_wiki_json(self, params): :return: """ async with aiohttp.ClientSession(headers={'User-Agent': 'DevBot v.10'}) as cs: - async with async_timeout.timeout(20): + async with aiohttp.Timeout(20): async with cs.get("https://en.wikipedia.org/w/api.php", params=params) as r: log.info(f"{r.url}: {r.status}: {r.reason}") return await r.json() From 1744c078c518b214e4ae68219c6c59dad9a0fe7f Mon Sep 17 00:00:00 2001 From: runew0lf Date: Sun, 25 Mar 2018 13:34:21 +0100 Subject: [PATCH 41/47] Fixed while loop to include win / tries --- bot/cogs/snakes.py | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/bot/cogs/snakes.py b/bot/cogs/snakes.py index 59024ee6..0400fd86 100644 --- a/bot/cogs/snakes.py +++ b/bot/cogs/snakes.py @@ -319,7 +319,7 @@ def event_check(reaction_: Reaction, user_: Member): ) # Begin main game loop - while True: + while not win and antidote_tries < 10: try: reaction, user = await ctx.bot.wait_for("reaction_add", timeout=300, check=event_check) except asyncio.TimeoutError: @@ -375,11 +375,6 @@ def event_check(reaction_: Reaction, user_: Member): # Redisplay the board await board_id.edit(embed=antidote_embed) - if win is True: - break - if antidote_tries == 10: - break - # Winning / Ending Screen if win is True: antidote_embed = Embed(color=ctx.me.color, title="Antidote") From 128234cb7e63a86403ea17dbcb2a45478fd32026 Mon Sep 17 00:00:00 2001 From: biskette Date: Sun, 25 Mar 2018 13:44:10 +0100 Subject: [PATCH 42/47] Wrote a bunch of comments explaining the Snake Finder General --- bot/cogs/snakes.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/bot/cogs/snakes.py b/bot/cogs/snakes.py index 0400fd86..44ff8e8e 100644 --- a/bot/cogs/snakes.py +++ b/bot/cogs/snakes.py @@ -158,12 +158,12 @@ async def get_snek(self, name: str = None) -> Dict[str, Any]: page_id = list(text_json['query']['pages'].keys())[0] # Check that page exists or that snake is in cache - if page_id == "-1" or snake_name.lower() not in self.snake_cache: + if page_id == "-1" or snake_name not in self.snake_cache: # Build a list of matching snakes matched_snakes = [] for snake in self.snake_cache: - if any(s in snake for s in snake_name.lower().split()): + if any(s in snake for s in snake_name.split()): matched_snakes.append(snake) # On cache hit start building a sorted, trimmed, random list from hits @@ -179,7 +179,7 @@ async def get_snek(self, name: str = None) -> Dict[str, Any]: # If page doesn't exist and snake DOES exist in cache return error and suggestions # E.g. "corn" wont hit any snakes directly, but exists inside more than 1 result - if page_id == "-1" and snake_name.lower() in self.snake_cache: + if page_id == "-1" and snake_name in self.snake_cache: snake_dict = {"name": f"Found {capwords(snake_name)} but no page! Suggestions:", "snake_text": ''.join(trimmed_snakes), "snake_image": snake_image} From af7b064c5c802fe78d26ab074b7ba3240e8fef1a Mon Sep 17 00:00:00 2001 From: runew0lf Date: Sun, 25 Mar 2018 13:46:46 +0100 Subject: [PATCH 43/47] Remove cache --- bot/cogs/snakes.py | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/bot/cogs/snakes.py b/bot/cogs/snakes.py index 44ff8e8e..f09d5103 100644 --- a/bot/cogs/snakes.py +++ b/bot/cogs/snakes.py @@ -51,15 +51,7 @@ def __init__(self, bot: AutoShardedBot): self.snake_cache = [] # This caches the very expensive snake list operation on load - self.setup = bot.loop.create_task(self.cache_snake_list()) - - async def cache_snake_list(self): - """ - Calls get_snake_list, which is *very* hungry, and caches it - :return: - """ - self.snake_cache = await self.get_snake_list() - return + self.setup = bot.loop.create_task(self.get_snake_list()) async def get_wiki_json(self, params): """ From 4b53d9be09c4ccee27a276d2d4ab368e320dd4cc Mon Sep 17 00:00:00 2001 From: runew0lf Date: Sun, 25 Mar 2018 14:26:14 +0100 Subject: [PATCH 44/47] Re-added cache because i broke something --- bot/cogs/snakes.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/bot/cogs/snakes.py b/bot/cogs/snakes.py index f09d5103..44ff8e8e 100644 --- a/bot/cogs/snakes.py +++ b/bot/cogs/snakes.py @@ -51,7 +51,15 @@ def __init__(self, bot: AutoShardedBot): self.snake_cache = [] # This caches the very expensive snake list operation on load - self.setup = bot.loop.create_task(self.get_snake_list()) + self.setup = bot.loop.create_task(self.cache_snake_list()) + + async def cache_snake_list(self): + """ + Calls get_snake_list, which is *very* hungry, and caches it + :return: + """ + self.snake_cache = await self.get_snake_list() + return async def get_wiki_json(self, params): """ From 29ad19db09b796aec94061a1cb57a2104b4812de Mon Sep 17 00:00:00 2001 From: biskette Date: Sun, 25 Mar 2018 14:55:53 +0100 Subject: [PATCH 45/47] Wrote a bunch of comments explaining the Snake Finder General --- bot/cogs/snakes.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/bot/cogs/snakes.py b/bot/cogs/snakes.py index 44ff8e8e..ffad0fa7 100644 --- a/bot/cogs/snakes.py +++ b/bot/cogs/snakes.py @@ -58,6 +58,8 @@ async def cache_snake_list(self): Calls get_snake_list, which is *very* hungry, and caches it :return: """ + # This could be done more efficiently by combining it with get_snake_list + # However this is will do for now self.snake_cache = await self.get_snake_list() return @@ -122,11 +124,11 @@ async def get_snake_list(self): async def get_snek(self, name: str = None) -> Dict[str, Any]: """ - On user input it checks vs the snake cache and that page exists - If there is a hit on the cache and on the page it grabs the info - If the cache is hit but the page doesn't exist it suggests based off input - If the input only hits one item in cache it returns the info for that cache hit - If you write something stupid it'll throw up a knifey spoony error + Builds a Wiki API query and then checks if the result contains a page + If the cache is hit and the page exists then it pulls info + If the cache is hit and the page does not exist, offer suggestions + If the cache is hit once it returns the info for that hit + If you write something stupid it'll throw a snakey-wakey error :param name: Just some sort of user input, preferably a snake :return: """ From e1c5b036c2476b6022d73e313846dd8f6fc91b3a Mon Sep 17 00:00:00 2001 From: biskette Date: Sun, 25 Mar 2018 14:59:11 +0100 Subject: [PATCH 46/47] Tidying up doc strings and comments --- bot/cogs/snakes.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/bot/cogs/snakes.py b/bot/cogs/snakes.py index ffad0fa7..4c32bd8d 100644 --- a/bot/cogs/snakes.py +++ b/bot/cogs/snakes.py @@ -272,7 +272,7 @@ async def build_board(self, ctx: Context): await ctx.send("Unable to start game as I dont have manage_messages permissions") return - # initialize variables + # Initialize variables antidote_tries = 0 antidote_guess_count = 0 antidote_guess_list = [] @@ -286,12 +286,12 @@ async def build_board(self, ctx: Context): antidote_embed.set_author(name=ctx.author.name, icon_url=ctx.author.avatar_url) # Generate answer - antidote_answer = list(ANTIDOTE_EMOJI) # duplicate list, not reference it + antidote_answer = list(ANTIDOTE_EMOJI) # Duplicate list, not reference it random.shuffle(antidote_answer) antidote_answer.pop() log.info(antidote_answer) - # begin initial board building + # Begin initial board building for i in range(0, 10): page_guess_list.append(f"{HOLE_EMOJI} {HOLE_EMOJI} {HOLE_EMOJI} {HOLE_EMOJI}") page_result_list.append(f"{CROSS_EMOJI} {CROSS_EMOJI} {CROSS_EMOJI} {CROSS_EMOJI}") @@ -302,7 +302,7 @@ async def build_board(self, ctx: Context): antidote_embed.add_field(name="10 guesses remaining", value="\n".join(board)) board_id = await ctx.send(embed=antidote_embed) # Display board - # add our player reactions + # Add our player reactions for emoji in ANTIDOTE_EMOJI: await board_id.add_reaction(emoji) @@ -320,7 +320,7 @@ def event_check(reaction_: Reaction, user_: Member): )) ) - # Begin main game loop + # Begin main game loop while not win and antidote_tries < 10: try: reaction, user = await ctx.bot.wait_for("reaction_add", timeout=300, check=event_check) From cb26052d26795dc79a6a3cd80e70d02921b0e3a7 Mon Sep 17 00:00:00 2001 From: biskette Date: Mon, 26 Mar 2018 00:49:54 +0100 Subject: [PATCH 47/47] Changed win screen to look tidy + include solution --- bot/cogs/snakes.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/bot/cogs/snakes.py b/bot/cogs/snakes.py index 4c32bd8d..da85f06c 100644 --- a/bot/cogs/snakes.py +++ b/bot/cogs/snakes.py @@ -382,9 +382,9 @@ def event_check(reaction_: Reaction, user_: Member): antidote_embed = Embed(color=ctx.me.color, title="Antidote") antidote_embed.set_author(name=ctx.author.name, icon_url=ctx.author.avatar_url) antidote_embed.set_image(url="https://i.makeagif.com/media/7-12-2015/Cj1pts.gif") - antidote_embed.add_field(name=EMPTY, - value=f"You have created the snake antidote!\n" - f"You had {10 - antidote_tries} tries remaining") + antidote_embed.add_field(name=f"You have created the snake antidote!", + value=f"The solution was: {' '.join(antidote_answer)}\n" + f"You had {10 - antidote_tries} tries remaining.") await board_id.edit(embed=antidote_embed) else: antidote_embed = Embed(color=ctx.me.color, title="Antidote")