converted hangman to buttons

This commit is contained in:
NikolajDanger
2021-08-19 13:12:15 +02:00
parent 3819e56cd6
commit 98988efa4b
8 changed files with 266 additions and 250 deletions

View File

@ -14,10 +14,16 @@ import math # Used by DrawHangman(), mainly for drawing circles
import random # Used to draw poorly
import requests # Used for getting the word in Hangman.start()
import discord # Used for discord.file and type hints
import os
from discord_slash.context import SlashContext # Used for typehints
from discord_slash.utils.manage_components import (create_button,
create_actionrow)
from discord_slash.model import ButtonStyle
from discord_slash.context import SlashContext, ComponentContext
# Used for typehints
from PIL import ImageDraw, Image, ImageFont # Used to draw the image
from gwendolyn.utils import encode_id
class Hangman():
"""
@ -43,10 +49,10 @@ class Hangman():
APIPARAMS: dict
The parameters to pass to every api call.
"""
self.__bot = bot
self.bot = bot
self.__draw = DrawHangman(bot)
self.__API_url = "https://api.wordnik.com/v4/words.json/randomWords?" # pylint: disable=invalid-name
api_key = self.__bot.credentials["wordnik_key"]
api_key = self.bot.credentials["wordnik_key"]
self.__APIPARAMS = { # pylint: disable=invalid-name
"hasDictionaryDef": True,
"minCorpusCount": 5000,
@ -68,70 +74,88 @@ class Hangman():
ctx: SlashContext
The context of the command.
"""
await self.__bot.defer(ctx)
channel = str(ctx.channel_id)
user = f"#{ctx.author.id}"
game = self.__bot.database["hangman games"].find_one({"_id": channel})
user_name = self.__bot.database_funcs.get_name(user)
started_game = False
await self.bot.defer(ctx)
if game is None:
word = "-"
while "-" in word or "." in word:
response = requests.get(self.__API_url, params=self.__APIPARAMS)
word = list(response.json()[0]["word"].upper())
word = "-"
while "-" in word or "." in word:
response = requests.get(self.__API_url, params=self.__APIPARAMS)
word = list(response.json()[0]["word"].upper())
self.__bot.log("Found the word \""+"".join(word)+"\"")
guessed = [False] * len(word)
game_id = datetime.datetime.now().strftime("%Y%m%d%H%M%S")
new_game = {
"_id": channel,
"player": user,
"guessed letters": [],
"word": word,
"game ID": game_id,
"misses": 0,
"guessed": guessed
}
self.__bot.database["hangman games"].insert_one(new_game)
self.bot.log("Found the word \""+"".join(word)+"\"")
guessed = [False] * len(word)
game_id = datetime.datetime.now().strftime("%Y%m%d%H%M%S")
remaining_letters = list(string.ascii_uppercase)
remaining_letters = list(string.ascii_uppercase)
self.__draw.draw_image(channel)
self.__draw.draw_image(game_id, 0, word, guessed, [])
log_message = "Game started"
send_message = f"{user_name} started game of hangman."
started_game = True
else:
log_message = "There was already a game going on"
send_message = self.__bot.long_strings["Hangman going on"]
send_message = f"{ctx.author.display_name} started a game of hangman."
self.__bot.log(log_message)
await ctx.send(send_message)
self.bot.log("Game started")
if started_game:
boards_path = "gwendolyn/resources/games/hangman_boards/"
file_path = f"{boards_path}hangman_board{channel}.png"
new_image = await ctx.channel.send(file=discord.File(file_path))
boards_path = "gwendolyn/resources/games/hangman_boards/"
file_path = f"{boards_path}hangman_board{game_id}.png"
image_message = await ctx.send(
send_message,
file=discord.File(file_path)
)
blank_message = await ctx.channel.send("_ _")
reaction_messages = {
new_image: remaining_letters[:15],
blank_message: remaining_letters[15:]
}
blank_message_one = await ctx.channel.send("_ _")
blank_message_two = await ctx.channel.send("_ _")
old_messages = f"{new_image.id}\n{blank_message.id}"
old_images_path = "gwendolyn/resources/games/old_images/"
buttons = []
for letter in remaining_letters:
custom_id = encode_id([
"hangman",
"guess",
str(ctx.author.id),
letter,
"".join(word),
"",
game_id,
str(image_message.id),
str(blank_message_one.id),
str(blank_message_two.id)
])
buttons.append(create_button(
style=ButtonStyle.blue,
label=letter,
custom_id=custom_id
))
with open(old_images_path+f"hangman{channel}", "w") as file_pointer:
file_pointer.write(old_messages)
custom_id = encode_id([
"hangman",
"end",
str(ctx.author.id),
game_id,
str(image_message.id),
str(blank_message_one.id),
str(blank_message_two.id)
])
buttons.append(create_button(
style=ButtonStyle.red,
label="End game",
custom_id=custom_id
))
for message, letters in reaction_messages.items():
for letter in letters:
emoji = chr(ord(letter)+127397)
await message.add_reaction(emoji)
action_row_lists = []
for i in range(((len(buttons)-1)//20)+1):
action_rows = []
available_buttons = buttons[(i*20):(min(len(buttons),i*20+20))]
for x in range(((len(available_buttons)-1)//4)+1):
row_buttons = available_buttons[
(x*4):(min(len(available_buttons),x*4+4))
]
action_rows.append(create_actionrow(*row_buttons))
action_row_lists.append(action_rows)
async def stop(self, ctx: SlashContext):
await blank_message_one.edit(components=action_row_lists[0])
await blank_message_two.edit(components=action_row_lists[1])
async def stop(self, ctx: ComponentContext, game_id: str,
*messages: list[str]):
"""
Stop the game of hangman.
@ -140,28 +164,19 @@ class Hangman():
ctx: SlashContext
The context of the command.
"""
channel = str(ctx.channel.id)
game = self.__bot.database["hangman games"].find_one({"_id": channel})
for msg_id in messages:
msg = await ctx.channel.fetch_message(msg_id)
await msg.delete()
if game is None:
await ctx.send("There's no game going on")
elif f"#{ctx.author.id}" != game["player"]:
await ctx.send("You can't end a game you're not in")
else:
self.__bot.database["hangman games"].delete_one({"_id": channel})
old_images_path = "gwendolyn/resources/games/old_images/"
self.bot.log("Deleting old messages")
with open(old_images_path+f"hangman{channel}", "r") as file_pointer:
messages = file_pointer.read().splitlines()
await ctx.channel.send("Hangman game stopped")
boards_path = "gwendolyn/resources/games/hangman_boards/"
file_path = f"{boards_path}hangman_board{game_id}.png"
os.remove(file_path)
for message in messages:
old_message = await ctx.channel.fetch_message(int(message))
self.__bot.log("Deleting old message")
await old_message.delete()
await ctx.send("Game stopped")
async def guess(self, message: discord.Message, user: str, guess: str):
async def guess(self, ctx: ComponentContext, guess: str, word: str,
guessed_letters: str, game_id: str, *messages: list[str]):
"""
Guess a letter.
@ -174,98 +189,112 @@ class Hangman():
guess: str
The guess.
"""
channel = str(message.channel.id)
hangman_games = self.__bot.database["hangman games"]
game = hangman_games.find_one({"_id": channel})
for msg_id in messages:
msg = await ctx.channel.fetch_message(msg_id)
await msg.delete()
game_exists = (game is not None)
single_letter = (len(guess) == 1 and guess.isalpha())
new_guess = (guess not in game["guessed letters"])
valid_guess = (game_exists and single_letter and new_guess)
if valid_guess:
self.__bot.log("Guessed the letter")
misses = 0
guessed_letters += guess
guessed = [False for i in range(len(word))]
for guessed_letter in guessed_letters:
correct_guess = 0
for i, letter in enumerate(game["word"]):
if guess == letter:
for i, letter in enumerate(word):
if guessed_letter == letter:
correct_guess += 1
updater = {"$set": {f"guessed.{i}": True}}
hangman_games.update_one({"_id": channel}, updater)
guessed[i] = True
if correct_guess == 0:
updater = {"$inc": {"misses": 1}}
hangman_games.update_one({"_id": channel}, updater)
misses += 1
updater = {"$push": {"guessed letters": guess}}
hangman_games.update_one({"_id": channel}, updater)
remaining_letters = list(string.ascii_uppercase)
remaining_letters = list(string.ascii_uppercase)
for letter in guessed_letters:
remaining_letters.remove(letter)
game = hangman_games.find_one({"_id": channel})
if correct_guess == 1:
send_message = "Guessed {}. There was 1 {} in the word."
send_message = send_message.format(guess, guess)
else:
send_message = "Guessed {}. There were {} {}s in the word."
send_message = send_message.format(guess, correct_guess, guess)
for letter in game["guessed letters"]:
remaining_letters.remove(letter)
self.__draw.draw_image(game_id, misses, word, guessed, guessed_letters)
if correct_guess == 1:
send_message = "Guessed {}. There was 1 {} in the word."
send_message = send_message.format(guess, guess)
else:
send_message = "Guessed {}. There were {} {}s in the word."
send_message = send_message.format(guess, correct_guess, guess)
if misses == 6:
send_message += self.bot.long_strings["Hangman lost game"]
remaining_letters = []
elif all(guessed):
self.bot.money.addMoney(f"#{ctx.author_id}", 15)
send_message += self.bot.long_strings["Hangman guessed word"]
remaining_letters = []
self.__draw.draw_image(channel)
if game["misses"] == 6:
hangman_games.delete_one({"_id": channel})
send_message += self.__bot.long_strings["Hangman lost game"]
remaining_letters = []
elif all(game["guessed"]):
hangman_games.delete_one({"_id": channel})
self.__bot.money.addMoney(user, 15)
send_message += self.__bot.long_strings["Hangman guessed word"]
remaining_letters = []
await message.channel.send(send_message)
old_images_path = "gwendolyn/resources/games/old_images/"
with open(old_images_path+f"hangman{channel}", "r") as file_pointer:
old_message_ids = file_pointer.read().splitlines()
for old_id in old_message_ids:
old_message = await message.channel.fetch_message(int(old_id))
self.__bot.log("Deleting old message")
await old_message.delete()
if remaining_letters != []:
boards_path = "gwendolyn/resources/games/hangman_boards/"
file_path = f"{boards_path}hangman_board{channel}.png"
new_image = await message.channel.send(file=discord.File(file_path))
file_path = f"{boards_path}hangman_board{game_id}.png"
image_message = await ctx.channel.send(
send_message,
file=discord.File(file_path)
)
blank_message_one = await ctx.channel.send("_ _")
blank_message_two = await ctx.channel.send("_ _")
buttons = []
for letter in list(string.ascii_uppercase):
custom_id = encode_id([
"hangman",
"guess",
str(ctx.author.id),
letter,
word,
guessed_letters,
game_id,
str(image_message.id),
str(blank_message_one.id),
str(blank_message_two.id)
])
buttons.append(create_button(
style=ButtonStyle.blue,
label=letter,
custom_id=custom_id,
disabled=(letter not in remaining_letters)
))
custom_id = encode_id([
"hangman",
"end",
str(ctx.author.id),
game_id,
str(image_message.id),
str(blank_message_one.id),
str(blank_message_two.id)
])
buttons.append(create_button(
style=ButtonStyle.red,
label="End game",
custom_id=custom_id
))
if len(remaining_letters) > 0:
if len(remaining_letters) > 15:
blank_message = await message.channel.send("_ _")
reaction_messages = {
new_image: remaining_letters[:15],
blank_message: remaining_letters[15:]
}
else:
blank_message = ""
reaction_messages = {new_image: remaining_letters}
action_row_lists = []
for i in range(((len(buttons)-1)//20)+1):
action_rows = []
available_buttons = buttons[(i*20):(min(len(buttons),i*20+20))]
for x in range(((len(available_buttons)-1)//4)+1):
row_buttons = available_buttons[
(x*4):(min(len(available_buttons),x*4+4))
]
action_rows.append(create_actionrow(*row_buttons))
action_row_lists.append(action_rows)
await blank_message_one.edit(components=action_row_lists[0])
await blank_message_two.edit(components=action_row_lists[1])
else:
boards_path = "gwendolyn/resources/games/hangman_boards/"
file_path = f"{boards_path}hangman_board{game_id}.png"
await ctx.channel.send(send_message, file=discord.File(file_path))
os.remove(file_path)
if blank_message != "":
old_messages = f"{new_image.id}\n{blank_message.id}"
else:
old_messages = str(new_image.id)
old_images_path = "gwendolyn/resources/games/old_images/"
old_image_path = old_images_path + f"hangman{channel}"
with open(old_image_path, "w") as file_pointer:
file_pointer.write(old_messages)
for message, letters in reaction_messages.items():
for letter in letters:
emoji = chr(ord(letter)+127397)
await message.add_reaction(emoji)
class DrawHangman():
@ -355,9 +384,9 @@ class DrawHangman():
deviance_accuracy_x = 0
deviance_accuracy_y = 0
start = random.randint(-100, -80)
degreess_amount = 360 + random.randint(-10, 30)
degrees_amount = 360 + random.randint(-10, 30)
for degree in range(degreess_amount):
for degree in range(degrees_amount):
deviance_x, deviance_accuracy_x = self.__deviate(
deviance_x,
deviance_accuracy_x,
@ -589,7 +618,8 @@ class DrawHangman():
placed = True
return background
def draw_image(self, channel: str):
def draw_image(self, game_id: str, misses: int, word: str,
guessed: list[bool], guessed_letters: str):
"""
Draw a hangman Image.
@ -598,21 +628,20 @@ class DrawHangman():
channel: str
The id of the channel the game is in.
"""
self.__bot.log("Drawing hangman image", channel)
game = self.__bot.database["hangman games"].find_one({"_id": channel})
self.__bot.log("Drawing hangman image")
random.seed(game["game ID"])
random.seed(game_id)
background = Image.open("gwendolyn/resources/paper.jpg")
gallow = self.__draw_gallows()
man = self.__draw_man(game["misses"], game["game ID"])
man = self.__draw_man(misses, game_id)
random.seed(game["game ID"])
letter_line_parameters = [game["word"], game["guessed"], game["misses"]]
random.seed(game_id)
letter_line_parameters = [word, guessed, misses]
letter_lines = self.__draw_letter_lines(*letter_line_parameters)
random.seed(game["game ID"])
misses = self.__draw_misses(game["guessed letters"], game["word"])
random.seed(game_id)
misses = self.__draw_misses(list(guessed_letters), word)
background.paste(gallow, (100, 100), gallow)
background.paste(man, (300, 210), man)
@ -623,5 +652,6 @@ class DrawHangman():
misses_text_width = misses_text.size[0]
background.paste(misses_text, (850-misses_text_width//2, 50), misses_text)
board_path = f"gwendolyn/resources/games/hangman_boards/hangman_board{channel}.png"
background.save(board_path)
boards_path = "gwendolyn/resources/games/hangman_boards/"
image_path = f"{boards_path}hangman_board{game_id}.png"
background.save(image_path)

View File

@ -11,6 +11,8 @@ from discord_slash.utils.manage_components import (create_button,
create_actionrow)
from discord_slash.model import ButtonStyle
from gwendolyn.utils import encode_id
class Plex():
"""Container for Plex functions and commands."""
def __init__(self,bot):
@ -73,7 +75,7 @@ class Plex():
buttons.append(create_button(
style=ButtonStyle.green,
label="",
custom_id=f"plex:movie:{imdb_ids[0]}"
custom_id=encode_id(["plex", "movie", str(imdb_ids[0])])
)
)
else:
@ -82,14 +84,14 @@ class Plex():
create_button(
style=ButtonStyle.blue,
label=str(i+1),
custom_id=f"plex:movie:{imdb_ids[i]}"
custom_id=encode_id(["plex", "movie", str(imdb_ids[i])])
)
)
buttons.append(create_button(
style=ButtonStyle.red,
label="X",
custom_id="plex:movie:"
custom_id=encode_id(["plex", "movie", ""])
)
)
@ -211,7 +213,7 @@ class Plex():
buttons.append(create_button(
style=ButtonStyle.green,
label="",
custom_id=f"plex:show:{imdb_ids[0]}"
custom_id=encode_id(["plex", "show", str(imdb_ids[0])])
)
)
else:
@ -220,14 +222,14 @@ class Plex():
create_button(
style=ButtonStyle.blue,
label=str(i+1),
custom_id=f"plex:show:{imdb_ids[i]}"
custom_id=encode_id(["plex", "show", str(imdb_ids[i])])
)
)
buttons.append(create_button(
style=ButtonStyle.red,
label="X",
custom_id="plex:show:"
custom_id=encode_id(["plex", "show", ""])
)
)