1
0
Fork 0
mirror of synced 2024-05-02 19:52:25 +12:00

Update shiritori to work with kanji - only allow JP

This commit is contained in:
Dan Hess 2021-03-25 16:03:58 -08:00
parent cdccc2b85e
commit 4275f004ac
2 changed files with 68 additions and 23 deletions

View file

@ -1,6 +1,7 @@
from discord.ext import commands from discord.ext import commands
import collections import collections
import utils
class Games(commands.Cog): class Games(commands.Cog):
@ -8,9 +9,9 @@ class Games(commands.Cog):
self.running_games = collections.defaultdict(dict) self.running_games = collections.defaultdict(dict)
@commands.guild_only() @commands.guild_only()
# @utils.can_run(send_messages=True)
@commands.is_owner() @commands.is_owner()
@commands.command(aliases=["word_chain", "しりとり"]) @commands.command(aliases=["word_chain", "しりとり", "シリトリ"])
@commands.max_concurrency(1, per=commands.BucketType.channel)
async def shiritori(self, ctx, *, start_word): async def shiritori(self, ctx, *, start_word):
""" """
Starts a game of Shiritori, in which the last letter of the last word given Starts a game of Shiritori, in which the last letter of the last word given
@ -21,13 +22,17 @@ class Games(commands.Cog):
The kana cannot be used, as no word in Japanese starts with this The kana cannot be used, as no word in Japanese starts with this
The word used cannot be a previously given word The word used cannot be a previously given word
""" """
game = self.running_games["shiritori"].get(ctx.channel.id)
def grab_letter(word, last=True): def grab_letter(readings, last=True):
iterator = reversed(word) if last else iter(word) readings = [reversed(word) if last else iter(word) for word in readings]
for char in iterator: letters = []
if char.isalpha():
return char for reading in readings:
for char in reading:
if char.isalpha():
letters.append(char)
def check(message): def check(message):
# Ensure it's in the same channel # Ensure it's in the same channel
@ -39,20 +44,31 @@ class Games(commands.Cog):
# The last person who gave a message cannot be the next one as well # The last person who gave a message cannot be the next one as well
elif last_author is not None and message.author == last_author: elif last_author is not None and message.author == last_author:
return False return False
# If no game is running then how did this even happen!?
elif game is None:
return False
# If the author is not a player
elif message.author not in game["players"]:
return False
# Otherwise we good
else: else:
return True return True
# Setup the info needed for the game # Setup the info needed for the game
message = ctx.message message = ctx.message
message.content = start_word message.content = start_word
last_letter = None last_letters = None
words_used = [] words_used = []
# Ensure only one game is happening at once # Ensure only one game is happening at once
game = self.running_games["shiritori"].get(ctx.channel.id) if game is not None:
if game: if ctx.author not in game["players"]:
return await ctx.send("Only one game per channel!") game["players"].append(ctx.author)
self.running_games["shiritori"][ctx.channel.id] = True await ctx.message.add_reaction("")
else:
await ctx.message.add_reaction("")
else:
self.running_games["shiritori"][ctx.channel.id] = {"players": []}
await ctx.send( await ctx.send(
f"Shiritori game started! First word is `{start_word}`, any responses after this" f"Shiritori game started! First word is `{start_word}`, any responses after this"
@ -60,32 +76,38 @@ class Games(commands.Cog):
) )
while True: while True:
# Grab the first letter of this new word and check it is_noun, readings = await utils.readings_for_word(message.content)
first_letter = grab_letter(message.content, last=False) # Only nouns can be used
# Include extra check for if this is the first word if not is_noun:
if words_used and first_letter != last_letter:
break break
# Grab the first letter of this new word and check it
first_letters = grab_letter(readings, last=False)
# Include extra check for if this is the first word
if words_used:
# Check if there's a match between first and last letters
if not any(char in first_letters for char in last_letters):
break
# Now set the "last" information, to start checking if it's correct # Now set the "last" information, to start checking if it's correct
last_word = message.content last_words = readings
last_letter = grab_letter(last_word) last_letters = grab_letter(last_words)
last_author = message.author last_author = message.author
# Extra check for the japanese version, ん cannot be used # Extra check for the japanese version, ん cannot be used
if last_letter in ("", ""): if any(char in last_letters for char in ("", "")):
break break
# Cannot reuuse words; though make sure this doesn't get caught on the very first usage # Cannot reuuse words; though make sure this doesn't get caught on the very first usage
if last_word in words_used and len(words_used) >= 1: if any(word in words_used for word in last_words) and len(words_used) >= 1:
break break
# If we're here, then the last letter used was valid # If we're here, then the last letter used was valid
words_used.append(last_word) words_used.extend(last_words)
await message.add_reaction("") await message.add_reaction("")
message = await ctx.bot.wait_for("message", check=check) message = await ctx.bot.wait_for("message", check=check)
# If we're here, game over, someone messed up # If we're here, game over, someone messed up
self.running_games["shiritori"][ctx.channel.id] = False self.running_games["shiritori"][ctx.channel.id] = False
await message.add_reaction("") await message.add_reaction("")
if last_letter in ("", ""): if any(char in last_letters for char in ("", "")):
await ctx.send("Wrong! ん cannot be used as the last kana!") await ctx.send("Wrong! ん cannot be used as the last kana!")
else: else:
await ctx.send(f"Wrong! {message.author.mention} is a loser!") await ctx.send(f"Wrong! {message.author.mention} is a loser!")

View file

@ -12,6 +12,29 @@ def channel_is_nsfw(channel):
return isinstance(channel, discord.DMChannel) or channel.is_nsfw() return isinstance(channel, discord.DMChannel) or channel.is_nsfw()
async def readings_for_word(word):
"""Returns a tuple, the first element representing if this word is a noun or not,
the second being all the readings for this word"""
data = await request(
"https://jisho.org/api/v1/search/words", payload={"keyword": word}
)
is_noun = False
readings = []
for piece in data["data"]:
# Jisho returns parts of words too, we don't want those for this use case
if piece["slug"] != word:
continue
# Provide the readings for this word
readings.extend([r["reading"] for r in piece["japanese"] if r["word"] == word])
for sense in piece["senses"]:
if "Noun" in sense["parts_of_speech"]:
is_noun = True
return is_noun, readings
async def download_image(url): async def download_image(url):
"""Returns a file-like object based on the URL provided""" """Returns a file-like object based on the URL provided"""
# Simply read the image, to get the bytes # Simply read the image, to get the bytes
@ -74,7 +97,7 @@ async def request(
# If an invalid attribute was requested, return None # If an invalid attribute was requested, return None
return None return None
# If an error was hit other than the one we want to catch, try again # If an error was hit other than the one we want to catch, try again
except: except Exception:
continue continue